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 
  40 extern OGLPixelFormat PixelFormats[];
  41 
  42 /**
  43  * Inner loop used for copying a source OpenGL "Surface" (window, pbuffer,
  44  * etc.) to a destination OpenGL "Surface".  Note that the same surface can
  45  * be used as both the source and destination, as is the case in a copyArea()
  46  * operation.  This method is invoked from OGLBlitLoops_IsoBlit() as well as
  47  * OGLBlitLoops_CopyArea().
  48  *
  49  * The standard glCopyPixels() mechanism is used to copy the source region
  50  * into the destination region.  If the regions have different dimensions,
  51  * the source will be scaled into the destination as appropriate (only
  52  * nearest neighbor filtering will be applied for simple scale operations).
  53  */
  54 static void
  55 OGLBlitSurfaceToSurface(OGLContext *oglc, OGLSDOps *srcOps, OGLSDOps *dstOps,
  56                         jint sx1, jint sy1, jint sx2, jint sy2,
  57                         jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
  58 {
  59     GLfloat scalex, scaley;
  60     jint srcw = sx2 - sx1;
  61     jint srch = sy2 - sy1;
  62 
  63     scalex = ((GLfloat)(dx2-dx1)) / srcw;
  64     scaley = ((GLfloat)(dy2-dy1)) / srch;
  65 
  66     // the following lines account for the fact that glCopyPixels() copies a
  67     // region whose lower-left corner is at (x,y), but the source parameters
  68     // (sx1,sy1) we are given here point to the upper-left corner of the
  69     // source region... so here we play with the sy1 and dy1 parameters so
  70     // that they point to the lower-left corners of the regions...
  71     sx1 = srcOps->xOffset + sx1;
  72     sy1 = srcOps->yOffset + srcOps->height - sy2;
  73     dy1 = dy2;
  74 
  75     if (oglc->extraAlpha != 1.0f) {
  76         OGLContext_SetExtraAlpha(oglc->extraAlpha);
  77     }
  78 
  79     // see OGLBlitSwToSurface() for more info on the following two lines
  80     j2d_glRasterPos2i(0, 0);
  81     j2d_glBitmap(0, 0, 0, 0, (GLfloat)dx1, (GLfloat)-dy1, NULL);
  82 
  83     if (scalex == 1.0f && scaley == 1.0f) {
  84         j2d_glCopyPixels(sx1, sy1, srcw, srch, GL_COLOR);
  85     } else {
  86         j2d_glPixelZoom(scalex, scaley);
  87         j2d_glCopyPixels(sx1, sy1, srcw, srch, GL_COLOR);
  88         j2d_glPixelZoom(1.0f, 1.0f);
  89     }
  90 
  91     if (oglc->extraAlpha != 1.0f) {
  92         OGLContext_SetExtraAlpha(1.0f);
  93     }
  94 }
  95 
  96 /**
  97  * Inner loop used for copying a source OpenGL "Texture" to a destination
  98  * OpenGL "Surface".  This method is invoked from OGLBlitLoops_IsoBlit().
  99  *
 100  * This method will copy, scale, or transform the source texture into the
 101  * destination depending on the transform state, as established in
 102  * and OGLContext_SetTransform().  If the source texture is
 103  * transformed in any way when rendered into the destination, the filtering
 104  * method applied is determined by the hint parameter (can be GL_NEAREST or
 105  * GL_LINEAR).
 106  */
 107 static void
 108 OGLBlitTextureToSurface(OGLContext *oglc,
 109                         OGLSDOps *srcOps, OGLSDOps *dstOps,
 110                         jboolean rtt, jint hint,
 111                         jint sx1, jint sy1, jint sx2, jint sy2,
 112                         jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
 113 {
 114     GLdouble tx1, ty1, tx2, ty2;
 115 
 116     if (rtt) {
 117         /*
 118          * The source is a render-to-texture surface.  These surfaces differ
 119          * from regular texture objects in that the bottom scanline (of
 120          * the actual image content) coincides with the top edge of the
 121          * texture object.  Therefore, we need to adjust the sy1/sy2
 122          * coordinates relative to the top scanline of the image content.
 123          *
 124          * In texture coordinates, the top-left corner of the image content
 125          * would be at:
 126          *     (0.0, (imgHeight/texHeight))
 127          * while the bottom-right corner corresponds to:
 128          *     ((imgWidth/texWidth), 0.0)
 129          */
 130         sy1 = srcOps->height - sy1;
 131         sy2 = srcOps->height - sy2;
 132     }
 133 
 134     if (srcOps->textureTarget == GL_TEXTURE_RECTANGLE_ARB) {
 135         // The GL_ARB_texture_rectangle extension requires that we specify
 136         // texture coordinates in the range [0,srcw] and [0,srch] instead of
 137         // [0,1] as we would normally do in the case of GL_TEXTURE_2D
 138         tx1 = (GLdouble)sx1;
 139         ty1 = (GLdouble)sy1;
 140         tx2 = (GLdouble)sx2;
 141         ty2 = (GLdouble)sy2;
 142     } else {
 143         // Otherwise we need to convert the source bounds into the range [0,1]
 144         tx1 = ((GLdouble)sx1) / srcOps->textureWidth;
 145         ty1 = ((GLdouble)sy1) / srcOps->textureHeight;
 146         tx2 = ((GLdouble)sx2) / srcOps->textureWidth;
 147         ty2 = ((GLdouble)sy2) / srcOps->textureHeight;
 148     }
 149 
 150     // Note that we call CHECK_PREVIOUS_OP(texTarget) in IsoBlit(), which
 151     // will call glEnable(texTarget) as necessary.
 152     j2d_glBindTexture(srcOps->textureTarget, srcOps->textureID);
 153     OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
 154     OGLSD_UPDATE_TEXTURE_FILTER(srcOps, hint);
 155 
 156     j2d_glBegin(GL_QUADS);
 157     j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx1, dy1);
 158     j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx2, dy1);
 159     j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx2, dy2);
 160     j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx1, dy2);
 161     j2d_glEnd();
 162 }
 163 
 164 /**
 165  * Inner loop used for copying a source system memory ("Sw") surface to a
 166  * destination OpenGL "Surface".  This method is invoked from
 167  * OGLBlitLoops_Blit().
 168  *
 169  * The standard glDrawPixels() mechanism is used to copy the source region
 170  * into the destination region.  If the regions have different
 171  * dimensions, the source will be scaled into the destination
 172  * as appropriate (only nearest neighbor filtering will be applied for simple
 173  * scale operations).
 174  */
 175 static void
 176 OGLBlitSwToSurface(OGLContext *oglc, SurfaceDataRasInfo *srcInfo,
 177                    OGLPixelFormat *pf,
 178                    jint sx1, jint sy1, jint sx2, jint sy2,
 179                    jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
 180 {
 181     GLfloat scalex, scaley;
 182 
 183     scalex = ((GLfloat)(dx2-dx1)) / (sx2-sx1);
 184     scaley = ((GLfloat)(dy2-dy1)) / (sy2-sy1);
 185 
 186     if (oglc->extraAlpha != 1.0f) {
 187         OGLContext_SetExtraAlpha(oglc->extraAlpha);
 188     }
 189     if (!pf->hasAlpha) {
 190         // if the source surface does not have an alpha channel,
 191         // we need to ensure that the alpha values are forced to
 192         // the current extra alpha value (see OGLContext_SetExtraAlpha()
 193         // for more information)
 194         j2d_glPixelTransferf(GL_ALPHA_SCALE, 0.0f);
 195         j2d_glPixelTransferf(GL_ALPHA_BIAS, oglc->extraAlpha);
 196     }
 197 
 198     // This is a rather intriguing (yet totally valid) hack... If we were to
 199     // specify a raster position that is outside the surface bounds, the raster
 200     // position would be invalid and nothing would be rendered.  However, we
 201     // can use a widely known trick to move the raster position outside the
 202     // surface bounds while maintaining its status as valid.  The following
 203     // call to glBitmap() renders a no-op bitmap, but offsets the current
 204     // raster position from (0,0) to the desired location of (dx1,-dy1)...
 205     j2d_glRasterPos2i(0, 0);
 206     j2d_glBitmap(0, 0, 0, 0, (GLfloat)dx1, (GLfloat)-dy1, NULL);
 207 
 208     j2d_glPixelZoom(scalex, -scaley);
 209 
 210     // in case pixel stride is not a multiple of scanline stride the copy
 211     // has to be done line by line (see 6207877)
 212     if (srcInfo->scanStride % srcInfo->pixelStride != 0) {
 213         jint width = sx2-sx1;
 214         jint height = sy2-sy1;
 215         GLvoid *pSrc = srcInfo->rasBase;
 216 
 217         while (height > 0) {
 218             j2d_glDrawPixels(width, 1, pf->format, pf->type, pSrc);
 219             j2d_glBitmap(0, 0, 0, 0, (GLfloat)0, (GLfloat)-1, NULL);
 220             pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
 221             height--;
 222         }
 223     } else {
 224         j2d_glDrawPixels(sx2-sx1, sy2-sy1, pf->format, pf->type, srcInfo->rasBase);
 225     }
 226 
 227     j2d_glPixelZoom(1.0, 1.0);
 228 
 229     if (oglc->extraAlpha != 1.0f) {
 230         OGLContext_SetExtraAlpha(1.0f);
 231     }
 232     if (!pf->hasAlpha) {
 233         // restore scale/bias to their original values
 234         j2d_glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
 235         j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0f);
 236     }
 237 }
 238 
 239 /**
 240  * Inner loop used for copying a source system memory ("Sw") surface or
 241  * OpenGL "Surface" to a destination OpenGL "Surface", using an OpenGL texture
 242  * tile as an intermediate surface.  This method is invoked from
 243  * OGLBlitLoops_Blit() for "Sw" surfaces and OGLBlitLoops_IsoBlit() for
 244  * "Surface" surfaces.
 245  *
 246  * This method is used to transform the source surface into the destination.
 247  * Pixel rectangles cannot be arbitrarily transformed (without the
 248  * GL_EXT_pixel_transform extension, which is not supported on most modern
 249  * hardware).  However, texture mapped quads do respect the GL_MODELVIEW
 250  * transform matrix, so we use textures here to perform the transform
 251  * operation.  This method uses a tile-based approach in which a small
 252  * subregion of the source surface is copied into a cached texture tile.  The
 253  * texture tile is then mapped into the appropriate location in the
 254  * destination surface.
 255  *
 256  * REMIND: this only works well using GL_NEAREST for the filtering mode
 257  *         (GL_LINEAR causes visible stitching problems between tiles,
 258  *         but this can be fixed by making use of texture borders)
 259  */
 260 static void
 261 OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo,
 262                            OGLPixelFormat *pf, OGLSDOps *srcOps,
 263                            jboolean swsurface, jint hint,
 264                            jint sx1, jint sy1, jint sx2, jint sy2,
 265                            jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
 266 {
 267     GLdouble tx1, ty1, tx2, ty2;
 268     GLdouble dx, dy, dw, dh, cdw, cdh;
 269     jint tw, th;
 270     jint sx, sy, sw, sh;
 271     GLint glhint = (hint == OGLSD_XFORM_BILINEAR) ? GL_LINEAR : GL_NEAREST;
 272     jboolean adjustAlpha = (pf != NULL && !pf->hasAlpha);
 273     jboolean slowPath;
 274 
 275     if (oglc->blitTextureID == 0) {
 276         if (!OGLContext_InitBlitTileTexture(oglc)) {
 277             J2dRlsTraceLn(J2D_TRACE_ERROR,
 278                 "OGLBlitToSurfaceViaTexture: could not init blit tile");
 279             return;
 280         }
 281     }
 282 
 283     tx1 = 0.0f;
 284     ty1 = 0.0f;
 285     tw = OGLC_BLIT_TILE_SIZE;
 286     th = OGLC_BLIT_TILE_SIZE;
 287     cdw = (dx2-dx1) / (((GLdouble)(sx2-sx1)) / OGLC_BLIT_TILE_SIZE);
 288     cdh = (dy2-dy1) / (((GLdouble)(sy2-sy1)) / OGLC_BLIT_TILE_SIZE);
 289 
 290     j2d_glEnable(GL_TEXTURE_2D);
 291     j2d_glBindTexture(GL_TEXTURE_2D, oglc->blitTextureID);
 292     OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
 293     j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glhint);
 294     j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glhint);
 295 
 296     if (adjustAlpha) {
 297         // if the source surface does not have an alpha channel,
 298         // we need to ensure that the alpha values are forced to 1.0f
 299         j2d_glPixelTransferf(GL_ALPHA_SCALE, 0.0f);
 300         j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0f);
 301     }
 302 
 303     // in case pixel stride is not a multiple of scanline stride the copy
 304     // has to be done line by line (see 6207877)
 305     slowPath = srcInfo->scanStride % srcInfo->pixelStride != 0;
 306 
 307     for (sy = sy1, dy = dy1; sy < sy2; sy += th, dy += cdh) {
 308         sh = ((sy + th) > sy2) ? (sy2 - sy) : th;
 309         dh = ((dy + cdh) > dy2) ? (dy2 - dy) : cdh;
 310 
 311         for (sx = sx1, dx = dx1; sx < sx2; sx += tw, dx += cdw) {
 312             sw = ((sx + tw) > sx2) ? (sx2 - sx) : tw;
 313             dw = ((dx + cdw) > dx2) ? (dx2 - dx) : cdw;
 314 
 315             tx2 = ((GLdouble)sw) / tw;
 316             ty2 = ((GLdouble)sh) / th;
 317 
 318             if (swsurface) {
 319                 if (slowPath) {
 320                     jint tmph = sh;
 321                     GLvoid *pSrc = PtrCoord(srcInfo->rasBase,
 322                                             sx, srcInfo->pixelStride,
 323                                             sy, srcInfo->scanStride);
 324 
 325                     while (tmph > 0) {
 326                         j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
 327                                             0, sh - tmph, sw, 1,
 328                                             pf->format, pf->type,
 329                                             pSrc);
 330                         pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
 331                         tmph--;
 332                     }
 333                 } else {
 334                     j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
 335                     j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
 336 
 337                     j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
 338                                         0, 0, sw, sh,
 339                                         pf->format, pf->type,
 340                                         srcInfo->rasBase);
 341                 }
 342 
 343                 // the texture image is "right side up", so we align the
 344                 // upper-left texture corner with the upper-left quad corner
 345                 j2d_glBegin(GL_QUADS);
 346                 j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx, dy);
 347                 j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx + dw, dy);
 348                 j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx + dw, dy + dh);
 349                 j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx, dy + dh);
 350                 j2d_glEnd();
 351             } else {
 352                 // this accounts for lower-left origin of the source region
 353                 jint newsx = srcOps->xOffset + sx;
 354                 jint newsy = srcOps->yOffset + srcOps->height - (sy + sh);
 355                 j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
 356                                         0, 0, newsx, newsy, sw, sh);
 357 
 358                 // the texture image is "upside down" after the last step, so
 359                 // we align the bottom-left texture corner with the upper-left
 360                 // quad corner (and vice versa) to effectively flip the
 361                 // texture image
 362                 j2d_glBegin(GL_QUADS);
 363                 j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx, dy);
 364                 j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx + dw, dy);
 365                 j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx + dw, dy + dh);
 366                 j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx, dy + dh);
 367                 j2d_glEnd();
 368             }
 369         }
 370     }
 371 
 372     if (adjustAlpha) {
 373         // restore scale/bias to their original values
 374         j2d_glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
 375         j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0f);
 376     }
 377 
 378     j2d_glDisable(GL_TEXTURE_2D);
 379 }
 380 
 381 /**
 382  * Inner loop used for copying a source system memory ("Sw") surface to a
 383  * destination OpenGL "Texture".  This method is invoked from
 384  * OGLBlitLoops_Blit().
 385  *
 386  * The source surface is effectively loaded into the OpenGL texture object,
 387  * which must have already been initialized by OGLSD_initTexture().  Note
 388  * that this method is only capable of copying the source surface into the
 389  * destination surface (i.e. no scaling or general transform is allowed).
 390  * This restriction should not be an issue as this method is only used
 391  * currently to cache a static system memory image into an OpenGL texture in
 392  * a hidden-acceleration situation.
 393  */
 394 static void
 395 OGLBlitSwToTexture(SurfaceDataRasInfo *srcInfo, OGLPixelFormat *pf,
 396                    OGLSDOps *dstOps,
 397                    jint dx1, jint dy1, jint dx2, jint dy2)
 398 {
 399     jboolean adjustAlpha = (pf != NULL && !pf->hasAlpha);
 400     j2d_glBindTexture(dstOps->textureTarget, dstOps->textureID);
 401 
 402     if (adjustAlpha) {
 403         // if the source surface does not have an alpha channel,
 404         // we need to ensure that the alpha values are forced to 1.0f
 405         j2d_glPixelTransferf(GL_ALPHA_SCALE, 0.0f);
 406         j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0f);
 407     }
 408 
 409     // in case pixel stride is not a multiple of scanline stride the copy
 410     // has to be done line by line (see 6207877)
 411     if (srcInfo->scanStride % srcInfo->pixelStride != 0) {
 412         jint width = dx2 - dx1;
 413         jint height = dy2 - dy1;
 414         GLvoid *pSrc = srcInfo->rasBase;
 415 
 416         while (height > 0) {
 417             j2d_glTexSubImage2D(dstOps->textureTarget, 0,
 418                                 dx1, dy2 - height, width, 1,
 419                                 pf->format, pf->type, pSrc);
 420             pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
 421             height--;
 422         }
 423     } else {
 424         j2d_glTexSubImage2D(dstOps->textureTarget, 0,
 425                             dx1, dy1, dx2-dx1, dy2-dy1,
 426                             pf->format, pf->type, srcInfo->rasBase);
 427     }
 428     if (adjustAlpha) {
 429         // restore scale/bias to their original values
 430         j2d_glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
 431         j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0f);
 432     }
 433 }
 434 
 435 /**
 436  * General blit method for copying a native OpenGL surface (of type "Surface"
 437  * or "Texture") to another OpenGL "Surface".  If texture is JNI_TRUE, this
 438  * method will invoke the Texture->Surface inner loop; otherwise, one of the
 439  * Surface->Surface inner loops will be invoked, depending on the transform
 440  * state.
 441  *
 442  * REMIND: we can trick these blit methods into doing XOR simply by passing
 443  *         in the (pixel ^ xorpixel) as the pixel value and preceding the
 444  *         blit with a fillrect...
 445  */
 446 void
 447 OGLBlitLoops_IsoBlit(JNIEnv *env,
 448                      OGLContext *oglc, jlong pSrcOps, jlong pDstOps,
 449                      jboolean xform, jint hint,
 450                      jboolean texture, jboolean rtt,
 451                      jint sx1, jint sy1, jint sx2, jint sy2,
 452                      jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
 453 {
 454     OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
 455     OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDstOps);
 456     SurfaceDataRasInfo srcInfo;
 457     jint sw    = sx2 - sx1;
 458     jint sh    = sy2 - sy1;
 459     jdouble dw = dx2 - dx1;
 460     jdouble dh = dy2 - dy1;
 461 
 462     J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_IsoBlit");
 463 
 464     if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) {
 465         J2dTraceLn(J2D_TRACE_WARNING,
 466                    "OGLBlitLoops_IsoBlit: invalid dimensions");
 467         return;
 468     }
 469 
 470     RETURN_IF_NULL(srcOps);
 471     RETURN_IF_NULL(dstOps);
 472     RETURN_IF_NULL(oglc);
 473 
 474     srcInfo.bounds.x1 = sx1;
 475     srcInfo.bounds.y1 = sy1;
 476     srcInfo.bounds.x2 = sx2;
 477     srcInfo.bounds.y2 = sy2;
 478 
 479     SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
 480                                     0, 0, srcOps->width, srcOps->height);
 481 
 482     if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
 483         srcInfo.bounds.y2 > srcInfo.bounds.y1)
 484     {
 485         if (srcInfo.bounds.x1 != sx1) {
 486             dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
 487             sx1 = srcInfo.bounds.x1;
 488         }
 489         if (srcInfo.bounds.y1 != sy1) {
 490             dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
 491             sy1 = srcInfo.bounds.y1;
 492         }
 493         if (srcInfo.bounds.x2 != sx2) {
 494             dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
 495             sx2 = srcInfo.bounds.x2;
 496         }
 497         if (srcInfo.bounds.y2 != sy2) {
 498             dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
 499             sy2 = srcInfo.bounds.y2;
 500         }
 501 
 502         J2dTraceLn2(J2D_TRACE_VERBOSE, "  texture=%d hint=%d", texture, hint);
 503         J2dTraceLn4(J2D_TRACE_VERBOSE, "  sx1=%d sy1=%d sx2=%d sy2=%d",
 504                     sx1, sy1, sx2, sy2);
 505         J2dTraceLn4(J2D_TRACE_VERBOSE, "  dx1=%f dy1=%f dx2=%f dy2=%f",
 506                     dx1, dy1, dx2, dy2);
 507 
 508         if (texture) {
 509             GLint glhint = (hint == OGLSD_XFORM_BILINEAR) ? GL_LINEAR :
 510                                                             GL_NEAREST;
 511             CHECK_PREVIOUS_OP(srcOps->textureTarget);
 512             OGLBlitTextureToSurface(oglc, srcOps, dstOps, rtt, glhint,
 513                                     sx1, sy1, sx2, sy2,
 514                                     dx1, dy1, dx2, dy2);
 515         } else {
 516             jboolean viaTexture;
 517             if (xform) {
 518                 // we must use the via-texture codepath when there is a xform
 519                 viaTexture = JNI_TRUE;
 520             } else {
 521                 // look at the vendor to see which codepath is faster
 522                 // (this has been empirically determined; see 5020009)
 523                 switch (OGLC_GET_VENDOR(oglc)) {
 524                 case OGLC_VENDOR_NVIDIA:
 525                     // the via-texture codepath tends to be faster when
 526                     // there is either a simple scale OR an extra alpha
 527                     viaTexture =
 528                         (sx2-sx1) != (jint)(dx2-dx1) ||
 529                         (sy2-sy1) != (jint)(dy2-dy1) ||
 530                         oglc->extraAlpha != 1.0f;
 531                     break;
 532 
 533                 case OGLC_VENDOR_ATI:
 534                     // the via-texture codepath tends to be faster only when
 535                     // there is an extra alpha involved (scaling or not)
 536                     viaTexture = (oglc->extraAlpha != 1.0f);
 537                     break;
 538 
 539                 default:
 540                     // just use the glCopyPixels() codepath
 541                     viaTexture = JNI_FALSE;
 542                     break;
 543                 }
 544             }
 545 
 546             RESET_PREVIOUS_OP();
 547             if (viaTexture) {
 548                 OGLBlitToSurfaceViaTexture(oglc, &srcInfo, NULL, srcOps,
 549                                            JNI_FALSE, hint,
 550                                            sx1, sy1, sx2, sy2,
 551                                            dx1, dy1, dx2, dy2);
 552             } else {
 553                 OGLBlitSurfaceToSurface(oglc, srcOps, dstOps,
 554                                         sx1, sy1, sx2, sy2,
 555                                         dx1, dy1, dx2, dy2);
 556             }
 557         }
 558     }
 559 }
 560 
 561 /**
 562  * General blit method for copying a system memory ("Sw") surface to a native
 563  * OpenGL surface (of type "Surface" or "Texture").  If texture is JNI_TRUE,
 564  * this method will invoke the Sw->Texture inner loop; otherwise, one of the
 565  * Sw->Surface inner loops will be invoked, depending on the transform state.
 566  */
 567 void
 568 OGLBlitLoops_Blit(JNIEnv *env,
 569                   OGLContext *oglc, jlong pSrcOps, jlong pDstOps,
 570                   jboolean xform, jint hint,
 571                   jint srctype, jboolean texture,
 572                   jint sx1, jint sy1, jint sx2, jint sy2,
 573                   jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
 574 {
 575     SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);
 576     OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDstOps);
 577     SurfaceDataRasInfo srcInfo;
 578     OGLPixelFormat pf = PixelFormats[srctype];
 579     jint sw    = sx2 - sx1;
 580     jint sh    = sy2 - sy1;
 581     jdouble dw = dx2 - dx1;
 582     jdouble dh = dy2 - dy1;
 583 
 584     J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_Blit");
 585 
 586     if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0 || srctype < 0) {
 587         J2dTraceLn(J2D_TRACE_WARNING,
 588                    "OGLBlitLoops_Blit: invalid dimensions or srctype");
 589         return;
 590     }
 591 
 592     RETURN_IF_NULL(srcOps);
 593     RETURN_IF_NULL(dstOps);
 594     RETURN_IF_NULL(oglc);
 595     RESET_PREVIOUS_OP();
 596 
 597     srcInfo.bounds.x1 = sx1;
 598     srcInfo.bounds.y1 = sy1;
 599     srcInfo.bounds.x2 = sx2;
 600     srcInfo.bounds.y2 = sy2;
 601 
 602     if (srcOps->Lock(env, srcOps, &srcInfo, SD_LOCK_READ) != SD_SUCCESS) {
 603         J2dTraceLn(J2D_TRACE_WARNING,
 604                    "OGLBlitLoops_Blit: could not acquire lock");
 605         return;
 606     }
 607 
 608     if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
 609         srcInfo.bounds.y2 > srcInfo.bounds.y1)
 610     {
 611         srcOps->GetRasInfo(env, srcOps, &srcInfo);
 612         if (srcInfo.rasBase) {
 613             if (srcInfo.bounds.x1 != sx1) {
 614                 dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
 615                 sx1 = srcInfo.bounds.x1;
 616             }
 617             if (srcInfo.bounds.y1 != sy1) {
 618                 dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
 619                 sy1 = srcInfo.bounds.y1;
 620             }
 621             if (srcInfo.bounds.x2 != sx2) {
 622                 dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
 623                 sx2 = srcInfo.bounds.x2;
 624             }
 625             if (srcInfo.bounds.y2 != sy2) {
 626                 dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
 627                 sy2 = srcInfo.bounds.y2;
 628             }
 629 
 630             J2dTraceLn3(J2D_TRACE_VERBOSE, "  texture=%d srctype=%d hint=%d",
 631                         texture, srctype, hint);
 632             J2dTraceLn4(J2D_TRACE_VERBOSE, "  sx1=%d sy1=%d sx2=%d sy2=%d",
 633                         sx1, sy1, sx2, sy2);
 634             J2dTraceLn4(J2D_TRACE_VERBOSE, "  dx1=%f dy1=%f dx2=%f dy2=%f",
 635                         dx1, dy1, dx2, dy2);
 636 
 637             j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx1);
 638             j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy1);
 639             j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH,
 640                               srcInfo.scanStride / srcInfo.pixelStride);
 641             j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, pf.alignment);
 642 
 643             if (texture) {
 644                 // These coordinates will always be integers since we
 645                 // only ever do a straight copy from sw to texture.
 646                 // Thus these casts are "safe" - no loss of precision.
 647                 OGLBlitSwToTexture(&srcInfo, &pf, dstOps,
 648                                    (jint)dx1, (jint)dy1, (jint)dx2, (jint)dy2);
 649             } else {
 650                 jboolean viaTexture;
 651                 if (xform) {
 652                     // we must use the via-texture codepath when there
 653                     // is a xform
 654                     viaTexture = JNI_TRUE;
 655                 } else {
 656                     // look at the vendor to see which codepath is faster
 657                     // (this has been empirically determined; see 5020009)
 658                     switch (OGLC_GET_VENDOR(oglc)) {
 659                     case OGLC_VENDOR_NVIDIA:
 660                         // the via-texture codepath tends to be faster when
 661                         // there is either a simple scale OR an extra alpha
 662                         viaTexture =
 663                             (sx2-sx1) != (jint)(dx2-dx1) ||
 664                             (sy2-sy1) != (jint)(dy2-dy1) ||
 665                             oglc->extraAlpha != 1.0f;
 666                         break;
 667 #ifdef MACOSX
 668                     case OGLC_VENDOR_ATI:
 669                         // see 8024461
 670                         viaTexture = JNI_TRUE;
 671                         break;
 672 #endif
 673                     default:
 674                         // just use the glDrawPixels() codepath
 675                         viaTexture = JNI_FALSE;
 676                         break;
 677                     }
 678                 }
 679 
 680                 if (viaTexture) {
 681                     OGLBlitToSurfaceViaTexture(oglc, &srcInfo, &pf, NULL,
 682                                                JNI_TRUE, hint,
 683                                                sx1, sy1, sx2, sy2,
 684                                                dx1, dy1, dx2, dy2);
 685                 } else {
 686                     OGLBlitSwToSurface(oglc, &srcInfo, &pf,
 687                                        sx1, sy1, sx2, sy2,
 688                                        dx1, dy1, dx2, dy2);
 689                 }
 690             }
 691 
 692             j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 693             j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
 694             j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 695             j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 696         }
 697         SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
 698     }
 699     SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
 700 }
 701 
 702 /**
 703  * Specialized blit method for copying a native OpenGL "Surface" (pbuffer,
 704  * window, etc.) to a system memory ("Sw") surface.
 705  */
 706 void
 707 OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc,
 708                              jlong pSrcOps, jlong pDstOps, jint dsttype,
 709                              jint srcx, jint srcy, jint dstx, jint dsty,
 710                              jint width, jint height)
 711 {
 712     OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
 713     SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);
 714     SurfaceDataRasInfo srcInfo, dstInfo;
 715     OGLPixelFormat pf = PixelFormats[dsttype];
 716 
 717     J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_SurfaceToSwBlit");
 718 
 719     if (width <= 0 || height <= 0) {
 720         J2dTraceLn(J2D_TRACE_WARNING,
 721             "OGLBlitLoops_SurfaceToSwBlit: dimensions are non-positive");
 722         return;
 723     }
 724 
 725     RETURN_IF_NULL(srcOps);
 726     RETURN_IF_NULL(dstOps);
 727     RETURN_IF_NULL(oglc);
 728     RESET_PREVIOUS_OP();
 729 
 730     srcInfo.bounds.x1 = srcx;
 731     srcInfo.bounds.y1 = srcy;
 732     srcInfo.bounds.x2 = srcx + width;
 733     srcInfo.bounds.y2 = srcy + height;
 734     dstInfo.bounds.x1 = dstx;
 735     dstInfo.bounds.y1 = dsty;
 736     dstInfo.bounds.x2 = dstx + width;
 737     dstInfo.bounds.y2 = dsty + height;
 738 
 739     if (dstOps->Lock(env, dstOps, &dstInfo, SD_LOCK_WRITE) != SD_SUCCESS) {
 740         J2dTraceLn(J2D_TRACE_WARNING,
 741             "OGLBlitLoops_SurfaceToSwBlit: could not acquire dst lock");
 742         return;
 743     }
 744 
 745     SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
 746                                     0, 0, srcOps->width, srcOps->height);
 747     SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
 748                                     srcx - dstx, srcy - dsty);
 749 
 750     if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
 751         srcInfo.bounds.y2 > srcInfo.bounds.y1)
 752     {
 753         dstOps->GetRasInfo(env, dstOps, &dstInfo);
 754         if (dstInfo.rasBase) {
 755             void *pDst = dstInfo.rasBase;
 756             void* tempRow;
 757 
 758             srcx = srcInfo.bounds.x1;
 759             srcy = srcInfo.bounds.y1;
 760             dstx = dstInfo.bounds.x1;
 761             dsty = dstInfo.bounds.y1;
 762             width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
 763             height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
 764 
 765             j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, dstx);
 766             j2d_glPixelStorei(GL_PACK_ROW_LENGTH,
 767                               dstInfo.scanStride / dstInfo.pixelStride);
 768             j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);
 769 #ifdef MACOSX
 770             if (srcOps->isOpaque) {
 771                 // For some reason Apple's OpenGL implementation will
 772                 // read back zero values from the alpha channel of an
 773                 // opaque surface when using glReadPixels(), so here we
 774                 // force the resulting pixels to be fully opaque.
 775                 j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0);
 776             }
 777 #endif
 778 
 779             J2dTraceLn4(J2D_TRACE_VERBOSE, "  sx=%d sy=%d w=%d h=%d",
 780                         srcx, srcy, width, height);
 781             J2dTraceLn2(J2D_TRACE_VERBOSE, "  dx=%d dy=%d",
 782                         dstx, dsty);
 783 
 784             srcx = srcOps->xOffset + srcx;
 785             
 786             // Note that glReadPixels() is extremely slow!
 787             // So we try to call it only once and flip the image using memcpy.
 788             if (tempRow = malloc(dstInfo.scanStride)) {
 789                 // fast path
 790                 jint i;
 791                 const jint stride = dstInfo.scanStride;
 792                 srcy = srcOps->yOffset + srcy;
 793                 j2d_glReadPixels(srcx, srcy, width, height,
 794                                  pf.format, pf.type, pDst);
 795                 for (i = 0; i < height / 2; ++i) {
 796                     void * row1 = PtrAddBytes(pDst, (i * stride));
 797                     void * row2 = PtrAddBytes(pDst,(height - i - 1) * stride);
 798                     memcpy(tempRow, row1, stride);
 799                     memcpy(row1, row2, stride);
 800                     memcpy(row2, tempRow, stride);
 801                 }
 802                 free(tempRow);
 803             } else {
 804                 // slow path
 805                 // this accounts for lower-left origin of the source region
 806                 srcy = srcOps->yOffset + srcOps->height - (srcy + 1);
 807                 // we must read one scanline at a time because there is no way
 808                 // to read starting at the top-left corner of the source region
 809                 while (height > 0) {
 810                     j2d_glPixelStorei(GL_PACK_SKIP_ROWS, dsty);
 811                     j2d_glReadPixels(srcx, srcy, width, 1,
 812                                      pf.format, pf.type, pDst);
 813                     srcy--;
 814                     dsty++;
 815                     height--;
 816                 }
 817             }
 818 #ifdef MACOSX
 819             if (srcOps->isOpaque) {
 820                 j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0);
 821             }
 822 #endif
 823 
 824             j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
 825             j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0);
 826             j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
 827             j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);
 828         }
 829         SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
 830     }
 831     SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
 832 }
 833 
 834 void
 835 OGLBlitLoops_CopyArea(JNIEnv *env,
 836                       OGLContext *oglc, OGLSDOps *dstOps,
 837                       jint x, jint y, jint width, jint height,
 838                       jint dx, jint dy)
 839 {
 840     SurfaceDataBounds srcBounds, dstBounds;
 841 
 842     J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_CopyArea");
 843 
 844     RETURN_IF_NULL(oglc);
 845     RETURN_IF_NULL(dstOps);
 846     RESET_PREVIOUS_OP();
 847 
 848     J2dTraceLn4(J2D_TRACE_VERBOSE, "  x=%d y=%d w=%d h=%d",
 849                 x, y, width, height);
 850     J2dTraceLn2(J2D_TRACE_VERBOSE, "  dx=%d dy=%d",
 851                 dx, dy);
 852 
 853     srcBounds.x1 = x;
 854     srcBounds.y1 = y;
 855     srcBounds.x2 = srcBounds.x1 + width;
 856     srcBounds.y2 = srcBounds.y1 + height;
 857     dstBounds.x1 = x + dx;
 858     dstBounds.y1 = y + dy;
 859     dstBounds.x2 = dstBounds.x1 + width;
 860     dstBounds.y2 = dstBounds.y1 + height;
 861 
 862     // 6430601: manually clip src/dst parameters to work around
 863     // some bugs in Sun's and Apple's OpenGL implementations
 864     // (it's a good idea to restrict the source parameters anyway, since
 865     // passing out of range parameters to glCopyPixels() will result in
 866     // an OpenGL error)
 867     SurfaceData_IntersectBoundsXYXY(&srcBounds,
 868                                     0, 0, dstOps->width, dstOps->height);
 869     SurfaceData_IntersectBoundsXYXY(&dstBounds,
 870                                     0, 0, dstOps->width, dstOps->height);
 871     SurfaceData_IntersectBlitBounds(&dstBounds, &srcBounds, -dx, -dy);
 872 
 873     if (dstBounds.x1 < dstBounds.x2 && dstBounds.y1 < dstBounds.y2) {
 874 #ifdef MACOSX
 875         if (dstOps->isOpaque) {
 876             // For some reason Apple's OpenGL implementation will fail
 877             // to render glCopyPixels() when the src/dst rectangles are
 878             // overlapping and glColorMask() has disabled writes to the
 879             // alpha channel.  The workaround is to temporarily re-enable
 880             // the alpha channel during the glCopyPixels() operation.
 881             j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 882         }
 883 #endif
 884 
 885         OGLBlitSurfaceToSurface(oglc, dstOps, dstOps,
 886                                 srcBounds.x1, srcBounds.y1,
 887                                 srcBounds.x2, srcBounds.y2,
 888                                 dstBounds.x1, dstBounds.y1,
 889                                 dstBounds.x2, dstBounds.y2);
 890 #ifdef MACOSX
 891         if (dstOps->isOpaque) {
 892             j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
 893         }
 894 #endif
 895     }
 896 }
 897 
 898 #endif /* !HEADLESS */