modules/graphics/src/main/java/com/sun/prism/impl/BaseContext.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -30,11 +30,14 @@
 import java.util.Iterator;
 import java.util.Map;
 import com.sun.glass.ui.Screen;
 import com.sun.javafx.font.FontResource;
 import com.sun.javafx.font.FontStrike;
+import com.sun.javafx.geom.RectBounds;
 import com.sun.javafx.geom.transform.BaseTransform;
+import com.sun.javafx.image.ByteToBytePixelConverter;
+import com.sun.javafx.image.impl.ByteGray;
 import com.sun.javafx.sg.prism.NGCamera;
 import com.sun.prism.PixelFormat;
 import com.sun.prism.RTTexture;
 import com.sun.prism.RenderTarget;
 import com.sun.prism.ResourceFactory;

@@ -48,11 +51,18 @@
 
     private final Screen screen;
     private final ResourceFactory factory;
     private final VertexBuffer vertexBuffer;
 
+    private static final int MIN_MASK_DIM = 1024;
     private Texture maskTex;
+    private ByteBuffer maskBuffer;
+    private ByteBuffer clearBuffer;
+    private int curMaskRow;
+    private int nextMaskRow;
+    private int curMaskCol;
+    private int highMaskCol;
     private Texture paintTex;
     private int[] paintPixels;
     private ByteBuffer paintBuffer;
 
     private Texture rectTex;

@@ -86,10 +96,20 @@
     public VertexBuffer getVertexBuffer() {
         return vertexBuffer;
     }
 
     public void flushVertexBuffer() {
+        if (curMaskRow > 0 || curMaskCol > 0) {
+            maskTex.lock();
+            // assert !maskTex.isSurfaceLost();
+            // since it was bound and unflushed...
+            maskTex.update(maskBuffer, maskTex.getPixelFormat(),
+                           0, 0, 0, 0, highMaskCol, nextMaskRow,
+                           maskTex.getPhysicalWidth(), true);
+            maskTex.unlock();
+            curMaskRow = curMaskCol = nextMaskRow = highMaskCol = 0;
+        }
         vertexBuffer.flush();
     }
 
     /**
      *

@@ -160,46 +180,106 @@
             glyphCaches.put(strike, glyphCache);
         }
         return glyphCache;
     }
 
-    public Texture getMaskTexture(MaskData maskData, boolean canScale) {
-        int maskW = maskData.getWidth();
-        int maskH = maskData.getHeight();
+    public Texture validateMaskTexture(MaskData maskData, boolean canScale) {
+        int pad = canScale ? 1 : 0;
+        int needW = maskData.getWidth() + pad + pad;
+        int needH = maskData.getHeight() + pad + pad;
+        int texW = 0, texH = 0;
+
         if (maskTex != null) {
             maskTex.lock();
             if (maskTex.isSurfaceLost()) {
                 maskTex = null;
+            } else {
+                texW = maskTex.getContentWidth();
+                texH = maskTex.getContentHeight();
             }
         }
-        if (maskTex == null ||
-            maskTex.getContentWidth()  < maskW ||
-            maskTex.getContentHeight() < maskH)
-        {
-            int newTexW = maskW;
-            int newTexH = maskH;
+
+        if (maskTex == null || texW < needW || texH < needH) {
             if (maskTex != null) {
+                flushVertexBuffer();
+                maskTex.dispose();
+                maskTex = null;
+            }
+            maskBuffer = null;
+
                 // grow the mask texture so that the new one is always
                 // at least as large as the previous one; this avoids
                 // lots of creation/disposal when the shapes alternate
                 // between narrow/tall and wide/short
-                newTexW = Math.max(maskW, maskTex.getContentWidth());
-                newTexH = Math.max(maskH, maskTex.getContentHeight());
-                maskTex.dispose();
-            }
+            int newTexW = Math.max(MIN_MASK_DIM, Math.max(needW, texW));
+            int newTexH = Math.max(MIN_MASK_DIM, Math.max(needH, texH));
+
             maskTex = getResourceFactory().
-                createMaskTexture(newTexW, newTexH,
-                                  canScale
-                                      ? WrapMode.CLAMP_TO_ZERO
-                                      : WrapMode.CLAMP_NOT_NEEDED);
+                createMaskTexture(newTexW, newTexH, WrapMode.CLAMP_NOT_NEEDED);
+            maskBuffer = ByteBuffer.allocate(newTexW * newTexH);
+            if (clearBuffer == null || clearBuffer.capacity() < newTexW) {
+                clearBuffer = null;
+                clearBuffer = ByteBuffer.allocate(newTexW);
+            }
+            curMaskRow = curMaskCol = nextMaskRow = highMaskCol = 0;
         }
-
-        maskData.uploadToTexture(maskTex, 0, 0, false);
 
         return maskTex;
     }
 
+    public void updateMaskTexture(MaskData maskData, RectBounds maskBounds, boolean canScale) {
+        // assert maskTex bound as texture 1...
+        maskTex.assertLocked();
+        int maskW = maskData.getWidth();
+        int maskH = maskData.getHeight();
+        int texW = maskTex.getContentWidth();
+        int texH = maskTex.getContentHeight();
+        int pad = canScale ? 1 : 0;
+        int needW = maskW + pad + pad;
+        int needH = maskH + pad + pad;
+        if (curMaskCol + needW > texW) {
+            curMaskCol = 0;
+            curMaskRow = nextMaskRow;
+        }
+        if (curMaskRow + needH > texH) {
+            flushVertexBuffer(); // side effect clears mask params
+//            curMaskRow = curMaskCol = nextMaskRow = 0;
+        }
+
+        int offset = curMaskRow * texW + curMaskCol;
+        ByteToBytePixelConverter b2bpc = ByteGray.ToByteGrayConverter();
+        if (canScale) {
+            // [UL => UR)
+            int off = offset;
+            b2bpc.convert(clearBuffer, 0, 0, maskBuffer, off, texW, maskW + 1, 1);
+            // [UR => LR)
+            off = offset + maskW + 1;
+            b2bpc.convert(clearBuffer, 0, 0, maskBuffer, off, texW, 1, maskH + 1);
+            // (UL => LL]
+            off = offset + texW;  // UL corner + 1 row
+            b2bpc.convert(clearBuffer, 0, 0, maskBuffer, off, texW, 1, maskH + 1);
+            // (LL => LR]
+            off = offset + (maskH + 1) * texW + 1; // LL corner + 1 col
+            b2bpc.convert(clearBuffer, 0, 0, maskBuffer, off, texW, maskW + 1, 1);
+            offset += texW + 1;
+        }
+        b2bpc.convert(maskData.getMaskBuffer(), 0, maskW,
+                      maskBuffer, offset, texW,
+                      maskW, maskH);
+
+        float physW = maskTex.getPhysicalWidth();
+        float physH = maskTex.getPhysicalHeight();
+        maskBounds.setMinX((curMaskCol + pad        ) / physW);
+        maskBounds.setMinY((curMaskRow + pad        ) / physH);
+        maskBounds.setMaxX((curMaskCol + pad + maskW) / physW);
+        maskBounds.setMaxY((curMaskRow + pad + maskH) / physH);
+
+        curMaskCol = curMaskCol + needW;
+        if (highMaskCol < curMaskCol) highMaskCol = curMaskCol;
+        if (nextMaskRow < curMaskRow + needH) nextMaskRow = curMaskRow + needH;
+    }
+
     public int getRectTextureMaxSize() {
         if (rectTex == null) {
             createRectTexture();
         }
         return rectTexMax;