Skip to content

Commit 1823f6e

Browse files
fthevenetkevinrushforth
authored andcommitted
8088198: Exception thrown from snapshot if dimensions are larger than max texture size
Reviewed-by: arapte, kcr
1 parent 5a0e71b commit 1823f6e

File tree

2 files changed

+64
-33
lines changed

2 files changed

+64
-33
lines changed

modules/javafx.graphics/src/main/java/javafx/scene/Scene.java

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,27 +1285,71 @@ static WritableImage doSnapshot(Scene scene,
12851285
Node root, BaseTransform transform, boolean depthBuffer,
12861286
Paint fill, Camera camera, WritableImage wimg) {
12871287

1288-
Toolkit tk = Toolkit.getToolkit();
1289-
Toolkit.ImageRenderingContext context = new Toolkit.ImageRenderingContext();
1290-
12911288
int xMin = (int)Math.floor(x);
12921289
int yMin = (int)Math.floor(y);
1293-
int xMax = (int)Math.ceil(x + w);
1294-
int yMax = (int)Math.ceil(y + h);
1295-
int width = Math.max(xMax - xMin, 1);
1296-
int height = Math.max(yMax - yMin, 1);
1290+
int width;
1291+
int height;
12971292
if (wimg == null) {
1293+
int xMax = (int)Math.ceil(x + w);
1294+
int yMax = (int)Math.ceil(y + h);
1295+
width = Math.max(xMax - xMin, 1);
1296+
height = Math.max(yMax - yMin, 1);
12981297
wimg = new WritableImage(width, height);
12991298
} else {
13001299
width = (int)wimg.getWidth();
13011300
height = (int)wimg.getHeight();
13021301
}
13031302

1303+
// Attempt to capture snapshot
1304+
try {
1305+
wimg = doSnapshotTile(scene, xMin, yMin, width, height, root, transform, depthBuffer, fill, camera, wimg);
1306+
} catch (Exception e) {
1307+
// A first attempt to capture a snapshot failed, most likely because it is larger than
1308+
// maxTextureSize: retry by taking several snapshot tiles and merge them into single image
1309+
// (Addresses JDK-8088198)
1310+
int maxTextureSize = PrismSettings.maxTextureSize;
1311+
int numVerticalTiles = (int) Math.ceil(height / (double) maxTextureSize);
1312+
int numHorizontalTiles = (int) Math.ceil(width / (double) maxTextureSize);
1313+
for (int i = 0; i < numHorizontalTiles; i++) {
1314+
int xOffset = i * maxTextureSize;
1315+
int tileWidth = Math.min(maxTextureSize, width - xOffset);
1316+
for (int j = 0; j < numVerticalTiles; j++) {
1317+
int yOffset = j * maxTextureSize;
1318+
int tileHeight = Math.min(maxTextureSize, height - yOffset);
1319+
WritableImage tile = doSnapshotTile(scene, xMin + xOffset, yMin + yOffset, tileWidth,
1320+
tileHeight, root, transform, depthBuffer, fill, camera, null);
1321+
wimg.getPixelWriter().setPixels(xOffset, yOffset, tileWidth, tileHeight, tile.getPixelReader(), 0, 0);
1322+
}
1323+
}
1324+
}
1325+
1326+
// if this scene belongs to some stage
1327+
// we need to mark the entire scene as dirty
1328+
// because dirty logic is buggy
1329+
if (scene != null && scene.peer != null) {
1330+
scene.setNeedsRepaint();
1331+
}
1332+
1333+
return wimg;
1334+
}
1335+
1336+
/**
1337+
* Capture a single snapshot tile
1338+
*/
1339+
private static WritableImage doSnapshotTile(Scene scene,
1340+
int x, int y, int w, int h,
1341+
Node root, BaseTransform transform, boolean depthBuffer,
1342+
Paint fill, Camera camera, WritableImage tileImg) {
1343+
Toolkit tk = Toolkit.getToolkit();
1344+
Toolkit.ImageRenderingContext context = new Toolkit.ImageRenderingContext();
1345+
if (tileImg == null) {
1346+
tileImg = new WritableImage(w, h);
1347+
}
13041348
setAllowPGAccess(true);
1305-
context.x = xMin;
1306-
context.y = yMin;
1307-
context.width = width;
1308-
context.height = height;
1349+
context.x = x;
1350+
context.y = y;
1351+
context.width = w;
1352+
context.height = h;
13091353
context.transform = transform;
13101354
context.depthBuffer = depthBuffer;
13111355
context.root = root.getPeer();
@@ -1316,8 +1360,8 @@ static WritableImage doSnapshot(Scene scene,
13161360
// temporarily adjust camera viewport to the snapshot size
13171361
cameraViewWidth = camera.getViewWidth();
13181362
cameraViewHeight = camera.getViewHeight();
1319-
camera.setViewWidth(width);
1320-
camera.setViewHeight(height);
1363+
camera.setViewWidth(w);
1364+
camera.setViewHeight(h);
13211365
NodeHelper.updatePeer(camera);
13221366
context.camera = camera.getPeer();
13231367
} else {
@@ -1334,10 +1378,10 @@ static WritableImage doSnapshot(Scene scene,
13341378
}
13351379

13361380
Toolkit.WritableImageAccessor accessor = Toolkit.getWritableImageAccessor();
1337-
context.platformImage = accessor.getTkImageLoader(wimg);
1381+
context.platformImage = accessor.getTkImageLoader(tileImg);
13381382
setAllowPGAccess(false);
13391383
Object tkImage = tk.renderToImage(context);
1340-
accessor.loadTkImage(wimg, tkImage);
1384+
accessor.loadTkImage(tileImg, tkImage);
13411385

13421386
if (camera != null) {
13431387
setAllowPGAccess(true);
@@ -1346,15 +1390,7 @@ static WritableImage doSnapshot(Scene scene,
13461390
NodeHelper.updatePeer(camera);
13471391
setAllowPGAccess(false);
13481392
}
1349-
1350-
// if this scene belongs to some stage
1351-
// we need to mark the entire scene as dirty
1352-
// because dirty logic is buggy
1353-
if (scene != null && scene.peer != null) {
1354-
scene.setNeedsRepaint();
1355-
}
1356-
1357-
return wimg;
1393+
return tileImg;
13581394
}
13591395

13601396
/**

tests/system/src/test/java/test/javafx/scene/Snapshot2Test.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import org.junit.AfterClass;
4242
import org.junit.Before;
4343
import org.junit.BeforeClass;
44-
import org.junit.Ignore;
4544
import org.junit.Test;
4645
import org.junit.runner.RunWith;
4746
import org.junit.runners.Parameterized;
@@ -373,26 +372,22 @@ public void testSnapshotScaleNodeDefer() {
373372
doTestSnapshotScaleNodeDefer(3, 3);
374373
}
375374

376-
// TODO: Re-enable this test when RT-22073 is fixed
377-
@Ignore @Test
375+
@Test
378376
public void testSnapshotBigXScaleNodeImm() {
379377
doTestSnapshotScaleNodeImm(100, 1);
380378
}
381379

382-
// TODO: Re-enable this test when RT-22073 is fixed
383-
@Ignore @Test
380+
@Test
384381
public void testSnapshotBigXScaleNodeDefer() {
385382
doTestSnapshotScaleNodeDefer(100, 1);
386383
}
387384

388-
// TODO: Re-enable this test when RT-22073 is fixed
389-
@Ignore @Test
385+
@Test
390386
public void testSnapshotBigYScaleNodeImm() {
391387
doTestSnapshotScaleNodeImm(1, 200);
392388
}
393389

394-
// TODO: Re-enable this test when RT-22073 is fixed
395-
@Ignore @Test
390+
@Test
396391
public void testSnapshotBigYScaleNodeDefer() {
397392
doTestSnapshotScaleNodeDefer(1, 200);
398393
}

0 commit comments

Comments
 (0)