[4/6] wined3d: Fix CreateFakeGLContext to work with a foreign context

Jan Zerebecki jan.wine at zerebecki.de
Thu Nov 23 12:58:41 CST 2006


I still think it would be cleaner to encapsulate the variables
for CreateFakeGLContext in a struct (as it was before) to prevent
using them in code that didn't call CreateFakeGLContext, but AJ
said he wants it this way.

If this patch is rejected from inclusion, please tell me why, as
I would have to ask anyway.

From: Jan Zerebecki <jan.wine at zerebecki.de>
Changelog:
wined3d: Fix CreateFakeGLContext to work with a foreign context
(one that wasn't created by CreateFakeGLContext). Fix all the
calling functions for the changed interface.
---

 dlls/wined3d/directx.c |  248 +++++++++++++++++++++++-------------------------
 1 files changed, 119 insertions(+), 129 deletions(-)

diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 778f6f7..8568121 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -28,6 +28,7 @@
 
 
 #include "config.h"
+#include <assert.h>
 #include "wined3d_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
@@ -66,105 +67,115 @@ DWORD *stateLookup[MAX_LOOKUPS];
 DWORD minMipLookup[WINED3DTEXF_ANISOTROPIC + 1][WINED3DTEXF_LINEAR + 1];
 
 
-typedef struct _WineD3D_GLContext {
-  GLXContext   glCtx;
-  Display*     display;
-  LONG         ref;
-} WineD3D_Context;
-
-
 /**
  * Note: GL seems to trap if GetDeviceCaps is called before any HWND's created
  * ie there is no GL Context - Get a default rendering context to enable the
  * function query some info from GL
  */
-static WineD3D_Context* WineD3D_CreateFakeGLContext(void) {
-    static WineD3D_Context ctx;
-    WineD3D_Context* ret = NULL;
-
-    if (glXGetCurrentContext() == NULL) {
-       BOOL         gotContext  = FALSE;
-       BOOL         created     = FALSE;
-       XVisualInfo  template;
-       HDC          device_context;
-       Visual*      visual;
-       BOOL         failed = FALSE;
-       int          num;
-       XVisualInfo *visInfo;
-       Drawable drawable;
-       XWindowAttributes win_attr;
-       TRACE_(d3d_caps)("Creating Fake GL Context\n");
-
-       drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");
-
-       /* Get the display */
-       device_context = GetDC(0);
-       ctx.display = get_display(device_context);
-       ReleaseDC(0, device_context);
-
-       /* Get the X visual */
-       ENTER_GL();
-       if (XGetWindowAttributes(ctx.display, drawable, &win_attr)) {
-           visual = win_attr.visual;
-       } else {
-           visual = DefaultVisual(ctx.display, DefaultScreen(ctx.display));
-       }
-       template.visualid = XVisualIDFromVisual(visual);
-       visInfo = XGetVisualInfo(ctx.display, VisualIDMask, &template, &num);
-       if (visInfo == NULL) {
-           LEAVE_GL();
-           WARN_(d3d_caps)("Error creating visual info for capabilities initialization\n");
-           failed = TRUE;
-       }
-
-       /* Create a GL context */
-       if (!failed) {
-           ctx.glCtx = glXCreateContext(ctx.display, visInfo, NULL, GL_TRUE);
-           XFree( visInfo );
-
-           if (ctx.glCtx == NULL) {
-               LEAVE_GL();
-               WARN_(d3d_caps)("Error creating default context for capabilities initialization\n");
-               failed = TRUE;
-           }
-       }
-
-       /* Make it the current GL context */
-       if (!failed && glXMakeCurrent(ctx.display, drawable, ctx.glCtx) == False) {
-           glXDestroyContext(ctx.display, ctx.glCtx);
-           LEAVE_GL();
-           WARN_(d3d_caps)("Error setting default context as current for capabilities initialization\n");
-           failed = TRUE;
-       }
-
-       /* It worked! Wow... */
-       if (!failed) {
-           gotContext = TRUE;
-           created = TRUE;
-           ret = &ctx;
-       } else {
-           ret = NULL;
-       }
-
-   } else {
-     if (ctx.ref > 0) ret = &ctx;
-   }
-
-   if (NULL != ret) InterlockedIncrement(&ret->ref);
-   return ret;
+
+static int             wined3d_fake_gl_context_ref = 0;
+static BOOL            wined3d_fake_gl_context_foreign;
+static BOOL            wined3d_fake_gl_context_available = FALSE;
+static Display*        wined3d_fake_gl_context_display = NULL;
+
+static void WineD3D_ReleaseFakeGLContext(void) {
+    GLXContext glCtx;
+
+    if(!wined3d_fake_gl_context_available) {
+        TRACE_(d3d_caps)("context not available\n");
+        return;
+    }
+
+    glCtx = glXGetCurrentContext();
+
+    TRACE_(d3d_caps)("decrementing ref from %i\n", wined3d_fake_gl_context_ref);
+    if (0 == (--wined3d_fake_gl_context_ref) ) {
+        if(!wined3d_fake_gl_context_foreign && glCtx) {
+            TRACE_(d3d_caps)("destroying fake GL context\n");
+            glXMakeCurrent(wined3d_fake_gl_context_display, None, NULL);
+            glXDestroyContext(wined3d_fake_gl_context_display, glCtx);
+        }
+        LEAVE_GL();
+        wined3d_fake_gl_context_available = FALSE;
+    }
+    assert(wined3d_fake_gl_context_ref >= 0);
+
 }
 
-static void WineD3D_ReleaseFakeGLContext(WineD3D_Context* ctx) {
-    /* If we created a dummy context, throw it away */
-    if (NULL != ctx) {
-        if (0 == InterlockedDecrement(&ctx->ref)) {
-            glXMakeCurrent(ctx->display, None, NULL);
-            glXDestroyContext(ctx->display, ctx->glCtx);
-            ctx->display = NULL;
-            ctx->glCtx = NULL;
-            LEAVE_GL();
+static BOOL WineD3D_CreateFakeGLContext(void) {
+    XVisualInfo* visInfo;
+    GLXContext   glCtx;
+
+    TRACE_(d3d_caps)("getting context...\n");
+    if(wined3d_fake_gl_context_ref > 0) goto ret;
+    assert(0 == wined3d_fake_gl_context_ref);
+
+    wined3d_fake_gl_context_foreign = TRUE;
+
+    if(!wined3d_fake_gl_context_display) {
+        HDC        device_context = GetDC(0);
+
+        wined3d_fake_gl_context_display = get_display(device_context);
+        ReleaseDC(0, device_context);
+    }
+
+    ENTER_GL();
+
+    visInfo = NULL;
+    glCtx = glXGetCurrentContext();
+
+    if (!glCtx) {
+        Drawable     drawable;
+        XVisualInfo  template;
+        Visual*      visual;
+        int          num;
+        XWindowAttributes win_attr;
+
+        wined3d_fake_gl_context_foreign = FALSE;
+        drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");;
+
+        TRACE_(d3d_caps)("Creating Fake GL Context\n");
+
+        /* Get the X visual */
+        if (XGetWindowAttributes(wined3d_fake_gl_context_display, drawable, &win_attr)) {
+            visual = win_attr.visual;
+        } else {
+            visual = DefaultVisual(wined3d_fake_gl_context_display, DefaultScreen(wined3d_fake_gl_context_display));
+        }
+        template.visualid = XVisualIDFromVisual(visual);
+        visInfo = XGetVisualInfo(wined3d_fake_gl_context_display, VisualIDMask, &template, &num);
+        if (!visInfo) {
+            WARN_(d3d_caps)("Error creating visual info for capabilities initialization\n");
+            goto fail;
         }
+
+        /* Create a GL context */
+        glCtx = glXCreateContext(wined3d_fake_gl_context_display, visInfo, NULL, GL_TRUE);
+        if (!glCtx) {
+            WARN_(d3d_caps)("Error creating default context for capabilities initialization\n");
+            goto fail;
+        }
+
+        /* Make it the current GL context */
+        if (!glXMakeCurrent(wined3d_fake_gl_context_display, drawable, glCtx)) {
+            WARN_(d3d_caps)("Error setting default context as current for capabilities initialization\n");
+            goto fail;
+        }
+
+        XFree(visInfo);
+
     }
+
+  ret:
+    TRACE_(d3d_caps)("incrementing ref from %i\n", wined3d_fake_gl_context_ref);
+    wined3d_fake_gl_context_ref++;
+    wined3d_fake_gl_context_available = TRUE;
+    return TRUE;
+  fail:
+    if(visInfo) XFree(visInfo);
+    if(glCtx) glXDestroyContext(wined3d_fake_gl_context_display, glCtx);
+    LEAVE_GL();
+    return FALSE;
 }
 
 /**********************************************************
@@ -304,18 +315,14 @@ BOOL IWineD3DImpl_FillGLCaps(IWineD3D *i
     GLfloat     gl_floatv[2];
     Bool        test = 0;
     int         major, minor;
-    WineD3D_Context *fake_ctx = NULL;
-    BOOL        gotContext    = FALSE;
+    BOOL        return_value = TRUE;
     int         i;
 
     /* Make sure that we've got a context */
-    if (glXGetCurrentContext() == NULL) {
-        /* TODO: CreateFakeGLContext should really take a display as a parameter  */
-        fake_ctx = WineD3D_CreateFakeGLContext();
-        if (NULL != fake_ctx) gotContext = TRUE;
-    } else {
-        gotContext = TRUE;
-    }
+    /* TODO: CreateFakeGLContext should really take a display as a parameter  */
+    /* Only save the values obtained when a display is provided */
+    if (!WineD3D_CreateFakeGLContext() || wined3d_fake_gl_context_foreign)
+        return_value = FALSE;
 
     TRACE_(d3d_caps)("(%p, %p)\n", gl_info, display);
 
@@ -1013,15 +1020,9 @@ #undef USE_GL_FUNC
         }
     }
 
-    /* If we created a dummy context, throw it away */
-    if (NULL != fake_ctx) WineD3D_ReleaseFakeGLContext(fake_ctx);
 
-    /* Only save the values obtained when a display is provided */
-    if (fake_ctx == NULL) {
-        return TRUE;
-    } else {
-        return FALSE;
-    }
+    WineD3D_ReleaseFakeGLContext();
+    return return_value;
 }
 
 /**********************************************************
@@ -1292,11 +1293,8 @@ static HRESULT WINAPI IWineD3DImpl_GetAd
            reuse the values once we have a context which is valid. Values from
            a temporary context may differ from the final ones                 */
         if (!isGLInfoValid) {
-            WineD3D_Context *fake_ctx = NULL;
-            if (glXGetCurrentContext() == NULL) fake_ctx = WineD3D_CreateFakeGLContext();
             /* If we don't know the device settings, go query them now */
             isGLInfoValid = IWineD3DImpl_FillGLCaps(iface, IWineD3DImpl_GetAdapterDisplay(iface, Adapter));
-            if (fake_ctx != NULL) WineD3D_ReleaseFakeGLContext(fake_ctx);
         }
 
         /* If it worked, return the information requested */
@@ -1481,7 +1479,6 @@ static HRESULT WINAPI IWineD3DImpl_Check
                                                    WINED3DFORMAT DepthStencilFormat) {
     IWineD3DImpl *This = (IWineD3DImpl *)iface;
     HRESULT hr = WINED3DERR_NOTAVAILABLE;
-    WineD3D_Context* ctx = NULL;
     GLXFBConfig* cfgs = NULL;
     int nCfgs = 0;
     int it;
@@ -1497,18 +1494,14 @@ static HRESULT WINAPI IWineD3DImpl_Check
         TRACE("(%p) Failed: Atapter (%u) higher than supported adapters (%u) returning WINED3DERR_INVALIDCALL\n", This, Adapter, IWineD3D_GetAdapterCount(iface));
         return WINED3DERR_INVALIDCALL;
     }
-    /* TODO: use the real context if it's available */
-    ctx = WineD3D_CreateFakeGLContext();
-    if(NULL !=  ctx) {
-        cfgs = glXGetFBConfigs(ctx->display, DefaultScreen(ctx->display), &nCfgs);
-    } else {
-        TRACE_(d3d_caps)("(%p) : Unable to create a fake context at this time (there may already be an active context)\n", This);
-    }
 
-    if (NULL != cfgs) {
+    if(WineD3D_CreateFakeGLContext())
+        cfgs = glXGetFBConfigs(wined3d_fake_gl_context_display, DefaultScreen(wined3d_fake_gl_context_display), &nCfgs);
+
+    if (cfgs) {
         for (it = 0; it < nCfgs; ++it) {
-            if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(ctx->display, cfgs[it], RenderTargetFormat)) {
-                if (IWineD3DImpl_IsGLXFBConfigCompatibleWithDepthFmt(ctx->display, cfgs[it], DepthStencilFormat)) {
+            if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(wined3d_fake_gl_context_display, cfgs[it], RenderTargetFormat)) {
+                if (IWineD3DImpl_IsGLXFBConfigCompatibleWithDepthFmt(wined3d_fake_gl_context_display, cfgs[it], DepthStencilFormat)) {
                     hr = WINED3D_OK;
                     break ;
                 }
@@ -1521,8 +1514,7 @@ static HRESULT WINAPI IWineD3DImpl_Check
         hr = WINED3D_OK;
     }
 
-    if (ctx != NULL)
-        WineD3D_ReleaseFakeGLContext(ctx);
+    WineD3D_ReleaseFakeGLContext();
 
     if (hr != WINED3D_OK)
         TRACE_(d3d_caps)("Failed to match stencil format to device\n");
@@ -1570,7 +1562,6 @@ static HRESULT WINAPI IWineD3DImpl_Check
     int nCfgs = 0;
     int it;
     HRESULT hr = WINED3DERR_NOTAVAILABLE;
-    WineD3D_Context* ctx;
 
     TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, CheckType:(%x,%s), DispFmt:(%x,%s), BackBuf:(%x,%s), Win?%d): stub\n",
           This,
@@ -1585,18 +1576,17 @@ static HRESULT WINAPI IWineD3DImpl_Check
         return WINED3DERR_INVALIDCALL;
     }
 
-    ctx = WineD3D_CreateFakeGLContext();
-    if (NULL != ctx) {
-      cfgs = glXGetFBConfigs(ctx->display, DefaultScreen(ctx->display), &nCfgs);
+    if (WineD3D_CreateFakeGLContext()) {
+      cfgs = glXGetFBConfigs(wined3d_fake_gl_context_display, DefaultScreen(wined3d_fake_gl_context_display), &nCfgs);
       for (it = 0; it < nCfgs; ++it) {
-          if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(ctx->display, cfgs[it], DisplayFormat)) {
+          if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(wined3d_fake_gl_context_display, cfgs[it], DisplayFormat)) {
               hr = WINED3D_OK;
               TRACE_(d3d_caps)("OK\n");
               break ;
           }
       }
       if(cfgs) XFree(cfgs);
-      WineD3D_ReleaseFakeGLContext(ctx);
+      WineD3D_ReleaseFakeGLContext();
     }
 
     if(hr != WINED3D_OK)



More information about the wine-patches mailing list