/**
 * Returns JNI_TRUE if the given extension name is available for the current
 * GraphicsConfig; JNI_FALSE otherwise.  An extension is considered available
 * if its identifier string is found amongst the space-delimited GL_EXTENSIONS
 * string.
 *
 * Adapted from the OpenGL Red Book, pg. 506.
 */
jboolean
OGLContext_IsExtensionAvailable(const char *extString, char *extName)
{
    jboolean ret = JNI_FALSE;
    char *p = (char *)extString;
    char *end;

    if (extString == NULL) {
        J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsExtensionAvailable");
        J2dRlsTraceLn(J2D_TRACE_ERROR,
                      "OGLContext_IsExtensionAvailable: extension string is null");
        return JNI_FALSE;
    }

    end = p + strlen(p);

    while (p < end) {
        size_t n = strcspn(p, " ");

        if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0)) {
            ret = JNI_TRUE;
            break;
        }

        p += (n + 1);
    }

    J2dRlsTraceLn2(J2D_TRACE_INFO,
                   "OGLContext_IsExtensionAvailable: %s=%s",
                   extName, ret ? "true" : "false");

    return ret;
}
Exemple #2
0
// static
HRESULT
D3DPipelineManager::CheckForBadHardware(DWORD vId, DWORD dId, LONGLONG version)
{
    DWORD vendorId, deviceId;
    UINT adapterInfo = 0;

    J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::CheckForBadHardware");

    while ((vendorId = badHardware[adapterInfo].VendorId) != 0x0000 &&
           (deviceId = badHardware[adapterInfo].DeviceId) != 0x0000)
    {
        if (vendorId == vId && (deviceId == dId || deviceId == ALL_DEVICEIDS)) {
            LONGLONG goodVersion = badHardware[adapterInfo].DriverVersion;
            USHORT osInfo = badHardware[adapterInfo].OsInfo;
            // the hardware check fails if:
            // - we have an entry for this OS and
            // - hardware is bad for all driver versions (NO_VERSION), or
            //   we have a driver version which is older than the
            //   minimum required for this OS
            if (D3DPPLM_OsVersionMatches(osInfo) &&
                (goodVersion == NO_VERSION || version < goodVersion))
            {
                J2dRlsTraceLn2(J2D_TRACE_ERROR,
                    "D3DPPLM::CheckForBadHardware: found matching "\
                    "hardware: VendorId=0x%04x DeviceId=0x%04x",
                    vendorId, deviceId);
                if (goodVersion != NO_VERSION) {
                    // this was a match by the driver version
                    LARGE_INTEGER li;
                    li.QuadPart = goodVersion;
                    J2dRlsTraceLn(J2D_TRACE_ERROR,
                                  "  bad driver found, device disabled");
                    J2dRlsTraceLn4(J2D_TRACE_ERROR,
                                   "  update your driver to at "\
                                   "least version %d.%d.%d.%d",
                                   HIWORD(li.HighPart), LOWORD(li.HighPart),
                                   HIWORD(li.LowPart),  LOWORD(li.LowPart));
                } else {
                    // this was a match by the device (no good driver for this
                    // device)
                    J2dRlsTraceLn(J2D_TRACE_ERROR,
                                  "D3DPPLM::CheckForBadHardware: bad hardware "\
                                  "found, device disabled");
                }
                if (!bNoHwCheck) {
                    return D3DERR_INVALIDDEVICE;
                }
                J2dRlsTraceLn(J2D_TRACE_WARNING, "  Warning: hw/driver match "\
                              "overridden (via J2D_D3D_NO_HWCHECK)");
            }
        }
        adapterInfo++;
    }

    return S_OK;
}
Exemple #3
0
/**
 * Returns the X11 VisualID that corresponds to the best GLXFBConfig for the
 * given screen.  If no valid visual could be found, this method returns zero.
 * Note that this method will attempt to initialize GLX (and all the
 * necessary function symbols) if it has not been already.  The AWT_LOCK
 * must be acquired before calling this method.
 */
VisualID
GLXGC_FindBestVisual(JNIEnv *env, jint screen)
{
    GLXFBConfig fbc;
    XVisualInfo *xvi;
    VisualID visualid;

    J2dRlsTraceLn1(J2D_TRACE_INFO, "GLXGC_FindBestVisual: scn=%d", screen);

    if (!GLXGC_IsGLXAvailable()) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "GLXGC_FindBestVisual: could not initialize GLX");
        return 0;
    }

    fbc = GLXGC_InitFBConfig(env, screen, 0);
    if (fbc == 0) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "GLXGC_FindBestVisual: could not find best visual");
        return 0;
    }

    xvi = j2d_glXGetVisualFromFBConfig(awt_display, fbc);
    if (xvi == NULL) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "GLXGC_FindBestVisual: could not get visual for fbconfig");
        return 0;
    }

    visualid = xvi->visualid;
    XFree(xvi);

    J2dRlsTraceLn2(J2D_TRACE_INFO,
        "GLXGC_FindBestVisual: chose 0x%x as the best visual for screen %d",
                   visualid, screen);

    return visualid;
}
/**
 * Compiles and links the given fragment shader program.  If
 * successful, this function returns a handle to the newly created shader
 * program; otherwise returns 0.
 */
GLhandleARB
OGLContext_CreateFragmentProgram(const char *fragmentShaderSource)
{
    GLhandleARB fragmentShader, fragmentProgram;
    GLint success;
    int infoLogLength = 0;

    J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateFragmentProgram");

    // create the shader object and compile the shader source code
    fragmentShader = j2d_glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
    j2d_glShaderSourceARB(fragmentShader, 1, &fragmentShaderSource, NULL);
    j2d_glCompileShaderARB(fragmentShader);
    j2d_glGetObjectParameterivARB(fragmentShader,
                                  GL_OBJECT_COMPILE_STATUS_ARB,
                                  &success);

    // print the compiler messages, if necessary
    j2d_glGetObjectParameterivARB(fragmentShader,
                                  GL_OBJECT_INFO_LOG_LENGTH_ARB,
                                  &infoLogLength);
    if (infoLogLength > 1) {
        char infoLog[1024];
        j2d_glGetInfoLogARB(fragmentShader, 1024, NULL, infoLog);
        J2dRlsTraceLn2(J2D_TRACE_WARNING,
                       "OGLContext_CreateFragmentProgram: compiler msg (%d):\n%s",
                       infoLogLength, infoLog);
    }

    if (!success) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
                      "OGLContext_CreateFragmentProgram: error compiling shader");
        j2d_glDeleteObjectARB(fragmentShader);
        return 0;
    }

    // create the program object and attach it to the shader
    fragmentProgram = j2d_glCreateProgramObjectARB();
    j2d_glAttachObjectARB(fragmentProgram, fragmentShader);

    // it is now safe to delete the shader object
    j2d_glDeleteObjectARB(fragmentShader);

    // link the program
    j2d_glLinkProgramARB(fragmentProgram);
    j2d_glGetObjectParameterivARB(fragmentProgram,
                                  GL_OBJECT_LINK_STATUS_ARB,
                                  &success);

    // print the linker messages, if necessary
    j2d_glGetObjectParameterivARB(fragmentProgram,
                                  GL_OBJECT_INFO_LOG_LENGTH_ARB,
                                  &infoLogLength);
    if (infoLogLength > 1) {
        char infoLog[1024];
        j2d_glGetInfoLogARB(fragmentProgram, 1024, NULL, infoLog);
        J2dRlsTraceLn2(J2D_TRACE_WARNING,
                       "OGLContext_CreateFragmentProgram: linker msg (%d):\n%s",
                       infoLogLength, infoLog);
    }

    if (!success) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
                      "OGLContext_CreateFragmentProgram: error linking shader");
        j2d_glDeleteObjectARB(fragmentProgram);
        return 0;
    }

    return fragmentProgram;
}
Exemple #5
0
HRESULT D3DPipelineManager::CheckAdaptersInfo()
{
    D3DADAPTER_IDENTIFIER9 aid;
    UINT failedAdaptersCount = 0;

    J2dRlsTraceLn(J2D_TRACE_INFO, "CheckAdaptersInfo");
    J2dRlsTraceLn(J2D_TRACE_INFO, "------------------");
    for (UINT Adapter = 0; Adapter < adapterCount; Adapter++) {

        if (FAILED(pd3d9->GetAdapterIdentifier(Adapter, 0, &aid))) {
            pAdapters[Adapter].state = CONTEXT_INIT_FAILED;
            failedAdaptersCount++;
            continue;
        }

        J2dRlsTraceLn1(J2D_TRACE_INFO, "Adapter Ordinal  : %d", Adapter);
        J2dRlsTraceLn1(J2D_TRACE_INFO, "Adapter Handle   : 0x%x",
                       pd3d9->GetAdapterMonitor(Adapter));
        J2dRlsTraceLn1(J2D_TRACE_INFO, "Description      : %s",
                       aid.Description);
        J2dRlsTraceLn2(J2D_TRACE_INFO, "GDI Name, Driver : %s, %s",
                       aid.DeviceName, aid.Driver);
        J2dRlsTraceLn1(J2D_TRACE_INFO, "Vendor Id        : 0x%04x",
                       aid.VendorId);
        J2dRlsTraceLn1(J2D_TRACE_INFO, "Device Id        : 0x%04x",
                       aid.DeviceId);
        J2dRlsTraceLn1(J2D_TRACE_INFO, "SubSys Id        : 0x%x",
                       aid.SubSysId);
        J2dRlsTraceLn4(J2D_TRACE_INFO, "Driver Version   : %d.%d.%d.%d",
                       HIWORD(aid.DriverVersion.HighPart),
                       LOWORD(aid.DriverVersion.HighPart),
                       HIWORD(aid.DriverVersion.LowPart),
                       LOWORD(aid.DriverVersion.LowPart));
        J2dRlsTrace3(J2D_TRACE_INFO,
                     "[I] GUID             : {%08X-%04X-%04X-",
                       aid.DeviceIdentifier.Data1,
                       aid.DeviceIdentifier.Data2,
                       aid.DeviceIdentifier.Data3);
        J2dRlsTrace4(J2D_TRACE_INFO, "%02X%02X-%02X%02X",
                       aid.DeviceIdentifier.Data4[0],
                       aid.DeviceIdentifier.Data4[1],
                       aid.DeviceIdentifier.Data4[2],
                       aid.DeviceIdentifier.Data4[3]);
        J2dRlsTrace4(J2D_TRACE_INFO, "%02X%02X%02X%02X}\n",
                       aid.DeviceIdentifier.Data4[4],
                       aid.DeviceIdentifier.Data4[5],
                       aid.DeviceIdentifier.Data4[6],
                       aid.DeviceIdentifier.Data4[7]);

        if (FAILED(CheckForBadHardware(aid.VendorId, aid.DeviceId,
                                       aid.DriverVersion.QuadPart)) ||
            FAILED(CheckDeviceCaps(Adapter))  ||
            FAILED(D3DEnabledOnAdapter(Adapter)))
        {
            pAdapters[Adapter].state = CONTEXT_INIT_FAILED;
            failedAdaptersCount++;
        }
        J2dRlsTraceLn(J2D_TRACE_INFO, "------------------");
    }

    if (failedAdaptersCount == adapterCount) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
                      "D3DPPLM::CheckAdaptersInfo: no suitable adapters found");
        return E_FAIL;
    }

    return S_OK;
}
Exemple #6
0
JNIEXPORT jboolean JNICALL
Java_sun_java2d_opengl_WGLSurfaceData_initPbuffer
    (JNIEnv *env, jobject wglsd,
     jlong pData, jlong pConfigInfo,
     jboolean isOpaque,
     jint width, jint height)
{
    int attrKeys[] = {
        WGL_MAX_PBUFFER_WIDTH_ARB,
        WGL_MAX_PBUFFER_HEIGHT_ARB,
    };
    int attrVals[2];
    int pbAttrList[] = { 0 };
    OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
    WGLGraphicsConfigInfo *wglInfo =
        (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
    WGLSDOps *wglsdo;
    HWND hwnd;
    HDC hdc, pbufferDC;
    HPBUFFERARB pbuffer;
    int maxWidth, maxHeight;
    int actualWidth, actualHeight;

    J2dTraceLn3(J2D_TRACE_INFO,
                "WGLSurfaceData_initPbuffer: w=%d h=%d opq=%d",
                width, height, isOpaque);

    if (oglsdo == NULL) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLSurfaceData_initPbuffer: ops are null");
        return JNI_FALSE;
    }

    wglsdo = (WGLSDOps *)oglsdo->privOps;
    if (wglsdo == NULL) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLSurfaceData_initPbuffer: wgl ops are null");
        return JNI_FALSE;
    }

    if (wglInfo == NULL) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLSurfaceData_initPbuffer: wgl config info is null");
        return JNI_FALSE;
    }

    // create a scratch window
    hwnd = WGLGC_CreateScratchWindow(wglInfo->screen);
    if (hwnd == 0) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLSurfaceData_initPbuffer: could not create scratch window");
        return JNI_FALSE;
    }

    // get the HDC for the scratch window
    hdc = GetDC(hwnd);
    if (hdc == 0) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLSurfaceData_initPbuffer: could not get dc for scratch window");
        DestroyWindow(hwnd);
        return JNI_FALSE;
    }

    // get the maximum allowable pbuffer dimensions
    j2d_wglGetPixelFormatAttribivARB(hdc, wglInfo->pixfmt, 0, 2,
                                     attrKeys, attrVals);
    maxWidth  = attrVals[0];
    maxHeight = attrVals[1];

    J2dTraceLn4(J2D_TRACE_VERBOSE,
                "  desired pbuffer dimensions: w=%d h=%d maxw=%d maxh=%d",
                width, height, maxWidth, maxHeight);

    // if either dimension is 0 or larger than the maximum, we cannot
    // allocate a pbuffer with the requested dimensions
    if (width  == 0 || width  > maxWidth ||
        height == 0 || height > maxHeight)
    {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLSurfaceData_initPbuffer: invalid dimensions");
        ReleaseDC(hwnd, hdc);
        DestroyWindow(hwnd);
        return JNI_FALSE;
    }

    pbuffer = j2d_wglCreatePbufferARB(hdc, wglInfo->pixfmt,
                                      width, height, pbAttrList);

    ReleaseDC(hwnd, hdc);
    DestroyWindow(hwnd);

    if (pbuffer == 0) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLSurfaceData_initPbuffer: could not create wgl pbuffer");
        return JNI_FALSE;
    }

    // note that we get the DC for the pbuffer at creation time, and then
    // release the DC when the pbuffer is disposed; the WGL_ARB_pbuffer
    // spec is vague about such things, but from past experience we know
    // this approach to be more robust than, for example, doing a
    // Get/ReleasePbufferDC() everytime we make a context current
    pbufferDC = j2d_wglGetPbufferDCARB(pbuffer);
    if (pbufferDC == 0) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLSurfaceData_initPbuffer: could not get dc for pbuffer");
        j2d_wglDestroyPbufferARB(pbuffer);
        return JNI_FALSE;
    }

    // make sure the actual dimensions match those that we requested
    j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_WIDTH_ARB, &actualWidth);
    j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_HEIGHT_ARB, &actualHeight);

    if (width != actualWidth || height != actualHeight) {
        J2dRlsTraceLn2(J2D_TRACE_ERROR,
            "WGLSurfaceData_initPbuffer: actual (w=%d h=%d) != requested",
                       actualWidth, actualHeight);
        j2d_wglReleasePbufferDCARB(pbuffer, pbufferDC);
        j2d_wglDestroyPbufferARB(pbuffer);
        return JNI_FALSE;
    }

    oglsdo->drawableType = OGLSD_PBUFFER;
    oglsdo->isOpaque = isOpaque;
    oglsdo->width = width;
    oglsdo->height = height;
    wglsdo->pbuffer = pbuffer;
    wglsdo->pbufferDC = pbufferDC;

    OGLSD_SetNativeDimensions(env, oglsdo, width, height);

    return JNI_TRUE;
}
Exemple #7
0
/**
 * Attempts to create a new GLXFBConfig for the requested screen and visual.
 * If visualid is 0, this method will iterate through all GLXFBConfigs (if
 * any) that match the requested attributes and will attempt to find an
 * fbconfig with a minimal combined depth+stencil buffer.  Note that we
 * currently only need depth capabilities (for shape clipping purposes), but
 * glXChooseFBConfig() will often return a list of fbconfigs with the largest
 * depth buffer (and stencil) sizes at the top of the list.  Therefore, we
 * scan through the whole list to find the most VRAM-efficient fbconfig.
 * If visualid is non-zero, the GLXFBConfig associated with the given visual
 * is chosen (assuming it meets the requested attributes).  If there are no
 * valid GLXFBConfigs available, this method returns 0.
 */
static GLXFBConfig
GLXGC_InitFBConfig(JNIEnv *env, jint screennum, VisualID visualid)
{
    GLXFBConfig *fbconfigs;
    GLXFBConfig chosenConfig = 0;
    int nconfs, i;
    int attrlist[] = {GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT,
                      GLX_RENDER_TYPE, GLX_RGBA_BIT,
                      GLX_CONFIG_CAVEAT, GLX_NONE, // avoid "slow" configs
                      GLX_DEPTH_SIZE, 16, // anything >= 16 will work for us
                      0};

    // this is the initial minimum value for the combined depth+stencil size
    // (we initialize it to some absurdly high value; realistic values will
    // be much less than this number)
    int minDepthPlusStencil = 512;

    J2dRlsTraceLn2(J2D_TRACE_INFO, "GLXGC_InitFBConfig: scn=%d vis=0x%x",
                   screennum, visualid);

    // find all fbconfigs for this screen with the provided attributes
    fbconfigs = j2d_glXChooseFBConfig(awt_display, screennum,
                                      attrlist, &nconfs);

    if ((fbconfigs == NULL) || (nconfs <= 0)) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "GLXGC_InitFBConfig: could not find any valid fbconfigs");
        return 0;
    }

    J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  candidate fbconfigs:");

    // iterate through the list of fbconfigs, looking for the one that matches
    // the requested VisualID and supports RGBA rendering as well as the
    // creation of windows and pbuffers
    for (i = 0; i < nconfs; i++) {
        XVisualInfo *xvi;
        VisualID fbvisualid;
        GLXFBConfig fbc = fbconfigs[i];

        // get VisualID from GLXFBConfig
        xvi = j2d_glXGetVisualFromFBConfig(awt_display, fbc);
        if (xvi == NULL) {
            continue;
        }
        fbvisualid = xvi->visualid;
        XFree(xvi);

        if (visualid == 0 || visualid == fbvisualid) {
            int dtype, rtype, depth, stencil, db, alpha, gamma;

            // get GLX-specific attributes from GLXFBConfig
            j2d_glXGetFBConfigAttrib(awt_display, fbc,
                                     GLX_DRAWABLE_TYPE, &dtype);
            j2d_glXGetFBConfigAttrib(awt_display, fbc,
                                     GLX_RENDER_TYPE, &rtype);
            j2d_glXGetFBConfigAttrib(awt_display, fbc,
                                     GLX_DEPTH_SIZE, &depth);
            j2d_glXGetFBConfigAttrib(awt_display, fbc,
                                     GLX_STENCIL_SIZE, &stencil);

            // these attributes don't affect our decision, but they are
            // interesting for trace logs, so we will query them anyway
            j2d_glXGetFBConfigAttrib(awt_display, fbc,
                                     GLX_DOUBLEBUFFER, &db);
            j2d_glXGetFBConfigAttrib(awt_display, fbc,
                                     GLX_ALPHA_SIZE, &alpha);

            J2dRlsTrace5(J2D_TRACE_VERBOSE,
                "[V]     id=0x%x db=%d alpha=%d depth=%d stencil=%d valid=",
                         fbvisualid, db, alpha, depth, stencil);

#ifdef __sparc
            /*
             * Sun's OpenGL implementation will always
             * return at least two GLXFBConfigs (visuals) from
             * glXChooseFBConfig().  The first will be a linear (gamma
             * corrected) visual; the second will have the same capabilities
             * as the first, except it will be a non-linear (non-gamma
             * corrected) visual, which is the one we want, otherwise
             * everything will look "washed out".  So we will reject any
             * visuals that have gamma values other than 1.0 (the value
             * returned by glXGetFBConfigAttrib() will be scaled
             * by 100, so 100 corresponds to a gamma value of 1.0, 220
             * corresponds to 2.2, and so on).
             */
            j2d_glXGetFBConfigAttrib(awt_display, fbc,
                                     GLX_GAMMA_VALUE_SUN, &gamma);
            if (gamma != 100) {
                J2dRlsTrace(J2D_TRACE_VERBOSE, "false (linear visual)\n");
                continue;
            }
#endif /* __sparc */

            if ((dtype & GLX_WINDOW_BIT) &&
                (dtype & GLX_PBUFFER_BIT) &&
                (rtype & GLX_RGBA_BIT) &&
                (depth >= 16))
            {
                if (visualid == 0) {
                    // when visualid == 0, we loop through all configs
                    // looking for an fbconfig that has the smallest combined
                    // depth+stencil size (this keeps VRAM usage to a minimum)
                    if ((depth + stencil) < minDepthPlusStencil) {
                        J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");
                        minDepthPlusStencil = depth + stencil;
                        chosenConfig = fbc;
                    } else {
                        J2dRlsTrace(J2D_TRACE_VERBOSE,
                                    "false (large depth)\n");
                    }
                    continue;
                } else {
                    // in this case, visualid == fbvisualid, which means
                    // we've found a valid fbconfig corresponding to the
                    // requested VisualID, so break out of the loop
                    J2dRlsTrace(J2D_TRACE_VERBOSE, "true\n");
                    chosenConfig = fbc;
                    break;
                }
            } else {
                J2dRlsTrace(J2D_TRACE_VERBOSE, "false (bad match)\n");
            }
        }
    }

    // free the list of fbconfigs
    XFree(fbconfigs);

    if (chosenConfig == 0) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "GLXGC_InitFBConfig: could not find an appropriate fbconfig");
        return 0;
    }

    return chosenConfig;
}
/**
 * Initializes an OpenGL texture object.
 *
 * If the isOpaque parameter is JNI_FALSE, then the texture will have a
 * full alpha channel; otherwise, the texture will be opaque (this can
 * help save VRAM when translucency is not needed).
 *
 * If the GL_ARB_texture_non_power_of_two extension is present (texNonPow2
 * is JNI_TRUE), the actual texture is allowed to have non-power-of-two
 * dimensions, and therefore width==textureWidth and height==textureHeight.
 *
 * Failing that, if the GL_ARB_texture_rectangle extension is present
 * (texRect is JNI_TRUE), the actual texture is allowed to have
 * non-power-of-two dimensions, except that instead of using the usual
 * GL_TEXTURE_2D target, we need to use the GL_TEXTURE_RECTANGLE_ARB target.
 * Note that the GL_REPEAT wrapping mode is not allowed with this target,
 * so if that mode is needed (e.g. as is the case in the TexturePaint code)
 * one should pass JNI_FALSE to avoid using this extension.  Also note that
 * when the texture target is GL_TEXTURE_RECTANGLE_ARB, texture coordinates
 * must be specified in the range [0,width] and [0,height] rather than
 * [0,1] as is the case with the usual GL_TEXTURE_2D target (so take care)!
 *
 * Otherwise, the actual texture must have power-of-two dimensions, and
 * therefore the textureWidth and textureHeight will be the next
 * power-of-two greater than (or equal to) the requested width and height.
 */
static jboolean
OGLSD_InitTextureObject(OGLSDOps *oglsdo,
                        jboolean isOpaque,
                        jboolean texNonPow2, jboolean texRect,
                        jint width, jint height)
{
    GLenum texTarget, texProxyTarget;
    GLint format = isOpaque ? GL_RGB : GL_RGBA;
    GLuint texID;
    GLsizei texWidth, texHeight, realWidth, realHeight;
    GLint texMax;

    J2dTraceLn4(J2D_TRACE_INFO,
                "OGLSD_InitTextureObject: w=%d h=%d opq=%d nonpow2=%d",
                width, height, isOpaque, texNonPow2);

    if (oglsdo == NULL) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
                      "OGLSD_InitTextureObject: ops are null");
        return JNI_FALSE;
    }

    if (texNonPow2) {
        // use non-pow2 dimensions with GL_TEXTURE_2D target
        j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texMax);
        texWidth = (width <= texMax) ? width : 0;
        texHeight = (height <= texMax) ? height : 0;
        texTarget = GL_TEXTURE_2D;
        texProxyTarget = GL_PROXY_TEXTURE_2D;
    } else if (texRect) {
        // use non-pow2 dimensions with GL_TEXTURE_RECTANGLE_ARB target
        j2d_glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &texMax);
        texWidth = (width <= texMax) ? width : 0;
        texHeight = (height <= texMax) ? height : 0;
        texTarget = GL_TEXTURE_RECTANGLE_ARB;
        texProxyTarget = GL_PROXY_TEXTURE_RECTANGLE_ARB;
    } else {
        // find the appropriate power-of-two dimensions
        j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texMax);
        texWidth = OGLSD_NextPowerOfTwo(width, texMax);
        texHeight = OGLSD_NextPowerOfTwo(height, texMax);
        texTarget = GL_TEXTURE_2D;
        texProxyTarget = GL_PROXY_TEXTURE_2D;
    }

    J2dTraceLn3(J2D_TRACE_VERBOSE,
                "  desired texture dimensions: w=%d h=%d max=%d",
                texWidth, texHeight, texMax);

    // if either dimension is 0, we cannot allocate a texture with the
    // requested dimensions
    if ((texWidth == 0) || (texHeight == 0)) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "OGLSD_InitTextureObject: texture dimensions too large");
        return JNI_FALSE;
    }

    // now use a proxy to determine whether we can create a texture with
    // the calculated power-of-two dimensions and the given internal format
    j2d_glTexImage2D(texProxyTarget, 0, format,
                     texWidth, texHeight, 0,
                     format, GL_UNSIGNED_BYTE, NULL);
    j2d_glGetTexLevelParameteriv(texProxyTarget, 0,
                                 GL_TEXTURE_WIDTH, &realWidth);
    j2d_glGetTexLevelParameteriv(texProxyTarget, 0,
                                 GL_TEXTURE_HEIGHT, &realHeight);

    // if the requested dimensions and proxy dimensions don't match,
    // we shouldn't attempt to create the texture
    if ((realWidth != texWidth) || (realHeight != texHeight)) {
        J2dRlsTraceLn2(J2D_TRACE_ERROR,
            "OGLSD_InitTextureObject: actual (w=%d h=%d) != requested",
                       realWidth, realHeight);
        return JNI_FALSE;
    }

    // initialize the texture with some dummy data (this allows us to create
    // a texture object once with 2^n dimensions, and then use
    // glTexSubImage2D() to provide further updates)
    j2d_glGenTextures(1, &texID);
    j2d_glBindTexture(texTarget, texID);
    j2d_glTexImage2D(texTarget, 0, format,
                     texWidth, texHeight, 0,
                     format, GL_UNSIGNED_BYTE, NULL);

    oglsdo->isOpaque = isOpaque;
    oglsdo->xOffset = 0;
    oglsdo->yOffset = 0;
    oglsdo->width = width;
    oglsdo->height = height;
    oglsdo->textureID = texID;
    oglsdo->textureWidth = texWidth;
    oglsdo->textureHeight = texHeight;
    oglsdo->textureTarget = texTarget;
    OGLSD_INIT_TEXTURE_FILTER(oglsdo, GL_NEAREST);
    OGLSD_RESET_TEXTURE_WRAP(texTarget);

    J2dTraceLn3(J2D_TRACE_VERBOSE, "  created texture: w=%d h=%d id=%d",
                width, height, texID);

    return JNI_TRUE;
}