Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
8088198: Exception thrown from snapshot if dimensions are larger than…
… max texture size

Reviewed-by: arapte, kcr
  • Loading branch information
fthevenet authored and kevinrushforth committed Jan 31, 2020
1 parent 5a0e71b commit 1823f6e
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 33 deletions.
84 changes: 60 additions & 24 deletions modules/javafx.graphics/src/main/java/javafx/scene/Scene.java
Expand Up @@ -1285,27 +1285,71 @@ static WritableImage doSnapshot(Scene scene,
Node root, BaseTransform transform, boolean depthBuffer,
Paint fill, Camera camera, WritableImage wimg) {

Toolkit tk = Toolkit.getToolkit();
Toolkit.ImageRenderingContext context = new Toolkit.ImageRenderingContext();

int xMin = (int)Math.floor(x);
int yMin = (int)Math.floor(y);
int xMax = (int)Math.ceil(x + w);
int yMax = (int)Math.ceil(y + h);
int width = Math.max(xMax - xMin, 1);
int height = Math.max(yMax - yMin, 1);
int width;
int height;
if (wimg == null) {
int xMax = (int)Math.ceil(x + w);
int yMax = (int)Math.ceil(y + h);
width = Math.max(xMax - xMin, 1);
height = Math.max(yMax - yMin, 1);
wimg = new WritableImage(width, height);
} else {
width = (int)wimg.getWidth();
height = (int)wimg.getHeight();
}

// Attempt to capture snapshot
try {
wimg = doSnapshotTile(scene, xMin, yMin, width, height, root, transform, depthBuffer, fill, camera, wimg);
} catch (Exception e) {
// A first attempt to capture a snapshot failed, most likely because it is larger than
// maxTextureSize: retry by taking several snapshot tiles and merge them into single image
// (Addresses JDK-8088198)
int maxTextureSize = PrismSettings.maxTextureSize;
int numVerticalTiles = (int) Math.ceil(height / (double) maxTextureSize);
int numHorizontalTiles = (int) Math.ceil(width / (double) maxTextureSize);
for (int i = 0; i < numHorizontalTiles; i++) {
int xOffset = i * maxTextureSize;
int tileWidth = Math.min(maxTextureSize, width - xOffset);
for (int j = 0; j < numVerticalTiles; j++) {
int yOffset = j * maxTextureSize;
int tileHeight = Math.min(maxTextureSize, height - yOffset);
WritableImage tile = doSnapshotTile(scene, xMin + xOffset, yMin + yOffset, tileWidth,
tileHeight, root, transform, depthBuffer, fill, camera, null);
wimg.getPixelWriter().setPixels(xOffset, yOffset, tileWidth, tileHeight, tile.getPixelReader(), 0, 0);
}
}
}

// if this scene belongs to some stage
// we need to mark the entire scene as dirty
// because dirty logic is buggy
if (scene != null && scene.peer != null) {
scene.setNeedsRepaint();
}

return wimg;
}

/**
* Capture a single snapshot tile
*/
private static WritableImage doSnapshotTile(Scene scene,
int x, int y, int w, int h,
Node root, BaseTransform transform, boolean depthBuffer,
Paint fill, Camera camera, WritableImage tileImg) {
Toolkit tk = Toolkit.getToolkit();
Toolkit.ImageRenderingContext context = new Toolkit.ImageRenderingContext();
if (tileImg == null) {
tileImg = new WritableImage(w, h);
}
setAllowPGAccess(true);
context.x = xMin;
context.y = yMin;
context.width = width;
context.height = height;
context.x = x;
context.y = y;
context.width = w;
context.height = h;
context.transform = transform;
context.depthBuffer = depthBuffer;
context.root = root.getPeer();
Expand All @@ -1316,8 +1360,8 @@ static WritableImage doSnapshot(Scene scene,
// temporarily adjust camera viewport to the snapshot size
cameraViewWidth = camera.getViewWidth();
cameraViewHeight = camera.getViewHeight();
camera.setViewWidth(width);
camera.setViewHeight(height);
camera.setViewWidth(w);
camera.setViewHeight(h);
NodeHelper.updatePeer(camera);
context.camera = camera.getPeer();
} else {
Expand All @@ -1334,10 +1378,10 @@ static WritableImage doSnapshot(Scene scene,
}

Toolkit.WritableImageAccessor accessor = Toolkit.getWritableImageAccessor();
context.platformImage = accessor.getTkImageLoader(wimg);
context.platformImage = accessor.getTkImageLoader(tileImg);
setAllowPGAccess(false);
Object tkImage = tk.renderToImage(context);
accessor.loadTkImage(wimg, tkImage);
accessor.loadTkImage(tileImg, tkImage);

if (camera != null) {
setAllowPGAccess(true);
Expand All @@ -1346,15 +1390,7 @@ static WritableImage doSnapshot(Scene scene,
NodeHelper.updatePeer(camera);
setAllowPGAccess(false);
}

// if this scene belongs to some stage
// we need to mark the entire scene as dirty
// because dirty logic is buggy
if (scene != null && scene.peer != null) {
scene.setNeedsRepaint();
}

return wimg;
return tileImg;
}

/**
Expand Down
13 changes: 4 additions & 9 deletions tests/system/src/test/java/test/javafx/scene/Snapshot2Test.java
Expand Up @@ -41,7 +41,6 @@
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
Expand Down Expand Up @@ -373,26 +372,22 @@ public void testSnapshotScaleNodeDefer() {
doTestSnapshotScaleNodeDefer(3, 3);
}

// TODO: Re-enable this test when RT-22073 is fixed
@Ignore @Test
@Test
public void testSnapshotBigXScaleNodeImm() {
doTestSnapshotScaleNodeImm(100, 1);
}

// TODO: Re-enable this test when RT-22073 is fixed
@Ignore @Test
@Test
public void testSnapshotBigXScaleNodeDefer() {
doTestSnapshotScaleNodeDefer(100, 1);
}

// TODO: Re-enable this test when RT-22073 is fixed
@Ignore @Test
@Test
public void testSnapshotBigYScaleNodeImm() {
doTestSnapshotScaleNodeImm(1, 200);
}

// TODO: Re-enable this test when RT-22073 is fixed
@Ignore @Test
@Test
public void testSnapshotBigYScaleNodeDefer() {
doTestSnapshotScaleNodeDefer(1, 200);
}
Expand Down

0 comments on commit 1823f6e

Please sign in to comment.