modules/graphics/src/main/java/com/sun/javafx/tk/quantum/ViewPainter.java

Print this page




 157             scaleTx.setToScale(width / 2.0, -height / 2.0, 1);
 158             scaleTx.translate(1, -1);
 159             projTx.mul(scaleTx);
 160             viewProjTx = camera.getProjViewTx(viewProjTx);
 161             projTx.mul(viewProjTx);
 162         }
 163     }
 164 
 165     protected void paintImpl(final Graphics backBufferGraphics) {
 166         // We should not be painting anything with a width / height
 167         // that is <= 0, so we might as well bail right off.
 168         if (width <= 0 || height <= 0 || backBufferGraphics == null) {
 169             root.renderForcedContent(backBufferGraphics);
 170             return;
 171         }
 172 
 173         // This "g" variable might represent the back buffer graphics, or it
 174         // might be reassigned to the sceneBuffer graphics.
 175         Graphics g = backBufferGraphics;
 176         // Take into account the pixel scale factor for retina displays
 177         final float pixelScale = getPixelScaleFactor();

 178         // Cache pixelScale in Graphics for use in 3D shaders such as camera and light positions.
 179         g.setPixelScaleFactor(pixelScale);
 180 
 181         // Initialize renderEverything based on various conditions that will cause us to render
 182         // the entire scene every time.
 183         boolean renderEverything = overlayRoot != null ||
 184                 freshBackBuffer ||
 185                 sceneState.getScene().isEntireSceneDirty() ||
 186                 sceneState.getScene().getDepthBuffer() ||
 187                 !PrismSettings.dirtyOptsEnabled;
 188         // We are going to draw dirty opt boxes either if we're supposed to show the dirty
 189         // regions, or if we're supposed to show the overdraw boxes.
 190         final boolean showDirtyOpts = PrismSettings.showDirtyRegions || PrismSettings.showOverdraw;
 191         // If showDirtyOpts is turned on and we're not using a depth buffer
 192         // then we will render the scene to an intermediate texture, and then at the end we'll
 193         // draw that intermediate texture to the back buffer.
 194         if (showDirtyOpts && !sceneState.getScene().getDepthBuffer()) {
 195             final int bufferWidth = (int) Math.ceil(width * pixelScale);
 196             final int bufferHeight = (int) Math.ceil(height * pixelScale);
 197             // Check whether the sceneBuffer texture needs to be reconstructed
 198             if (sceneBuffer != null) {
 199                 sceneBuffer.lock();
 200                 if (sceneBuffer.isSurfaceLost() ||
 201                         bufferWidth != sceneBuffer.getContentWidth() ||
 202                         bufferHeight != sceneBuffer.getContentHeight()) {
 203                     sceneBuffer.unlock();
 204                     sceneBuffer.dispose();
 205                     sceneBuffer = null;
 206                 }
 207             }
 208             // If sceneBuffer is null, we need to create a new texture. In this
 209             // case we will also need to render the whole scene (so don't bother
 210             // with dirty opts)
 211             if (sceneBuffer == null) {
 212                 sceneBuffer = g.getResourceFactory().createRTTexture(
 213                         bufferWidth,
 214                         bufferHeight,
 215                         Texture.WrapMode.CLAMP_TO_ZERO,
 216                         false);
 217                 renderEverything = true;
 218             }
 219             sceneBuffer.contentsUseful();
 220             // Hijack the "g" graphics variable
 221             g = sceneBuffer.createGraphics();
 222             g.scale(pixelScale, pixelScale);

 223         } else if (sceneBuffer != null) {
 224             // We're in a situation where we have previously rendered to the sceneBuffer, but in
 225             // this render pass for whatever reason we're going to draw directly to the back buffer.
 226             // In this case we need to release the sceneBuffer.
 227             sceneBuffer.dispose();
 228             sceneBuffer = null;
 229         }
 230 
 231         // The status will be set only if we're rendering with dirty regions
 232         int status = -1;
 233 
 234         // If we're rendering with dirty regions, then we'll call the root node to accumulate
 235         // the dirty regions and then again to do the pre culling.
 236         if (!renderEverything) {
 237             if (PULSE_LOGGING_ENABLED) {
 238                 PulseLogger.newPhase("Dirty Opts Computed");
 239             }
 240             clip.setBounds(0, 0, width, height);
 241             dirtyRegionTemp.makeEmpty();
 242             dirtyRegionContainer.reset();


 295                         if (!nodePath.isEmpty()) {
 296                             roots.add(nodePath.last());
 297                         }
 298                     }
 299                 }
 300                 root.printDirtyOpts(s, roots);
 301                 PulseLogger.addMessage(s.toString());
 302             }
 303 
 304             // Paint each dirty region
 305             for (int i = 0; i < dirtyRegionSize; ++i) {
 306                 final RectBounds dirtyRegion = dirtyRegionContainer.getDirtyRegion(i);
 307                 // TODO it should be impossible to have ever created a dirty region that was empty...
 308                 // Make sure we are not trying to render in some invalid region
 309                 if (dirtyRegion.getWidth() > 0 && dirtyRegion.getHeight() > 0) {
 310                     // Set the clip rectangle using integer bounds since a fractional bounding box will
 311                     // still require a complete repaint on pixel boundaries
 312                     dirtyRect.setBounds(dirtyRegion);
 313                     // TODO I don't understand why this is needed. And if it is, are fractional pixelScale
 314                     // values OK? And if not, shouldn't pixelScale be an int instead?
 315                     if (pixelScale != 1.0f) {
 316                         dirtyRect.x *= pixelScale;
 317                         dirtyRect.y *= pixelScale;
 318                         dirtyRect.width *= pixelScale;
 319                         dirtyRect.height *= pixelScale;
 320                     }
 321                     g.setClipRect(dirtyRect);
 322                     g.setClipRectIndex(i);
 323                     doPaint(g, getRootPath(i));
 324                 }
 325             }
 326         } else {
 327             // There are no dirty regions, so just paint everything
 328             g.setHasPreCullingBits(false);
 329             g.setClipRect(null);
 330             this.doPaint(g, null);
 331         }
 332         root.renderForcedContent(g);
 333 
 334         // If we have an overlay then we need to render it too.
 335         if (overlayRoot != null) {
 336             overlayRoot.render(g);
 337         }
 338 
 339         // If we're showing dirty regions or overdraw, then we're going to need to draw


 420     protected void disposePresentable() {
 421         if (presentable instanceof GraphicsResource) {
 422             ((GraphicsResource)presentable).dispose();
 423         }
 424         presentable = null;
 425     }
 426 
 427     protected boolean validateStageGraphics() {
 428         if (!sceneState.isValid()) {
 429             // indicates something happened between the scheduling of the
 430             // job and the running of this job.
 431             return false;
 432         }
 433 
 434         width = viewWidth = sceneState.getWidth();
 435         height = viewHeight = sceneState.getHeight();
 436 
 437         return sceneState.isWindowVisible() && !sceneState.isWindowMinimized();
 438     }
 439 
 440     protected float getPixelScaleFactor() {
 441         return presentable == null ? 1.0f : presentable.getPixelScaleFactor();




 442     }
 443 
 444     private void doPaint(Graphics g, NodePath renderRootPath) {
 445         // Null path indicates that occlusion culling is not used
 446         if (renderRootPath != null) {
 447             if (renderRootPath.isEmpty()) {
 448                 // empty render path indicates that no rendering is needed.
 449                 // There may be occluded dirty Nodes however, so we need to clear them
 450                 root.clearDirtyTree();
 451                 return;
 452             }
 453             // If the path is not empty, the first node must be the root node
 454             assert(renderRootPath.getCurrentNode() == root);
 455         }
 456         if (PULSE_LOGGING_ENABLED) {
 457             PulseLogger.newPhase("Painting");
 458         }
 459         GlassScene scene = sceneState.getScene();
 460         scene.clearEntireSceneDirty();
 461         g.setLights(scene.getLights());


 157             scaleTx.setToScale(width / 2.0, -height / 2.0, 1);
 158             scaleTx.translate(1, -1);
 159             projTx.mul(scaleTx);
 160             viewProjTx = camera.getProjViewTx(viewProjTx);
 161             projTx.mul(viewProjTx);
 162         }
 163     }
 164 
 165     protected void paintImpl(final Graphics backBufferGraphics) {
 166         // We should not be painting anything with a width / height
 167         // that is <= 0, so we might as well bail right off.
 168         if (width <= 0 || height <= 0 || backBufferGraphics == null) {
 169             root.renderForcedContent(backBufferGraphics);
 170             return;
 171         }
 172 
 173         // This "g" variable might represent the back buffer graphics, or it
 174         // might be reassigned to the sceneBuffer graphics.
 175         Graphics g = backBufferGraphics;
 176         // Take into account the pixel scale factor for retina displays
 177         final float pixelScaleX = getPixelScaleFactorX();
 178         final float pixelScaleY = getPixelScaleFactorY();
 179         // Cache pixelScale in Graphics for use in 3D shaders such as camera and light positions.
 180         g.setPixelScaleFactors(pixelScaleX, pixelScaleY);
 181 
 182         // Initialize renderEverything based on various conditions that will cause us to render
 183         // the entire scene every time.
 184         boolean renderEverything = overlayRoot != null ||
 185                 freshBackBuffer ||
 186                 sceneState.getScene().isEntireSceneDirty() ||
 187                 sceneState.getScene().getDepthBuffer() ||
 188                 !PrismSettings.dirtyOptsEnabled;
 189         // We are going to draw dirty opt boxes either if we're supposed to show the dirty
 190         // regions, or if we're supposed to show the overdraw boxes.
 191         final boolean showDirtyOpts = PrismSettings.showDirtyRegions || PrismSettings.showOverdraw;
 192         // If showDirtyOpts is turned on and we're not using a depth buffer
 193         // then we will render the scene to an intermediate texture, and then at the end we'll
 194         // draw that intermediate texture to the back buffer.
 195         if (showDirtyOpts && !sceneState.getScene().getDepthBuffer()) {
 196             final int bufferWidth = (int) Math.ceil(width * pixelScaleX);
 197             final int bufferHeight = (int) Math.ceil(height * pixelScaleY);
 198             // Check whether the sceneBuffer texture needs to be reconstructed
 199             if (sceneBuffer != null) {
 200                 sceneBuffer.lock();
 201                 if (sceneBuffer.isSurfaceLost() ||
 202                         bufferWidth != sceneBuffer.getContentWidth() ||
 203                         bufferHeight != sceneBuffer.getContentHeight()) {
 204                     sceneBuffer.unlock();
 205                     sceneBuffer.dispose();
 206                     sceneBuffer = null;
 207                 }
 208             }
 209             // If sceneBuffer is null, we need to create a new texture. In this
 210             // case we will also need to render the whole scene (so don't bother
 211             // with dirty opts)
 212             if (sceneBuffer == null) {
 213                 sceneBuffer = g.getResourceFactory().createRTTexture(
 214                         bufferWidth,
 215                         bufferHeight,
 216                         Texture.WrapMode.CLAMP_TO_ZERO,
 217                         false);
 218                 renderEverything = true;
 219             }
 220             sceneBuffer.contentsUseful();
 221             // Hijack the "g" graphics variable
 222             g = sceneBuffer.createGraphics();
 223             g.setPixelScaleFactors(pixelScaleX, pixelScaleY);
 224             g.scale(pixelScaleX, pixelScaleY);
 225         } else if (sceneBuffer != null) {
 226             // We're in a situation where we have previously rendered to the sceneBuffer, but in
 227             // this render pass for whatever reason we're going to draw directly to the back buffer.
 228             // In this case we need to release the sceneBuffer.
 229             sceneBuffer.dispose();
 230             sceneBuffer = null;
 231         }
 232 
 233         // The status will be set only if we're rendering with dirty regions
 234         int status = -1;
 235 
 236         // If we're rendering with dirty regions, then we'll call the root node to accumulate
 237         // the dirty regions and then again to do the pre culling.
 238         if (!renderEverything) {
 239             if (PULSE_LOGGING_ENABLED) {
 240                 PulseLogger.newPhase("Dirty Opts Computed");
 241             }
 242             clip.setBounds(0, 0, width, height);
 243             dirtyRegionTemp.makeEmpty();
 244             dirtyRegionContainer.reset();


 297                         if (!nodePath.isEmpty()) {
 298                             roots.add(nodePath.last());
 299                         }
 300                     }
 301                 }
 302                 root.printDirtyOpts(s, roots);
 303                 PulseLogger.addMessage(s.toString());
 304             }
 305 
 306             // Paint each dirty region
 307             for (int i = 0; i < dirtyRegionSize; ++i) {
 308                 final RectBounds dirtyRegion = dirtyRegionContainer.getDirtyRegion(i);
 309                 // TODO it should be impossible to have ever created a dirty region that was empty...
 310                 // Make sure we are not trying to render in some invalid region
 311                 if (dirtyRegion.getWidth() > 0 && dirtyRegion.getHeight() > 0) {
 312                     // Set the clip rectangle using integer bounds since a fractional bounding box will
 313                     // still require a complete repaint on pixel boundaries
 314                     dirtyRect.setBounds(dirtyRegion);
 315                     // TODO I don't understand why this is needed. And if it is, are fractional pixelScale
 316                     // values OK? And if not, shouldn't pixelScale be an int instead?
 317                     if (pixelScaleX != 1.0f || pixelScaleY != 1.0f) {
 318                         dirtyRect.x *= pixelScaleX;
 319                         dirtyRect.y *= pixelScaleY;
 320                         dirtyRect.width *= pixelScaleX;
 321                         dirtyRect.height *= pixelScaleY;
 322                     }
 323                     g.setClipRect(dirtyRect);
 324                     g.setClipRectIndex(i);
 325                     doPaint(g, getRootPath(i));
 326                 }
 327             }
 328         } else {
 329             // There are no dirty regions, so just paint everything
 330             g.setHasPreCullingBits(false);
 331             g.setClipRect(null);
 332             this.doPaint(g, null);
 333         }
 334         root.renderForcedContent(g);
 335 
 336         // If we have an overlay then we need to render it too.
 337         if (overlayRoot != null) {
 338             overlayRoot.render(g);
 339         }
 340 
 341         // If we're showing dirty regions or overdraw, then we're going to need to draw


 422     protected void disposePresentable() {
 423         if (presentable instanceof GraphicsResource) {
 424             ((GraphicsResource)presentable).dispose();
 425         }
 426         presentable = null;
 427     }
 428 
 429     protected boolean validateStageGraphics() {
 430         if (!sceneState.isValid()) {
 431             // indicates something happened between the scheduling of the
 432             // job and the running of this job.
 433             return false;
 434         }
 435 
 436         width = viewWidth = sceneState.getWidth();
 437         height = viewHeight = sceneState.getHeight();
 438 
 439         return sceneState.isWindowVisible() && !sceneState.isWindowMinimized();
 440     }
 441 
 442     protected float getPixelScaleFactorX() {
 443         return presentable == null ? 1.0f : presentable.getPixelScaleFactorX();
 444     }
 445 
 446     protected float getPixelScaleFactorY() {
 447         return presentable == null ? 1.0f : presentable.getPixelScaleFactorY();
 448     }
 449 
 450     private void doPaint(Graphics g, NodePath renderRootPath) {
 451         // Null path indicates that occlusion culling is not used
 452         if (renderRootPath != null) {
 453             if (renderRootPath.isEmpty()) {
 454                 // empty render path indicates that no rendering is needed.
 455                 // There may be occluded dirty Nodes however, so we need to clear them
 456                 root.clearDirtyTree();
 457                 return;
 458             }
 459             // If the path is not empty, the first node must be the root node
 460             assert(renderRootPath.getCurrentNode() == root);
 461         }
 462         if (PULSE_LOGGING_ENABLED) {
 463             PulseLogger.newPhase("Painting");
 464         }
 465         GlassScene scene = sceneState.getScene();
 466         scene.clearEntireSceneDirty();
 467         g.setLights(scene.getLights());