コード例 #1
0
/**
 * Determines whether the WGL pipeline can be used for a given GraphicsConfig
 * provided its screen number and visual ID.  If the minimum requirements are
 * met, the native WGLGraphicsConfigInfo structure is initialized for this
 * GraphicsConfig with the necessary information (pixel format, etc.)
 * and a pointer to this structure is returned as a jlong.  If
 * initialization fails at any point, zero is returned, indicating that WGL
 * cannot be used for this GraphicsConfig (we should fallback on the existing
 * DX pipeline).
 */
JNIEXPORT jlong JNICALL
Java_sun_java2d_opengl_WGLGraphicsConfig_getWGLConfigInfo(JNIEnv *env,
                                                          jclass wglgc,
                                                          jint screennum,
                                                          jint pixfmt)
{
    OGLContext *oglc;
    PIXELFORMATDESCRIPTOR pfd;
    HWND hwnd;
    HDC hdc;
    HGLRC context;
    HPBUFFERARB scratch;
    HDC scratchDC;
    WGLGraphicsConfigInfo *wglinfo;
    const unsigned char *versionstr;
    const char *extstr;
    jint caps = CAPS_EMPTY;
    int attrKeys[] = { WGL_DOUBLE_BUFFER_ARB, WGL_ALPHA_BITS_ARB };
    int attrVals[2];

    J2dRlsTraceLn(J2D_TRACE_INFO, "WGLGraphicsConfig_getWGLConfigInfo");

    // initialize GL/WGL extension functions
    if (!WGLGC_InitExtFuncs(screennum)) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLGraphicsConfig_getWGLConfigInfo: could not init ext funcs");
        return 0L;
    }

    // create a scratch window
    hwnd = WGLGC_CreateScratchWindow(screennum);
    if (hwnd == 0) {
        return 0L;
    }

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

    if (pixfmt == 0) {
        // find an appropriate pixel format
        pixfmt = WGLGC_GetPixelFormatForDC(hdc);
        if (pixfmt == 0) {
            J2dRlsTraceLn(J2D_TRACE_ERROR,
                "WGLGraphicsConfig_getWGLConfigInfo: could not find appropriate pixfmt");
            ReleaseDC(hwnd, hdc);
            DestroyWindow(hwnd);
            return 0L;
        }
    }

    if (sharedContext == 0) {
        // create the one shared context
        sharedContext = WGLGC_CreateContext(screennum, pixfmt);
        if (sharedContext == 0) {
            J2dRlsTraceLn(J2D_TRACE_ERROR,
                "WGLGraphicsConfig_getWGLConfigInfo: could not create shared context");
            ReleaseDC(hwnd, hdc);
            DestroyWindow(hwnd);
            return 0L;
        }
    }

    // set the pixel format for the scratch window
    if (!SetPixelFormat(hdc, pixfmt, &pfd)) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLGraphicsconfig_getWGLConfigInfo: error setting pixel format");
        ReleaseDC(hwnd, hdc);
        DestroyWindow(hwnd);
        return 0L;
    }

    // create the HGLRC (context) for this WGLGraphicsConfig
    context = j2d_wglCreateContext(hdc);
    if (context == 0) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLGraphicsConfig_getWGLConfigInfo: could not create WGL context");
        ReleaseDC(hwnd, hdc);
        DestroyWindow(hwnd);
        return 0L;
    }

    // REMIND: when using wglShareLists, the two contexts must use an
    //         identical pixel format...
    if (!j2d_wglShareLists(sharedContext, context)) {
        J2dRlsTraceLn(J2D_TRACE_WARNING,
            "WGLGraphicsConfig_getWGLConfigInfo: unable to share lists");
    }

    // make the context current so that we can query the OpenGL version
    // and extension strings
    if (!j2d_wglMakeCurrent(hdc, context)) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLGraphicsConfig_getWGLConfigInfo: could not make temp context current");
        j2d_wglDeleteContext(context);
        ReleaseDC(hwnd, hdc);
        DestroyWindow(hwnd);
        return 0L;
    }

    // get version and extension strings
    versionstr = j2d_glGetString(GL_VERSION);
    extstr = j2d_wglGetExtensionsStringARB(hdc);
    OGLContext_GetExtensionInfo(env, &caps);

    J2dRlsTraceLn1(J2D_TRACE_INFO,
        "WGLGraphicsConfig_getWGLConfigInfo: OpenGL version=%s",
                   (versionstr == NULL) ? "null" : (char *)versionstr);

    if (!OGLContext_IsVersionSupported(versionstr)) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLGraphicsConfig_getWGLConfigInfo: OpenGL 1.2 is required");
        j2d_wglMakeCurrent(NULL, NULL);
        j2d_wglDeleteContext(context);
        ReleaseDC(hwnd, hdc);
        DestroyWindow(hwnd);
        return 0L;
    }

    // check for required WGL extensions
    if (!OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_pbuffer") ||
        !OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_make_current_read")||
        !OGLContext_IsExtensionAvailable(extstr, "WGL_ARB_pixel_format"))
    {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLGraphicsConfig_getWGLConfigInfo: required ext(s) unavailable");
        j2d_wglMakeCurrent(NULL, NULL);
        j2d_wglDeleteContext(context);
        ReleaseDC(hwnd, hdc);
        DestroyWindow(hwnd);
        return 0L;
    }

    // get config-specific capabilities
    j2d_wglGetPixelFormatAttribivARB(hdc, pixfmt, 0, 2, attrKeys, attrVals);
    if (attrVals[0]) {
        caps |= CAPS_DOUBLEBUFFERED;
    }
    if (attrVals[1] > 0) {
        caps |= CAPS_STORED_ALPHA;
    }

    // create the scratch pbuffer
    scratch = j2d_wglCreatePbufferARB(hdc, pixfmt, 1, 1, NULL);

    // destroy the temporary resources
    j2d_wglMakeCurrent(NULL, NULL);
    ReleaseDC(hwnd, hdc);
    DestroyWindow(hwnd);

    if (scratch == 0) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLGraphicsConfig_getWGLConfigInfo: could not create scratch surface");
        j2d_wglDeleteContext(context);
        return 0L;
    }

    // get the HDC for the scratch pbuffer
    scratchDC = j2d_wglGetPbufferDCARB(scratch);
    if (scratchDC == 0) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLGraphicsConfig_getWGLConfigInfo: could not get hdc for scratch surface");
        j2d_wglDeleteContext(context);
        j2d_wglDestroyPbufferARB(scratch);
        return 0L;
    }

    // initialize the OGLContext, which wraps the pixfmt and HGLRC (context)
    oglc = WGLGC_InitOGLContext(pixfmt, context, scratch, scratchDC, caps);
    if (oglc == NULL) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLGraphicsConfig_getWGLConfigInfo: could not create oglc");
        j2d_wglDeleteContext(context);
        j2d_wglReleasePbufferDCARB(scratch, scratchDC);
        j2d_wglDestroyPbufferARB(scratch);
        return 0L;
    }    

    J2dTraceLn(J2D_TRACE_VERBOSE,
        "WGLGraphicsConfig_getWGLConfigInfo: finished checking dependencies");

    // create the WGLGraphicsConfigInfo record for this config
    wglinfo = (WGLGraphicsConfigInfo *)malloc(sizeof(WGLGraphicsConfigInfo));
    if (wglinfo == NULL) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "WGLGraphicsConfig_getWGLConfigInfo: could not allocate memory for wglinfo");
        WGLGC_DestroyOGLContext(oglc);
        return 0L;
    }

    wglinfo->screen = screennum;
    wglinfo->pixfmt = pixfmt;
    wglinfo->context = oglc;

    return ptr_to_jlong(wglinfo);
}
コード例 #2
0
/**
 * Initializes a new OGLContext, which includes the native WGL context handle
 * and some other important information such as the associated pixel format.
 * If sharedctx is non-null, its texture objects will be shared with the newly
 * created HGLRC.  If useDisposer is JNI_TRUE, a new DisposerTarget
 * (with the current Java-level thread object as the referent) will be
 * created and enqueued in the Disposer, so that this OGLContext will be
 * disposed of properly when its associated thread exits.  Contexts that are
 * intended to remain for the lifetime of the app (such as the sharedContext)
 * should specify JNI_FALSE for useDisposer.
 */
OGLContext *
WGLGC_InitOGLContext(JNIEnv *env, WGLGraphicsConfigInfo *wglinfo,
                     jboolean useDisposer)
{
    OGLContext *oglc;
    WGLCtxInfo *ctxinfo;
    HGLRC context;
    static jboolean firstTime = JNI_TRUE;

    J2dTraceLn(J2D_TRACE_INFO, "in WGLGC_InitOGLContext");

    oglc = (OGLContext *)malloc(sizeof(OGLContext));
    if (oglc == NULL) {
        J2dTraceLn(J2D_TRACE_ERROR, "could not allocate memory for oglc");
        return NULL;
    }

    memset(oglc, 0, sizeof(OGLContext));

    ctxinfo = (WGLCtxInfo *)malloc(sizeof(WGLCtxInfo));
    if (ctxinfo == NULL) {
        J2dTraceLn(J2D_TRACE_ERROR, "could not allocate memory for ctxinfo");
        free(oglc);
        return NULL;
    }

    context = WGLGC_CreateContext(wglinfo->screen, wglinfo->pixfmt);
    if (context == 0) {
        J2dTraceLn(J2D_TRACE_ERROR, "could not create new WGL context");
        free(oglc);
        free(ctxinfo);
        return NULL;
    }

    // REMIND: when using wglShareLists, the two contexts must use an
    //         identical pixel format...
    if (sharedContext != NULL) {
        WGLCtxInfo *sharedCtxInfo = (WGLCtxInfo *)sharedContext->ctxInfo;
        if (!j2d_wglShareLists(sharedCtxInfo->context, context)) {
            J2dTraceLn(J2D_TRACE_WARNING, "unable to share lists");
        }
    }

    ctxinfo->context = context;
    ctxinfo->configInfo = wglinfo;
    oglc->ctxInfo = ctxinfo;
    oglc->extInfo = &wglinfo->extInfo;

    // initialize this value to 1.0f as it is sometimes used when uploading
    // textures (see OGLBlitLoops_Blit()), and in the case of the shared
    // context, we skip the InitComposite() step that would otherwise
    // initialize the oglc->extraAlpha value...
    oglc->extraAlpha = 1.0f;

    /**
     * REMIND: The following is a total hack.  The first time we enter
     * this method, we must be on the main thread attempting to initialize
     * the default GraphicsConfig.  Each time we enter this method, we would
     * like to upcall to the static EventQueue.isDispatchThread() method.
     * But the first time we call that static method, we may end up implicitly
     * loading WToolkit, which will also attempt to call getDefaultConfig().
     * But since we still haven't fully initialized the default config, we
     * re-enter the getDefaultConfig() method (in the same thread), and then
     * come down through this same method.  JNI doesn't seem to like this
     * situation, and we end up with a seg fault.  This may be a JNI bug,
     * but for now we'll work around it, by avoiding the upcall the first
     * time around.  After that, we should be able to make this upcall without
     * the nasty side effects.
     */
    if (firstTime) {
        oglc->onJED = JNI_FALSE;
        firstTime = JNI_FALSE;
    } else {
        oglc->onJED = JNU_CallStaticMethodByName(env, NULL,
                                                 "java/awt/EventQueue",
                                                 "isDispatchThread",
                                                 "()Z").z;
    }

    if (useDisposer) {
        // initialize a new Disposer target (when the Java-level thread object
        // is about to go away, Disposer will invoke our native dispose
        // method, which destroys this OGLContext and its associated entries)
        jobject thread = JNU_CallStaticMethodByName(env, NULL,
                                                    "java/lang/Thread",
                                                    "currentThread",
                                                    "()Ljava/lang/Thread;").l;
        if (thread == NULL) {
            J2dTraceLn(J2D_TRACE_ERROR, "could not fetch current thread");
            j2d_wglDeleteContext(context);
            free(oglc);
            free(ctxinfo);
            return NULL;
        }

        Disposer_AddRecord(env, thread,
                           WGLGC_DisposeOGLContext, ptr_to_jlong(oglc));
    }

    return oglc;
}