src/share/native/sun/java2d/opengl/OGLBlitLoops.c

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2014, 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

@@ -32,10 +32,13 @@
 #include "OGLBlitLoops.h"
 #include "OGLRenderQueue.h"
 #include "OGLSurfaceData.h"
 #include "GraphicsPrimitiveMgr.h"
 
+#include <stdlib.h> // malloc
+#include <string.h> // memcpy
+
 extern OGLPixelFormat PixelFormats[];
 
 /**
  * Inner loop used for copying a source OpenGL "Surface" (window, pbuffer,
  * etc.) to a destination OpenGL "Surface".  Note that the same surface can

@@ -748,19 +751,23 @@
         srcInfo.bounds.y2 > srcInfo.bounds.y1)
     {
         dstOps->GetRasInfo(env, dstOps, &dstInfo);
         if (dstInfo.rasBase) {
             void *pDst = dstInfo.rasBase;
+            void* tempRow;
+            jint clippedStride;
 
             srcx = srcInfo.bounds.x1;
             srcy = srcInfo.bounds.y1;
             dstx = dstInfo.bounds.x1;
             dsty = dstInfo.bounds.y1;
             width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
             height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
 
-            j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, dstx);
+            pDst = PtrAddBytes(pDst, dstx * dstInfo.pixelStride);
+            j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+            j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0);
             j2d_glPixelStorei(GL_PACK_ROW_LENGTH,
                               dstInfo.scanStride / dstInfo.pixelStride);
             j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);
 #ifdef MACOSX
             if (srcOps->isOpaque) {

@@ -779,29 +786,49 @@
 
             // this accounts for lower-left origin of the source region
             srcx = srcOps->xOffset + srcx;
             srcy = srcOps->yOffset + srcOps->height - (srcy + 1);
 
+            // Note that glReadPixels() is extremely slow!
+            // So we try to call it only once and flip the image using memcpy.
+            clippedStride = dstInfo.pixelStride * width;
+            if (tempRow = malloc(clippedStride)) {
+                // fast path
+                jint i;
+                srcy = srcy - height + 1;
+                pDst = PtrAddBytes(pDst, dsty * dstInfo.scanStride);
+                j2d_glReadPixels(srcx, srcy, width, height,
+                                 pf.format, pf.type, pDst);
+                for (i = 0; i < height / 2; ++i) {
+                    void * row1 = PtrAddBytes(pDst, (i * dstInfo.scanStride));
+                    void * row2 = PtrAddBytes(pDst,(height - i - 1) * dstInfo.scanStride);
+                    memcpy(tempRow, row1, clippedStride);
+                    memcpy(row1, row2, clippedStride);
+                    memcpy(row2, tempRow, clippedStride);
+                }
+                free(tempRow);
+            } else {
+                // slow path
             // we must read one scanline at a time because there is no way
             // to read starting at the top-left corner of the source region
             while (height > 0) {
                 j2d_glPixelStorei(GL_PACK_SKIP_ROWS, dsty);
                 j2d_glReadPixels(srcx, srcy, width, 1,
                                  pf.format, pf.type, pDst);
                 srcy--;
                 dsty++;
                 height--;
             }
+                j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+            }
 
 #ifdef MACOSX
             if (srcOps->isOpaque) {
                 j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0);
             }
 #endif
 
-            j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
-            j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0);
             j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
             j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);
         }
         SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
     }