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

Print this page


   1 /*
   2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifndef HEADLESS
  27 
  28 #include <jni.h>
  29 #include <jlong.h>
  30 
  31 #include "SurfaceData.h"
  32 #include "OGLBlitLoops.h"
  33 #include "OGLRenderQueue.h"
  34 #include "OGLSurfaceData.h"
  35 #include "GraphicsPrimitiveMgr.h"
  36 




  37 extern OGLPixelFormat PixelFormats[];
  38 
  39 /**
  40  * Inner loop used for copying a source OpenGL "Surface" (window, pbuffer,
  41  * etc.) to a destination OpenGL "Surface".  Note that the same surface can
  42  * be used as both the source and destination, as is the case in a copyArea()
  43  * operation.  This method is invoked from OGLBlitLoops_IsoBlit() as well as
  44  * OGLBlitLoops_CopyArea().
  45  *
  46  * The standard glCopyPixels() mechanism is used to copy the source region
  47  * into the destination region.  If the regions have different dimensions,
  48  * the source will be scaled into the destination as appropriate (only
  49  * nearest neighbor filtering will be applied for simple scale operations).
  50  */
  51 static void
  52 OGLBlitSurfaceToSurface(OGLContext *oglc, OGLSDOps *srcOps, OGLSDOps *dstOps,
  53                         jint sx1, jint sy1, jint sx2, jint sy2,
  54                         jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
  55 {
  56     GLfloat scalex, scaley;


 318                     GLvoid *pSrc = PtrCoord(srcInfo->rasBase,
 319                                             sx, srcInfo->pixelStride,
 320                                             sy, srcInfo->scanStride);
 321 
 322                     while (tmph > 0) {
 323                         j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
 324                                             0, sh - tmph, sw, 1,
 325                                             pf->format, pf->type,
 326                                             pSrc);
 327                         pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
 328                         tmph--;
 329                     }
 330                 } else {
 331                     j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
 332                     j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
 333 
 334                     j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
 335                                         0, 0, sw, sh,
 336                                         pf->format, pf->type,
 337                                         srcInfo->rasBase);



 338                 }
 339 
 340                 // the texture image is "right side up", so we align the
 341                 // upper-left texture corner with the upper-left quad corner
 342                 j2d_glBegin(GL_QUADS);
 343                 j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx, dy);
 344                 j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx + dw, dy);
 345                 j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx + dw, dy + dh);
 346                 j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx, dy + dh);
 347                 j2d_glEnd();
 348             } else {
 349                 // this accounts for lower-left origin of the source region
 350                 jint newsx = srcOps->xOffset + sx;
 351                 jint newsy = srcOps->yOffset + srcOps->height - (sy + sh);
 352                 j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
 353                                         0, 0, newsx, newsy, sw, sh);
 354 
 355                 // the texture image is "upside down" after the last step, so
 356                 // we align the bottom-left texture corner with the upper-left
 357                 // quad corner (and vice versa) to effectively flip the


 680                                                sx1, sy1, sx2, sy2,
 681                                                dx1, dy1, dx2, dy2);
 682                 } else {
 683                     OGLBlitSwToSurface(oglc, &srcInfo, &pf,
 684                                        sx1, sy1, sx2, sy2,
 685                                        dx1, dy1, dx2, dy2);
 686                 }
 687             }
 688 
 689             j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 690             j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
 691             j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 692             j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 693         }
 694         SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
 695     }
 696     SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
 697 }
 698 
 699 /**












































 700  * Specialized blit method for copying a native OpenGL "Surface" (pbuffer,
 701  * window, etc.) to a system memory ("Sw") surface.
 702  */
 703 void
 704 OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc,
 705                              jlong pSrcOps, jlong pDstOps, jint dsttype,
 706                              jint srcx, jint srcy, jint dstx, jint dsty,
 707                              jint width, jint height)
 708 {
 709     OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
 710     SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);
 711     SurfaceDataRasInfo srcInfo, dstInfo;
 712     OGLPixelFormat pf = PixelFormats[dsttype];
 713 
 714     J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_SurfaceToSwBlit");
 715 
 716     if (width <= 0 || height <= 0) {
 717         J2dTraceLn(J2D_TRACE_WARNING,
 718             "OGLBlitLoops_SurfaceToSwBlit: dimensions are non-positive");
 719         return;


 741 
 742     SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
 743                                     0, 0, srcOps->width, srcOps->height);
 744     SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
 745                                     srcx - dstx, srcy - dsty);
 746 
 747     if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
 748         srcInfo.bounds.y2 > srcInfo.bounds.y1)
 749     {
 750         dstOps->GetRasInfo(env, dstOps, &dstInfo);
 751         if (dstInfo.rasBase) {
 752             void *pDst = dstInfo.rasBase;
 753 
 754             srcx = srcInfo.bounds.x1;
 755             srcy = srcInfo.bounds.y1;
 756             dstx = dstInfo.bounds.x1;
 757             dsty = dstInfo.bounds.y1;
 758             width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
 759             height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
 760 
 761             j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, dstx);


 762             j2d_glPixelStorei(GL_PACK_ROW_LENGTH,
 763                               dstInfo.scanStride / dstInfo.pixelStride);
 764             j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);
 765 #ifdef MACOSX
 766             if (srcOps->isOpaque) {
 767                 // For some reason Apple's OpenGL implementation will
 768                 // read back zero values from the alpha channel of an
 769                 // opaque surface when using glReadPixels(), so here we
 770                 // force the resulting pixels to be fully opaque.
 771                 j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0);
 772             }
 773 #endif
 774 
 775             J2dTraceLn4(J2D_TRACE_VERBOSE, "  sx=%d sy=%d w=%d h=%d",
 776                         srcx, srcy, width, height);
 777             J2dTraceLn2(J2D_TRACE_VERBOSE, "  dx=%d dy=%d",
 778                         dstx, dsty);
 779 
 780             // this accounts for lower-left origin of the source region
 781             srcx = srcOps->xOffset + srcx;
 782             srcy = srcOps->yOffset + srcOps->height - (srcy + 1);
 783 
 784             // we must read one scanline at a time because there is no way
 785             // to read starting at the top-left corner of the source region
 786             while (height > 0) {
 787                 j2d_glPixelStorei(GL_PACK_SKIP_ROWS, dsty);
 788                 j2d_glReadPixels(srcx, srcy, width, 1,
 789                                  pf.format, pf.type, pDst);
 790                 srcy--;
 791                 dsty++;
 792                 height--;
 793             }
 794 
 795 #ifdef MACOSX
 796             if (srcOps->isOpaque) {
 797                 j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0);
 798             }
 799 #endif
 800 
 801             j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
 802             j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0);
 803             j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
 804             j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);
 805         }
 806         SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
 807     }
 808     SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
 809 }
 810 
 811 void
 812 OGLBlitLoops_CopyArea(JNIEnv *env,
 813                       OGLContext *oglc, OGLSDOps *dstOps,
 814                       jint x, jint y, jint width, jint height,
 815                       jint dx, jint dy)
 816 {
 817     SurfaceDataBounds srcBounds, dstBounds;
 818 
 819     J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_CopyArea");
 820 
 821     RETURN_IF_NULL(oglc);
 822     RETURN_IF_NULL(dstOps);


   1 /*
   2  * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifndef HEADLESS
  27 
  28 #include <jni.h>
  29 #include <jlong.h>
  30 
  31 #include "SurfaceData.h"
  32 #include "OGLBlitLoops.h"
  33 #include "OGLRenderQueue.h"
  34 #include "OGLSurfaceData.h"
  35 #include "GraphicsPrimitiveMgr.h"
  36 
  37 #include <stdlib.h> // malloc
  38 #include <string.h> // memcpy
  39 #include "IntArgbPre.h"
  40 
  41 extern OGLPixelFormat PixelFormats[];
  42 
  43 /**
  44  * Inner loop used for copying a source OpenGL "Surface" (window, pbuffer,
  45  * etc.) to a destination OpenGL "Surface".  Note that the same surface can
  46  * be used as both the source and destination, as is the case in a copyArea()
  47  * operation.  This method is invoked from OGLBlitLoops_IsoBlit() as well as
  48  * OGLBlitLoops_CopyArea().
  49  *
  50  * The standard glCopyPixels() mechanism is used to copy the source region
  51  * into the destination region.  If the regions have different dimensions,
  52  * the source will be scaled into the destination as appropriate (only
  53  * nearest neighbor filtering will be applied for simple scale operations).
  54  */
  55 static void
  56 OGLBlitSurfaceToSurface(OGLContext *oglc, OGLSDOps *srcOps, OGLSDOps *dstOps,
  57                         jint sx1, jint sy1, jint sx2, jint sy2,
  58                         jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
  59 {
  60     GLfloat scalex, scaley;


 322                     GLvoid *pSrc = PtrCoord(srcInfo->rasBase,
 323                                             sx, srcInfo->pixelStride,
 324                                             sy, srcInfo->scanStride);
 325 
 326                     while (tmph > 0) {
 327                         j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
 328                                             0, sh - tmph, sw, 1,
 329                                             pf->format, pf->type,
 330                                             pSrc);
 331                         pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
 332                         tmph--;
 333                     }
 334                 } else {
 335                     j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
 336                     j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
 337 
 338                     j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
 339                                         0, 0, sw, sh,
 340                                         pf->format, pf->type,
 341                                         srcInfo->rasBase);
 342 
 343                     j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 344                     j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
 345                 }
 346 
 347                 // the texture image is "right side up", so we align the
 348                 // upper-left texture corner with the upper-left quad corner
 349                 j2d_glBegin(GL_QUADS);
 350                 j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx, dy);
 351                 j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx + dw, dy);
 352                 j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx + dw, dy + dh);
 353                 j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx, dy + dh);
 354                 j2d_glEnd();
 355             } else {
 356                 // this accounts for lower-left origin of the source region
 357                 jint newsx = srcOps->xOffset + sx;
 358                 jint newsy = srcOps->yOffset + srcOps->height - (sy + sh);
 359                 j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
 360                                         0, 0, newsx, newsy, sw, sh);
 361 
 362                 // the texture image is "upside down" after the last step, so
 363                 // we align the bottom-left texture corner with the upper-left
 364                 // quad corner (and vice versa) to effectively flip the


 687                                                sx1, sy1, sx2, sy2,
 688                                                dx1, dy1, dx2, dy2);
 689                 } else {
 690                     OGLBlitSwToSurface(oglc, &srcInfo, &pf,
 691                                        sx1, sy1, sx2, sy2,
 692                                        dx1, dy1, dx2, dy2);
 693                 }
 694             }
 695 
 696             j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 697             j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
 698             j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 699             j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 700         }
 701         SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
 702     }
 703     SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
 704 }
 705 
 706 /**
 707  * This method makes vertical flip of the provided area of Surface and convert
 708  * pixel's data from argbPre to argb format if requested.
 709  */
 710 void flip(void *pDst, juint w, juint h, jint scanStride, jboolean convert) {
 711     const size_t clippedStride = 4 * w;
 712     void *tempRow = (h > 1 && !convert) ? malloc(clippedStride) : NULL;
 713     juint i = 0;
 714     juint step = 0;
 715     // vertical flip and convert argbpre to argb if necessary
 716     for (; i < h / 2; ++i) {
 717         juint *r1 = PtrAddBytes(pDst, (i * scanStride));
 718         juint *r2 = PtrAddBytes(pDst, (h - i - 1) * scanStride);
 719         if (tempRow) {
 720             // fast path
 721             memcpy(tempRow, r1, clippedStride);
 722             memcpy(r1, r2, clippedStride);
 723             memcpy(r2, tempRow, clippedStride);
 724         } else {
 725             // slow path
 726             for (step = 0; step < w; ++step) {
 727                 juint tmp = r1[step];
 728                 if (convert) {
 729                     LoadIntArgbPreTo1IntArgb(r2, 0, step, r1[step]);
 730                     LoadIntArgbPreTo1IntArgb(&tmp, 0, 0, r2[step]);
 731                 } else {
 732                     r1[step] = r2[step];
 733                     r2[step] = tmp;
 734                 }
 735             }
 736         }
 737     }
 738     // convert the middle line if necessary
 739     if (convert && h % 2) {
 740         juint *r1 = PtrAddBytes(pDst, (i * scanStride));
 741         for (step = 0; step < w; ++step) {
 742             LoadIntArgbPreTo1IntArgb(r1, 0, step, r1[step]);
 743         }
 744     }
 745     if (tempRow) {
 746         free(tempRow);
 747     }
 748 }
 749 
 750 /**
 751  * Specialized blit method for copying a native OpenGL "Surface" (pbuffer,
 752  * window, etc.) to a system memory ("Sw") surface.
 753  */
 754 void
 755 OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc,
 756                              jlong pSrcOps, jlong pDstOps, jint dsttype,
 757                              jint srcx, jint srcy, jint dstx, jint dsty,
 758                              jint width, jint height)
 759 {
 760     OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
 761     SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);
 762     SurfaceDataRasInfo srcInfo, dstInfo;
 763     OGLPixelFormat pf = PixelFormats[dsttype];
 764 
 765     J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_SurfaceToSwBlit");
 766 
 767     if (width <= 0 || height <= 0) {
 768         J2dTraceLn(J2D_TRACE_WARNING,
 769             "OGLBlitLoops_SurfaceToSwBlit: dimensions are non-positive");
 770         return;


 792 
 793     SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
 794                                     0, 0, srcOps->width, srcOps->height);
 795     SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
 796                                     srcx - dstx, srcy - dsty);
 797 
 798     if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
 799         srcInfo.bounds.y2 > srcInfo.bounds.y1)
 800     {
 801         dstOps->GetRasInfo(env, dstOps, &dstInfo);
 802         if (dstInfo.rasBase) {
 803             void *pDst = dstInfo.rasBase;
 804 
 805             srcx = srcInfo.bounds.x1;
 806             srcy = srcInfo.bounds.y1;
 807             dstx = dstInfo.bounds.x1;
 808             dsty = dstInfo.bounds.y1;
 809             width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
 810             height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
 811 
 812             pDst = PtrAddBytes(pDst, dstx * dstInfo.pixelStride);
 813             pDst = PtrAddBytes(pDst, dsty * dstInfo.scanStride);
 814 
 815             j2d_glPixelStorei(GL_PACK_ROW_LENGTH,
 816                               dstInfo.scanStride / dstInfo.pixelStride);
 817             j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);
 818 #ifdef MACOSX
 819             if (srcOps->isOpaque) {
 820                 // For some reason Apple's OpenGL implementation will
 821                 // read back zero values from the alpha channel of an
 822                 // opaque surface when using glReadPixels(), so here we
 823                 // force the resulting pixels to be fully opaque.
 824                 j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0);
 825             }
 826 #endif
 827 
 828             J2dTraceLn4(J2D_TRACE_VERBOSE, "  sx=%d sy=%d w=%d h=%d",
 829                         srcx, srcy, width, height);
 830             J2dTraceLn2(J2D_TRACE_VERBOSE, "  dx=%d dy=%d",
 831                         dstx, dsty);
 832 
 833             // this accounts for lower-left origin of the source region
 834             srcx = srcOps->xOffset + srcx;
 835             srcy = srcOps->yOffset + srcOps->height - srcy - height;
 836 
 837             // Note that glReadPixels() is extremely slow!
 838             // So we call it only once and flip the image using memcpy.
 839             j2d_glReadPixels(srcx, srcy, width, height,


 840                              pf.format, pf.type, pDst);
 841             // It was checked above that width and height are positive.
 842             flip(pDst, (juint) width, (juint) height, dstInfo.scanStride,
 843                  !pf.isPremult && !srcOps->isOpaque);


 844 #ifdef MACOSX
 845             if (srcOps->isOpaque) {
 846                 j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0);
 847             }
 848 #endif



 849             j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
 850             j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);
 851         }
 852         SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
 853     }
 854     SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
 855 }
 856 
 857 void
 858 OGLBlitLoops_CopyArea(JNIEnv *env,
 859                       OGLContext *oglc, OGLSDOps *dstOps,
 860                       jint x, jint y, jint width, jint height,
 861                       jint dx, jint dy)
 862 {
 863     SurfaceDataBounds srcBounds, dstBounds;
 864 
 865     J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_CopyArea");
 866 
 867     RETURN_IF_NULL(oglc);
 868     RETURN_IF_NULL(dstOps);