alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (OGLBlitLoops.c)

This example Java source code file (OGLBlitLoops.c) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

gl_true, gldouble, glfloat, j2dtraceln, j2dtraceln4, macosx, oglblitloops_blit, oglblitloops_surfacetoswblit, oglc_blit_tile_size, oglpixelformat, oglsdops, return_if_null, surfacedataops, surfacedatarasinfo

The OGLBlitLoops.c Java example source code

/*
 * Copyright (c) 2003, 2013, 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
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#ifndef HEADLESS

#include <jni.h>
#include <jlong.h>

#include "SurfaceData.h"
#include "OGLBlitLoops.h"
#include "OGLRenderQueue.h"
#include "OGLSurfaceData.h"
#include "GraphicsPrimitiveMgr.h"

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
 * be used as both the source and destination, as is the case in a copyArea()
 * operation.  This method is invoked from OGLBlitLoops_IsoBlit() as well as
 * OGLBlitLoops_CopyArea().
 *
 * The standard glCopyPixels() mechanism is used to copy the source region
 * into the destination region.  If the regions have different dimensions,
 * the source will be scaled into the destination as appropriate (only
 * nearest neighbor filtering will be applied for simple scale operations).
 */
static void
OGLBlitSurfaceToSurface(OGLContext *oglc, OGLSDOps *srcOps, OGLSDOps *dstOps,
                        jint sx1, jint sy1, jint sx2, jint sy2,
                        jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
{
    GLfloat scalex, scaley;
    jint srcw = sx2 - sx1;
    jint srch = sy2 - sy1;

    scalex = ((GLfloat)(dx2-dx1)) / srcw;
    scaley = ((GLfloat)(dy2-dy1)) / srch;

    // the following lines account for the fact that glCopyPixels() copies a
    // region whose lower-left corner is at (x,y), but the source parameters
    // (sx1,sy1) we are given here point to the upper-left corner of the
    // source region... so here we play with the sy1 and dy1 parameters so
    // that they point to the lower-left corners of the regions...
    sx1 = srcOps->xOffset + sx1;
    sy1 = srcOps->yOffset + srcOps->height - sy2;
    dy1 = dy2;

    if (oglc->extraAlpha != 1.0f) {
        OGLContext_SetExtraAlpha(oglc->extraAlpha);
    }

    // see OGLBlitSwToSurface() for more info on the following two lines
    j2d_glRasterPos2i(0, 0);
    j2d_glBitmap(0, 0, 0, 0, (GLfloat)dx1, (GLfloat)-dy1, NULL);

    if (scalex == 1.0f && scaley == 1.0f) {
        j2d_glCopyPixels(sx1, sy1, srcw, srch, GL_COLOR);
    } else {
        j2d_glPixelZoom(scalex, scaley);
        j2d_glCopyPixels(sx1, sy1, srcw, srch, GL_COLOR);
        j2d_glPixelZoom(1.0f, 1.0f);
    }

    if (oglc->extraAlpha != 1.0f) {
        OGLContext_SetExtraAlpha(1.0f);
    }
}

/**
 * Inner loop used for copying a source OpenGL "Texture" to a destination
 * OpenGL "Surface".  This method is invoked from OGLBlitLoops_IsoBlit().
 *
 * This method will copy, scale, or transform the source texture into the
 * destination depending on the transform state, as established in
 * and OGLContext_SetTransform().  If the source texture is
 * transformed in any way when rendered into the destination, the filtering
 * method applied is determined by the hint parameter (can be GL_NEAREST or
 * GL_LINEAR).
 */
static void
OGLBlitTextureToSurface(OGLContext *oglc,
                        OGLSDOps *srcOps, OGLSDOps *dstOps,
                        jboolean rtt, jint hint,
                        jint sx1, jint sy1, jint sx2, jint sy2,
                        jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
{
    GLdouble tx1, ty1, tx2, ty2;

    if (rtt) {
        /*
         * The source is a render-to-texture surface.  These surfaces differ
         * from regular texture objects in that the bottom scanline (of
         * the actual image content) coincides with the top edge of the
         * texture object.  Therefore, we need to adjust the sy1/sy2
         * coordinates relative to the top scanline of the image content.
         *
         * In texture coordinates, the top-left corner of the image content
         * would be at:
         *     (0.0, (imgHeight/texHeight))
         * while the bottom-right corner corresponds to:
         *     ((imgWidth/texWidth), 0.0)
         */
        sy1 = srcOps->height - sy1;
        sy2 = srcOps->height - sy2;
    }

    if (srcOps->textureTarget == GL_TEXTURE_RECTANGLE_ARB) {
        // The GL_ARB_texture_rectangle extension requires that we specify
        // texture coordinates in the range [0,srcw] and [0,srch] instead of
        // [0,1] as we would normally do in the case of GL_TEXTURE_2D
        tx1 = (GLdouble)sx1;
        ty1 = (GLdouble)sy1;
        tx2 = (GLdouble)sx2;
        ty2 = (GLdouble)sy2;
    } else {
        // Otherwise we need to convert the source bounds into the range [0,1]
        tx1 = ((GLdouble)sx1) / srcOps->textureWidth;
        ty1 = ((GLdouble)sy1) / srcOps->textureHeight;
        tx2 = ((GLdouble)sx2) / srcOps->textureWidth;
        ty2 = ((GLdouble)sy2) / srcOps->textureHeight;
    }

    // Note that we call CHECK_PREVIOUS_OP(texTarget) in IsoBlit(), which
    // will call glEnable(texTarget) as necessary.
    j2d_glBindTexture(srcOps->textureTarget, srcOps->textureID);
    OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
    OGLSD_UPDATE_TEXTURE_FILTER(srcOps, hint);

    j2d_glBegin(GL_QUADS);
    j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx1, dy1);
    j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx2, dy1);
    j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx2, dy2);
    j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx1, dy2);
    j2d_glEnd();
}

/**
 * Inner loop used for copying a source system memory ("Sw") surface to a
 * destination OpenGL "Surface".  This method is invoked from
 * OGLBlitLoops_Blit().
 *
 * The standard glDrawPixels() mechanism is used to copy the source region
 * into the destination region.  If the regions have different
 * dimensions, the source will be scaled into the destination
 * as appropriate (only nearest neighbor filtering will be applied for simple
 * scale operations).
 */
static void
OGLBlitSwToSurface(OGLContext *oglc, SurfaceDataRasInfo *srcInfo,
                   OGLPixelFormat *pf,
                   jint sx1, jint sy1, jint sx2, jint sy2,
                   jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
{
    GLfloat scalex, scaley;

    scalex = ((GLfloat)(dx2-dx1)) / (sx2-sx1);
    scaley = ((GLfloat)(dy2-dy1)) / (sy2-sy1);

    if (oglc->extraAlpha != 1.0f) {
        OGLContext_SetExtraAlpha(oglc->extraAlpha);
    }
    if (!pf->hasAlpha) {
        // if the source surface does not have an alpha channel,
        // we need to ensure that the alpha values are forced to
        // the current extra alpha value (see OGLContext_SetExtraAlpha()
        // for more information)
        j2d_glPixelTransferf(GL_ALPHA_SCALE, 0.0f);
        j2d_glPixelTransferf(GL_ALPHA_BIAS, oglc->extraAlpha);
    }

    // This is a rather intriguing (yet totally valid) hack... If we were to
    // specify a raster position that is outside the surface bounds, the raster
    // position would be invalid and nothing would be rendered.  However, we
    // can use a widely known trick to move the raster position outside the
    // surface bounds while maintaining its status as valid.  The following
    // call to glBitmap() renders a no-op bitmap, but offsets the current
    // raster position from (0,0) to the desired location of (dx1,-dy1)...
    j2d_glRasterPos2i(0, 0);
    j2d_glBitmap(0, 0, 0, 0, (GLfloat)dx1, (GLfloat)-dy1, NULL);

    j2d_glPixelZoom(scalex, -scaley);

    // in case pixel stride is not a multiple of scanline stride the copy
    // has to be done line by line (see 6207877)
    if (srcInfo->scanStride % srcInfo->pixelStride != 0) {
        jint width = sx2-sx1;
        jint height = sy2-sy1;
        GLvoid *pSrc = srcInfo->rasBase;

        while (height > 0) {
            j2d_glDrawPixels(width, 1, pf->format, pf->type, pSrc);
            j2d_glBitmap(0, 0, 0, 0, (GLfloat)0, (GLfloat)-1, NULL);
            pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
            height--;
        }
    } else {
        j2d_glDrawPixels(sx2-sx1, sy2-sy1, pf->format, pf->type, srcInfo->rasBase);
    }

    j2d_glPixelZoom(1.0, 1.0);

    if (oglc->extraAlpha != 1.0f) {
        OGLContext_SetExtraAlpha(1.0f);
    }
    if (!pf->hasAlpha) {
        // restore scale/bias to their original values
        j2d_glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
        j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0f);
    }
}

/**
 * Inner loop used for copying a source system memory ("Sw") surface or
 * OpenGL "Surface" to a destination OpenGL "Surface", using an OpenGL texture
 * tile as an intermediate surface.  This method is invoked from
 * OGLBlitLoops_Blit() for "Sw" surfaces and OGLBlitLoops_IsoBlit() for
 * "Surface" surfaces.
 *
 * This method is used to transform the source surface into the destination.
 * Pixel rectangles cannot be arbitrarily transformed (without the
 * GL_EXT_pixel_transform extension, which is not supported on most modern
 * hardware).  However, texture mapped quads do respect the GL_MODELVIEW
 * transform matrix, so we use textures here to perform the transform
 * operation.  This method uses a tile-based approach in which a small
 * subregion of the source surface is copied into a cached texture tile.  The
 * texture tile is then mapped into the appropriate location in the
 * destination surface.
 *
 * REMIND: this only works well using GL_NEAREST for the filtering mode
 *         (GL_LINEAR causes visible stitching problems between tiles,
 *         but this can be fixed by making use of texture borders)
 */
static void
OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo,
                           OGLPixelFormat *pf, OGLSDOps *srcOps,
                           jboolean swsurface, jint hint,
                           jint sx1, jint sy1, jint sx2, jint sy2,
                           jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
{
    GLdouble tx1, ty1, tx2, ty2;
    GLdouble dx, dy, dw, dh, cdw, cdh;
    jint tw, th;
    jint sx, sy, sw, sh;
    GLint glhint = (hint == OGLSD_XFORM_BILINEAR) ? GL_LINEAR : GL_NEAREST;
    jboolean adjustAlpha = (pf != NULL && !pf->hasAlpha);
    jboolean slowPath;

    if (oglc->blitTextureID == 0) {
        if (!OGLContext_InitBlitTileTexture(oglc)) {
            J2dRlsTraceLn(J2D_TRACE_ERROR,
                "OGLBlitToSurfaceViaTexture: could not init blit tile");
            return;
        }
    }

    tx1 = 0.0f;
    ty1 = 0.0f;
    tw = OGLC_BLIT_TILE_SIZE;
    th = OGLC_BLIT_TILE_SIZE;
    cdw = (dx2-dx1) / (((GLdouble)(sx2-sx1)) / OGLC_BLIT_TILE_SIZE);
    cdh = (dy2-dy1) / (((GLdouble)(sy2-sy1)) / OGLC_BLIT_TILE_SIZE);

    j2d_glEnable(GL_TEXTURE_2D);
    j2d_glBindTexture(GL_TEXTURE_2D, oglc->blitTextureID);
    OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
    j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glhint);
    j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glhint);

    if (adjustAlpha) {
        // if the source surface does not have an alpha channel,
        // we need to ensure that the alpha values are forced to 1.0f
        j2d_glPixelTransferf(GL_ALPHA_SCALE, 0.0f);
        j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0f);
    }

    // in case pixel stride is not a multiple of scanline stride the copy
    // has to be done line by line (see 6207877)
    slowPath = srcInfo->scanStride % srcInfo->pixelStride != 0;

    for (sy = sy1, dy = dy1; sy < sy2; sy += th, dy += cdh) {
        sh = ((sy + th) > sy2) ? (sy2 - sy) : th;
        dh = ((dy + cdh) > dy2) ? (dy2 - dy) : cdh;

        for (sx = sx1, dx = dx1; sx < sx2; sx += tw, dx += cdw) {
            sw = ((sx + tw) > sx2) ? (sx2 - sx) : tw;
            dw = ((dx + cdw) > dx2) ? (dx2 - dx) : cdw;

            tx2 = ((GLdouble)sw) / tw;
            ty2 = ((GLdouble)sh) / th;

            if (swsurface) {
                if (slowPath) {
                    jint tmph = sh;
                    GLvoid *pSrc = PtrCoord(srcInfo->rasBase,
                                            sx, srcInfo->pixelStride,
                                            sy, srcInfo->scanStride);

                    while (tmph > 0) {
                        j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
                                            0, sh - tmph, sw, 1,
                                            pf->format, pf->type,
                                            pSrc);
                        pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
                        tmph--;
                    }
                } else {
                    j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
                    j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);

                    j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
                                        0, 0, sw, sh,
                                        pf->format, pf->type,
                                        srcInfo->rasBase);
                }

                // the texture image is "right side up", so we align the
                // upper-left texture corner with the upper-left quad corner
                j2d_glBegin(GL_QUADS);
                j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx, dy);
                j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx + dw, dy);
                j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx + dw, dy + dh);
                j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx, dy + dh);
                j2d_glEnd();
            } else {
                // this accounts for lower-left origin of the source region
                jint newsx = srcOps->xOffset + sx;
                jint newsy = srcOps->yOffset + srcOps->height - (sy + sh);
                j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
                                        0, 0, newsx, newsy, sw, sh);

                // the texture image is "upside down" after the last step, so
                // we align the bottom-left texture corner with the upper-left
                // quad corner (and vice versa) to effectively flip the
                // texture image
                j2d_glBegin(GL_QUADS);
                j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx, dy);
                j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx + dw, dy);
                j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx + dw, dy + dh);
                j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx, dy + dh);
                j2d_glEnd();
            }
        }
    }

    if (adjustAlpha) {
        // restore scale/bias to their original values
        j2d_glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
        j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0f);
    }

    j2d_glDisable(GL_TEXTURE_2D);
}

/**
 * Inner loop used for copying a source system memory ("Sw") surface to a
 * destination OpenGL "Texture".  This method is invoked from
 * OGLBlitLoops_Blit().
 *
 * The source surface is effectively loaded into the OpenGL texture object,
 * which must have already been initialized by OGLSD_initTexture().  Note
 * that this method is only capable of copying the source surface into the
 * destination surface (i.e. no scaling or general transform is allowed).
 * This restriction should not be an issue as this method is only used
 * currently to cache a static system memory image into an OpenGL texture in
 * a hidden-acceleration situation.
 */
static void
OGLBlitSwToTexture(SurfaceDataRasInfo *srcInfo, OGLPixelFormat *pf,
                   OGLSDOps *dstOps,
                   jint dx1, jint dy1, jint dx2, jint dy2)
{
    jboolean adjustAlpha = (pf != NULL && !pf->hasAlpha);
    j2d_glBindTexture(dstOps->textureTarget, dstOps->textureID);

    if (adjustAlpha) {
        // if the source surface does not have an alpha channel,
        // we need to ensure that the alpha values are forced to 1.0f
        j2d_glPixelTransferf(GL_ALPHA_SCALE, 0.0f);
        j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0f);
    }

    // in case pixel stride is not a multiple of scanline stride the copy
    // has to be done line by line (see 6207877)
    if (srcInfo->scanStride % srcInfo->pixelStride != 0) {
        jint width = dx2 - dx1;
        jint height = dy2 - dy1;
        GLvoid *pSrc = srcInfo->rasBase;

        while (height > 0) {
            j2d_glTexSubImage2D(dstOps->textureTarget, 0,
                                dx1, dy2 - height, width, 1,
                                pf->format, pf->type, pSrc);
            pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
            height--;
        }
    } else {
        j2d_glTexSubImage2D(dstOps->textureTarget, 0,
                            dx1, dy1, dx2-dx1, dy2-dy1,
                            pf->format, pf->type, srcInfo->rasBase);
    }
    if (adjustAlpha) {
        // restore scale/bias to their original values
        j2d_glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
        j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0f);
    }
}

/**
 * General blit method for copying a native OpenGL surface (of type "Surface"
 * or "Texture") to another OpenGL "Surface".  If texture is JNI_TRUE, this
 * method will invoke the Texture->Surface inner loop; otherwise, one of the
 * Surface->Surface inner loops will be invoked, depending on the transform
 * state.
 *
 * REMIND: we can trick these blit methods into doing XOR simply by passing
 *         in the (pixel ^ xorpixel) as the pixel value and preceding the
 *         blit with a fillrect...
 */
void
OGLBlitLoops_IsoBlit(JNIEnv *env,
                     OGLContext *oglc, jlong pSrcOps, jlong pDstOps,
                     jboolean xform, jint hint,
                     jboolean texture, jboolean rtt,
                     jint sx1, jint sy1, jint sx2, jint sy2,
                     jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
{
    OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
    OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDstOps);
    SurfaceDataRasInfo srcInfo;
    jint sw    = sx2 - sx1;
    jint sh    = sy2 - sy1;
    jdouble dw = dx2 - dx1;
    jdouble dh = dy2 - dy1;

    J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_IsoBlit");

    if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) {
        J2dTraceLn(J2D_TRACE_WARNING,
                   "OGLBlitLoops_IsoBlit: invalid dimensions");
        return;
    }

    RETURN_IF_NULL(srcOps);
    RETURN_IF_NULL(dstOps);
    RETURN_IF_NULL(oglc);

    srcInfo.bounds.x1 = sx1;
    srcInfo.bounds.y1 = sy1;
    srcInfo.bounds.x2 = sx2;
    srcInfo.bounds.y2 = sy2;

    SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
                                    0, 0, srcOps->width, srcOps->height);

    if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
        srcInfo.bounds.y2 > srcInfo.bounds.y1)
    {
        if (srcInfo.bounds.x1 != sx1) {
            dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
            sx1 = srcInfo.bounds.x1;
        }
        if (srcInfo.bounds.y1 != sy1) {
            dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
            sy1 = srcInfo.bounds.y1;
        }
        if (srcInfo.bounds.x2 != sx2) {
            dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
            sx2 = srcInfo.bounds.x2;
        }
        if (srcInfo.bounds.y2 != sy2) {
            dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
            sy2 = srcInfo.bounds.y2;
        }

        J2dTraceLn2(J2D_TRACE_VERBOSE, "  texture=%d hint=%d", texture, hint);
        J2dTraceLn4(J2D_TRACE_VERBOSE, "  sx1=%d sy1=%d sx2=%d sy2=%d",
                    sx1, sy1, sx2, sy2);
        J2dTraceLn4(J2D_TRACE_VERBOSE, "  dx1=%f dy1=%f dx2=%f dy2=%f",
                    dx1, dy1, dx2, dy2);

        if (texture) {
            GLint glhint = (hint == OGLSD_XFORM_BILINEAR) ? GL_LINEAR :
                                                            GL_NEAREST;
            CHECK_PREVIOUS_OP(srcOps->textureTarget);
            OGLBlitTextureToSurface(oglc, srcOps, dstOps, rtt, glhint,
                                    sx1, sy1, sx2, sy2,
                                    dx1, dy1, dx2, dy2);
        } else {
            jboolean viaTexture;
            if (xform) {
                // we must use the via-texture codepath when there is a xform
                viaTexture = JNI_TRUE;
            } else {
                // look at the vendor to see which codepath is faster
                // (this has been empirically determined; see 5020009)
                switch (OGLC_GET_VENDOR(oglc)) {
                case OGLC_VENDOR_NVIDIA:
                    // the via-texture codepath tends to be faster when
                    // there is either a simple scale OR an extra alpha
                    viaTexture =
                        (sx2-sx1) != (jint)(dx2-dx1) ||
                        (sy2-sy1) != (jint)(dy2-dy1) ||
                        oglc->extraAlpha != 1.0f;
                    break;

                case OGLC_VENDOR_ATI:
                    // the via-texture codepath tends to be faster only when
                    // there is an extra alpha involved (scaling or not)
                    viaTexture = (oglc->extraAlpha != 1.0f);
                    break;

                default:
                    // just use the glCopyPixels() codepath
                    viaTexture = JNI_FALSE;
                    break;
                }
            }

            RESET_PREVIOUS_OP();
            if (viaTexture) {
                OGLBlitToSurfaceViaTexture(oglc, &srcInfo, NULL, srcOps,
                                           JNI_FALSE, hint,
                                           sx1, sy1, sx2, sy2,
                                           dx1, dy1, dx2, dy2);
            } else {
                OGLBlitSurfaceToSurface(oglc, srcOps, dstOps,
                                        sx1, sy1, sx2, sy2,
                                        dx1, dy1, dx2, dy2);
            }
        }
    }
}

/**
 * General blit method for copying a system memory ("Sw") surface to a native
 * OpenGL surface (of type "Surface" or "Texture").  If texture is JNI_TRUE,
 * this method will invoke the Sw->Texture inner loop; otherwise, one of the
 * Sw->Surface inner loops will be invoked, depending on the transform state.
 */
void
OGLBlitLoops_Blit(JNIEnv *env,
                  OGLContext *oglc, jlong pSrcOps, jlong pDstOps,
                  jboolean xform, jint hint,
                  jint srctype, jboolean texture,
                  jint sx1, jint sy1, jint sx2, jint sy2,
                  jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
{
    SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);
    OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDstOps);
    SurfaceDataRasInfo srcInfo;
    OGLPixelFormat pf = PixelFormats[srctype];
    jint sw    = sx2 - sx1;
    jint sh    = sy2 - sy1;
    jdouble dw = dx2 - dx1;
    jdouble dh = dy2 - dy1;

    J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_Blit");

    if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0 || srctype < 0) {
        J2dTraceLn(J2D_TRACE_WARNING,
                   "OGLBlitLoops_Blit: invalid dimensions or srctype");
        return;
    }

    RETURN_IF_NULL(srcOps);
    RETURN_IF_NULL(dstOps);
    RETURN_IF_NULL(oglc);
    RESET_PREVIOUS_OP();

    srcInfo.bounds.x1 = sx1;
    srcInfo.bounds.y1 = sy1;
    srcInfo.bounds.x2 = sx2;
    srcInfo.bounds.y2 = sy2;

    if (srcOps->Lock(env, srcOps, &srcInfo, SD_LOCK_READ) != SD_SUCCESS) {
        J2dTraceLn(J2D_TRACE_WARNING,
                   "OGLBlitLoops_Blit: could not acquire lock");
        return;
    }

    if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
        srcInfo.bounds.y2 > srcInfo.bounds.y1)
    {
        srcOps->GetRasInfo(env, srcOps, &srcInfo);
        if (srcInfo.rasBase) {
            if (srcInfo.bounds.x1 != sx1) {
                dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
                sx1 = srcInfo.bounds.x1;
            }
            if (srcInfo.bounds.y1 != sy1) {
                dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
                sy1 = srcInfo.bounds.y1;
            }
            if (srcInfo.bounds.x2 != sx2) {
                dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
                sx2 = srcInfo.bounds.x2;
            }
            if (srcInfo.bounds.y2 != sy2) {
                dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
                sy2 = srcInfo.bounds.y2;
            }

            J2dTraceLn3(J2D_TRACE_VERBOSE, "  texture=%d srctype=%d hint=%d",
                        texture, srctype, hint);
            J2dTraceLn4(J2D_TRACE_VERBOSE, "  sx1=%d sy1=%d sx2=%d sy2=%d",
                        sx1, sy1, sx2, sy2);
            J2dTraceLn4(J2D_TRACE_VERBOSE, "  dx1=%f dy1=%f dx2=%f dy2=%f",
                        dx1, dy1, dx2, dy2);

            j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx1);
            j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy1);
            j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH,
                              srcInfo.scanStride / srcInfo.pixelStride);
            j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, pf.alignment);

            if (texture) {
                // These coordinates will always be integers since we
                // only ever do a straight copy from sw to texture.
                // Thus these casts are "safe" - no loss of precision.
                OGLBlitSwToTexture(&srcInfo, &pf, dstOps,
                                   (jint)dx1, (jint)dy1, (jint)dx2, (jint)dy2);
            } else {
                jboolean viaTexture;
                if (xform) {
                    // we must use the via-texture codepath when there
                    // is a xform
                    viaTexture = JNI_TRUE;
                } else {
                    // look at the vendor to see which codepath is faster
                    // (this has been empirically determined; see 5020009)
                    switch (OGLC_GET_VENDOR(oglc)) {
                    case OGLC_VENDOR_NVIDIA:
                        // the via-texture codepath tends to be faster when
                        // there is either a simple scale OR an extra alpha
                        viaTexture =
                            (sx2-sx1) != (jint)(dx2-dx1) ||
                            (sy2-sy1) != (jint)(dy2-dy1) ||
                            oglc->extraAlpha != 1.0f;
                        break;
#ifdef MACOSX
                    case OGLC_VENDOR_ATI:
                        // see 8024461
                        viaTexture = JNI_TRUE;
                        break;
#endif
                    default:
                        // just use the glDrawPixels() codepath
                        viaTexture = JNI_FALSE;
                        break;
                    }
                }

                if (viaTexture) {
                    OGLBlitToSurfaceViaTexture(oglc, &srcInfo, &pf, NULL,
                                               JNI_TRUE, hint,
                                               sx1, sy1, sx2, sy2,
                                               dx1, dy1, dx2, dy2);
                } else {
                    OGLBlitSwToSurface(oglc, &srcInfo, &pf,
                                       sx1, sy1, sx2, sy2,
                                       dx1, dy1, dx2, dy2);
                }
            }

            j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
            j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
            j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
            j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
        }
        SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
    }
    SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
}

/**
 * Specialized blit method for copying a native OpenGL "Surface" (pbuffer,
 * window, etc.) to a system memory ("Sw") surface.
 */
void
OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc,
                             jlong pSrcOps, jlong pDstOps, jint dsttype,
                             jint srcx, jint srcy, jint dstx, jint dsty,
                             jint width, jint height)
{
    OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
    SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);
    SurfaceDataRasInfo srcInfo, dstInfo;
    OGLPixelFormat pf = PixelFormats[dsttype];

    J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_SurfaceToSwBlit");

    if (width <= 0 || height <= 0) {
        J2dTraceLn(J2D_TRACE_WARNING,
            "OGLBlitLoops_SurfaceToSwBlit: dimensions are non-positive");
        return;
    }

    RETURN_IF_NULL(srcOps);
    RETURN_IF_NULL(dstOps);
    RETURN_IF_NULL(oglc);
    RESET_PREVIOUS_OP();

    srcInfo.bounds.x1 = srcx;
    srcInfo.bounds.y1 = srcy;
    srcInfo.bounds.x2 = srcx + width;
    srcInfo.bounds.y2 = srcy + height;
    dstInfo.bounds.x1 = dstx;
    dstInfo.bounds.y1 = dsty;
    dstInfo.bounds.x2 = dstx + width;
    dstInfo.bounds.y2 = dsty + height;

    if (dstOps->Lock(env, dstOps, &dstInfo, SD_LOCK_WRITE) != SD_SUCCESS) {
        J2dTraceLn(J2D_TRACE_WARNING,
            "OGLBlitLoops_SurfaceToSwBlit: could not acquire dst lock");
        return;
    }

    SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
                                    0, 0, srcOps->width, srcOps->height);
    SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
                                    srcx - dstx, srcy - dsty);

    if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
        srcInfo.bounds.y2 > srcInfo.bounds.y1)
    {
        dstOps->GetRasInfo(env, dstOps, &dstInfo);
        if (dstInfo.rasBase) {
            void *pDst = dstInfo.rasBase;

            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);
            j2d_glPixelStorei(GL_PACK_ROW_LENGTH,
                              dstInfo.scanStride / dstInfo.pixelStride);
            j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);
#ifdef MACOSX
            if (srcOps->isOpaque) {
                // For some reason Apple's OpenGL implementation will
                // read back zero values from the alpha channel of an
                // opaque surface when using glReadPixels(), so here we
                // force the resulting pixels to be fully opaque.
                j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0);
            }
#endif

            J2dTraceLn4(J2D_TRACE_VERBOSE, "  sx=%d sy=%d w=%d h=%d",
                        srcx, srcy, width, height);
            J2dTraceLn2(J2D_TRACE_VERBOSE, "  dx=%d dy=%d",
                        dstx, dsty);

            // this accounts for lower-left origin of the source region
            srcx = srcOps->xOffset + srcx;
            srcy = srcOps->yOffset + srcOps->height - (srcy + 1);

            // 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--;
            }

#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);
    }
    SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
}

void
OGLBlitLoops_CopyArea(JNIEnv *env,
                      OGLContext *oglc, OGLSDOps *dstOps,
                      jint x, jint y, jint width, jint height,
                      jint dx, jint dy)
{
    SurfaceDataBounds srcBounds, dstBounds;

    J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_CopyArea");

    RETURN_IF_NULL(oglc);
    RETURN_IF_NULL(dstOps);
    RESET_PREVIOUS_OP();

    J2dTraceLn4(J2D_TRACE_VERBOSE, "  x=%d y=%d w=%d h=%d",
                x, y, width, height);
    J2dTraceLn2(J2D_TRACE_VERBOSE, "  dx=%d dy=%d",
                dx, dy);

    srcBounds.x1 = x;
    srcBounds.y1 = y;
    srcBounds.x2 = srcBounds.x1 + width;
    srcBounds.y2 = srcBounds.y1 + height;
    dstBounds.x1 = x + dx;
    dstBounds.y1 = y + dy;
    dstBounds.x2 = dstBounds.x1 + width;
    dstBounds.y2 = dstBounds.y1 + height;

    // 6430601: manually clip src/dst parameters to work around
    // some bugs in Sun's and Apple's OpenGL implementations
    // (it's a good idea to restrict the source parameters anyway, since
    // passing out of range parameters to glCopyPixels() will result in
    // an OpenGL error)
    SurfaceData_IntersectBoundsXYXY(&srcBounds,
                                    0, 0, dstOps->width, dstOps->height);
    SurfaceData_IntersectBoundsXYXY(&dstBounds,
                                    0, 0, dstOps->width, dstOps->height);
    SurfaceData_IntersectBlitBounds(&dstBounds, &srcBounds, -dx, -dy);

    if (dstBounds.x1 < dstBounds.x2 && dstBounds.y1 < dstBounds.y2) {
#ifdef MACOSX
        if (dstOps->isOpaque) {
            // For some reason Apple's OpenGL implementation will fail
            // to render glCopyPixels() when the src/dst rectangles are
            // overlapping and glColorMask() has disabled writes to the
            // alpha channel.  The workaround is to temporarily re-enable
            // the alpha channel during the glCopyPixels() operation.
            j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
        }
#endif

        OGLBlitSurfaceToSurface(oglc, dstOps, dstOps,
                                srcBounds.x1, srcBounds.y1,
                                srcBounds.x2, srcBounds.y2,
                                dstBounds.x1, dstBounds.y1,
                                dstBounds.x2, dstBounds.y2);
#ifdef MACOSX
        if (dstOps->isOpaque) {
            j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
        }
#endif
    }
}

#endif /* !HEADLESS */

Other Java examples (source code examples)

Here is a short list of links related to this Java OGLBlitLoops.c source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.