< prev index next >

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

Print this page

1503                 if (rt == null) {
1504                     return;
1505                 }
1506                 Graphics g = rt.createGraphics();
1507                 draw(g, x, y, w, h);
1508                 int[] pixels = rt.getPixels();
1509                 if (pixels != null) {
1510                     pImage.setImage(com.sun.prism.Image.fromIntArgbPreData(pixels, w, h));
1511                 } else {
1512                     IntBuffer ib = IntBuffer.allocate(w * h);
1513                     if (rt.readPixels(ib, rt.getContentX(), rt.getContentY(), w, h)) {
1514                         pImage.setImage(com.sun.prism.Image.fromIntArgbPreData(ib, w, h));
1515                     } else {
1516                         pImage.dispose();
1517                         pImage = null;
1518                     }
1519                 }
1520                 rt.unlock();
1521             }
1522 
1523             private int computeOptimumTileSize(int size, int maxSize) {
1524                 return computeOptimumTileSize(size, maxSize, null);
1525             }
1526 
1527             private int computeOptimumTileSize(int size, int maxSize, boolean[] isDivExact) {
1528                 // This method attempts to find the smallest exact divider for the provided `size`
1529                 // while the result of the division is less than `maxSize`.
1530                 // It tests all potential dividers from 2 to 6 and returns the result of the division
1531                 // if all conditions can be satisfied or, failing that, `maxSize`.
1532                 // If non-null, the value for `isDivExact` is set so as to reflect whether or not
1533                 // an exact divider could be found.
1534                 for (int n = 2; n <= 6; n++) {
1535                     int optimumSize = size / n;
1536                     if (optimumSize <= maxSize && optimumSize * n == size) {
1537                         if (isDivExact != null && isDivExact.length > 0) {
1538                             isDivExact[0] = true;
1539                         }
1540                         return optimumSize;
1541                     }
1542                 }
1543                 if (isDivExact != null && isDivExact.length > 0) {
1544                     isDivExact[0]= false;
1545                 }
1546                 return maxSize;
1547             }
1548 
1549             @Override
1550             public void run() {
1551 
1552                 ResourceFactory rf = GraphicsPipeline.getDefaultResourceFactory();
1553 
1554                 if (!rf.isDeviceReady()) {
1555                     return;
1556                 }
1557 
1558                 int x = params.x;
1559                 int y = params.y;
1560                 int w = params.width;
1561                 int h = params.height;
1562 
1563                 if (w <= 0 || h <= 0) {
1564                     return;
1565                 }
1566 
1567                 boolean errored = false;
1568                 // A temp QuantumImage used only as a RTT cache for rendering tiles.
1569                 var tileRttCache = new QuantumImage((com.sun.prism.Image) null);
1570                 try {
1571                     QuantumImage pImage = (params.platformImage instanceof QuantumImage) ?
1572                             (QuantumImage) params.platformImage : new QuantumImage((com.sun.prism.Image) null);
1573 
1574                     int maxTextureSize = rf.getMaximumTextureSize();
1575                     if (h > maxTextureSize || w > maxTextureSize) {
1576                         // The requested size for the screenshot is too big to fit a single texture,
1577                         // so we need to take several snapshot tiles and merge them into pImage
1578                         if (pImage.image == null) {
1579                             pImage.setImage(com.sun.prism.Image.fromIntArgbPreData(IntBuffer.allocate(w * h), w, h));
1580                         }
1581                         // Find out if it is possible to divide up the image in tiles of the same size
1582                         int tileWidth = computeOptimumTileSize(w, maxTextureSize);
1583                         var exactHeightDivFound = new boolean[]{false};
1584                         int tileHeight = computeOptimumTileSize(h, maxTextureSize, exactHeightDivFound);
1585                         IntBuffer buffer = IntBuffer.allocate(tileWidth * tileHeight);
1586                         // In order to minimize the number of time we have to resize the underlying
1587                         // surface for capturing a tile, choose a dimension that has an exact divider
1588                         // (if any) to be processed in the inner most loop.
1589                         // E.g. looping on width then height in the example bellow requires four
1590                         // surface resizing, whereas the opposite requires only two:
1591                         //
1592                         //       for (w;;)                    for (h;;)
1593                         //           for(h;;)                     for(w;;)
1594                         //       -----------------           -----------------
1595                         //       |       |       |           |       |       |
1596                         //       |   1   |   3   |           |   1   |   2   |
1597                         //    h  |       |       |        h  |       |       |
1598                         //       -----------------           -----------------
1599                         //       |   2   |   4   |           |   3   |   4   |
1600                         //       -----------------           -----------------
1601                         //               w                           w
1602 
1603 
1604 
1605                         if (exactHeightDivFound[0]) {
1606                             for (int xOffset = 0; xOffset < w; xOffset += tileWidth) {
1607                                 tileWidth = Math.min(tileWidth, w - xOffset);
1608                                 for (int yOffset = 0; yOffset < h; yOffset += tileHeight) {
1609                                     tileHeight = Math.min(tileHeight, h - yOffset);
1610                                     renderTile(x, xOffset, y, yOffset, tileWidth, tileHeight,
1611                                             buffer, rf, tileRttCache, pImage);
1612                                 }
1613                             }
1614                         } else {
1615                             for (int yOffset = 0; yOffset < h; yOffset += tileHeight) {
1616                                 tileHeight = Math.min(tileHeight, h - yOffset);
1617                                 for (int xOffset = 0; xOffset < w; xOffset += tileWidth) {
1618                                     tileWidth = Math.min(tileWidth, w - xOffset);
1619                                     renderTile(x, xOffset, y, yOffset, tileWidth, tileHeight,
1620                                             buffer, rf, tileRttCache, pImage);
1621                                 }
1622                             }


1623                         }
1624                     } else {





















1625                         // The requested size for the screenshot fits max texture size,
1626                         // so we can directly render it in the target image.
1627                         renderWholeImage(x, y, w, h, rf, pImage);
1628                     }
1629                     params.platformImage = pImage;
1630                 } catch (Throwable t) {
1631                     errored = true;
1632                     t.printStackTrace(System.err);
1633                 } finally {
1634                     tileRttCache.dispose();
1635                     Disposer.cleanUp();
1636                     rf.getTextureResourcePool().freeDisposalRequestedAndCheckResources(errored);
1637                 }
1638             }
1639         });
1640 
1641         final CountDownLatch latch = new CountDownLatch(1);
1642         re.setCompletionListener(job -> latch.countDown());
1643         addRenderJob(re);
1644 

1503                 if (rt == null) {
1504                     return;
1505                 }
1506                 Graphics g = rt.createGraphics();
1507                 draw(g, x, y, w, h);
1508                 int[] pixels = rt.getPixels();
1509                 if (pixels != null) {
1510                     pImage.setImage(com.sun.prism.Image.fromIntArgbPreData(pixels, w, h));
1511                 } else {
1512                     IntBuffer ib = IntBuffer.allocate(w * h);
1513                     if (rt.readPixels(ib, rt.getContentX(), rt.getContentY(), w, h)) {
1514                         pImage.setImage(com.sun.prism.Image.fromIntArgbPreData(ib, w, h));
1515                     } else {
1516                         pImage.dispose();
1517                         pImage = null;
1518                     }
1519                 }
1520                 rt.unlock();
1521             }
1522 



1523 
1524             private int computeTileSize(int size, int maxSize) {
1525                 // If 'size' divided by either 2 or 3 produce an exact result
1526                 // and is lesser that the specified maxSize, then use this value
1527                 // as the tile size, as this makes the tiling process more efficient.
1528                 for (int n = 1; n <= 3; n++) {



1529                     int optimumSize = size / n;
1530                     if (optimumSize <= maxSize && optimumSize * n == size) {



1531                         return optimumSize;
1532                     }
1533                 }



1534                 return maxSize;
1535             }
1536 
1537             @Override
1538             public void run() {
1539 
1540                 ResourceFactory rf = GraphicsPipeline.getDefaultResourceFactory();
1541 
1542                 if (!rf.isDeviceReady()) {
1543                     return;
1544                 }
1545 
1546                 int x = params.x;
1547                 int y = params.y;
1548                 int w = params.width;
1549                 int h = params.height;
1550 
1551                 if (w <= 0 || h <= 0) {
1552                     return;
1553                 }
1554 
1555                 boolean errored = false;
1556                 // A temp QuantumImage used only as a RTT cache for rendering tiles.
1557                 var tileRttCache = new QuantumImage((com.sun.prism.Image) null);
1558                 try {
1559                     QuantumImage pImage = (params.platformImage instanceof QuantumImage) ?
1560                             (QuantumImage) params.platformImage : new QuantumImage((com.sun.prism.Image) null);
1561 
1562                     int maxTextureSize = rf.getMaximumTextureSize();
1563                     if (h > maxTextureSize || w > maxTextureSize) {
1564                         // The requested size for the screenshot is too big to fit a single texture,
1565                         // so we need to take several snapshot tiles and merge them into pImage
1566                         if (pImage.image == null) {
1567                             pImage.setImage(com.sun.prism.Image.fromIntArgbPreData(IntBuffer.allocate(w * h), w, h));
1568                         }
1569                         // Find out if it is possible to divide up the image in tiles of the same size
1570                         int tileWidth = computeTileSize(w, maxTextureSize);
1571                         int tileHeight = computeTileSize(h, maxTextureSize);

1572                         IntBuffer buffer = IntBuffer.allocate(tileWidth * tileHeight);
1573 
1574                         // M represents the middle set of tiles each with a size of tileW x tileH.
1575                         // R is the right hand column of tiles,
1576                         // B is the bottom row,
1577                         // C is the corner:
1578                         // +-----------+-----------+  .  +-------+
1579                         // |           |           |  .  |       |
1580                         // |     M     |     M     |  .  |   R   |
1581                         // |           |           |  .  |       |
1582                         // +-----------+-----------+  .  +-------+
1583                         // |           |           |  .  |       |
1584                         // |     M     |     M     |  .  |   R   |
1585                         // |           |           |  .  |       |
1586                         // +-----------+-----------+  .  +-------+
1587                         //       .           .        .      .
1588                         // +-----------+-----------+  .  +-------+
1589                         // |     B     |     B     |  .  |   C   |
1590                         // +-----------+-----------+  .  +-------+
1591 
1592                         // Walk through all same-size "M" tiles
1593                         int xOffset = 0;
1594                         int yOffset = 0;
1595                         var mTileWidth = tileWidth;
1596                         var mTileHeight = tileHeight;
1597                         while (mTileWidth == tileWidth && xOffset < w) {
1598                             yOffset = 0;
1599                             mTileHeight = tileHeight;
1600                             while (mTileHeight == tileHeight && yOffset < h) {
1601                                 renderTile(x, xOffset, y, yOffset, mTileWidth, mTileHeight,
1602                                         buffer, rf, tileRttCache, pImage);
1603                                 yOffset += tileHeight;
1604                                 mTileHeight = Math.min(tileHeight, h - yOffset);




1605                             }
1606                             xOffset += tileWidth;
1607                             mTileWidth = Math.min(tileWidth, w - xOffset);
1608                         }
1609                         // Walk through remaining same-width "B" tiles, if any
1610                         int bOffset = 0;
1611                         int bTileHeight = tileHeight;
1612                         while (bTileHeight == tileHeight && bOffset < h) {
1613                             renderTile(x, xOffset, y, bOffset, mTileWidth, bTileHeight, buffer, rf, tileRttCache, pImage);
1614                             bOffset += tileHeight;
1615                             bTileHeight = Math.min(tileHeight, h - bOffset);
1616                         }
1617                         // Walk through remaining same-height "R" tiles, if any
1618                         int rOffset = 0;
1619                         int rTileWidth = tileWidth;
1620                         while (rTileWidth == tileWidth && rOffset < w) {
1621                             renderTile(x, rOffset, y, yOffset, rTileWidth, mTileHeight, buffer, rf, tileRttCache, pImage);
1622                             rOffset += tileWidth;
1623                             rTileWidth = Math.min(tileWidth, w - rOffset);
1624                         }
1625                         // Render corner "C" tile if needed
1626                         if (bOffset > 0 && rOffset > 0) {
1627                             renderTile(x, rOffset, y, bOffset, rTileWidth, bTileHeight, buffer, rf, tileRttCache, pImage);
1628                         }
1629                     }
1630                     else {
1631                         // The requested size for the screenshot fits max texture size,
1632                         // so we can directly render it in the target image.
1633                         renderWholeImage(x, y, w, h, rf, pImage);
1634                     }
1635                     params.platformImage = pImage;
1636                 } catch (Throwable t) {
1637                     errored = true;
1638                     t.printStackTrace(System.err);
1639                 } finally {
1640                     tileRttCache.dispose();
1641                     Disposer.cleanUp();
1642                     rf.getTextureResourcePool().freeDisposalRequestedAndCheckResources(errored);
1643                 }
1644             }
1645         });
1646 
1647         final CountDownLatch latch = new CountDownLatch(1);
1648         re.setCompletionListener(job -> latch.countDown());
1649         addRenderJob(re);
1650 
< prev index next >