wined3d: CreateFakeGLContext should also work when we have a context [3rd try]

Jan Zerebecki jan.wine at zerebecki.de
Fri Oct 6 06:07:32 CDT 2006


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

Patch changed according to feedback.

From: Jan Zerebecki <jan.wine at zerebecki.de>
Changelog:
wined3d: CreateFakeGLContext should also work when we have a context
from somewhere else. This fixes all the calling functions for the
changed behaviour.
---

 dlls/wined3d/directx.c         |  274 +++++++++++++++++++---------------------
 dlls/wined3d/wined3d_main.c    |    1 
 dlls/wined3d/wined3d_private.h |    3 
 include/wine/wined3d_gl.h      |    8 -
 4 files changed, 132 insertions(+), 154 deletions(-)

diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index d405f5f..2434739 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);
@@ -72,90 +73,90 @@ DWORD minMipLookup[WINED3DTEXF_ANISOTROP
  * 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 = { NULL, NULL, NULL, 0, 0 };
-    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;
-       XWindowAttributes win_attr;
-       TRACE_(d3d_caps)("Creating Fake GL Context\n");
-
-       ctx.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, ctx.drawable, &win_attr)) {
-           visual = win_attr.visual;
-       } else {
-           visual = DefaultVisual(ctx.display, DefaultScreen(ctx.display));
-       }
-       template.visualid = XVisualIDFromVisual(visual);
-       ctx.visInfo = XGetVisualInfo(ctx.display, VisualIDMask, &template, &num);
-       if (ctx.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, ctx.visInfo, NULL, GL_TRUE);
-
-           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, ctx.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;
+
+int             wined3d_fake_gl_context_ref;
+BOOL            wined3d_fake_gl_context_foreign;
+
+static Display* WineD3D_GetDisplay(void) {
+    HDC        device_context = GetDC(0);
+    Display*   display = get_display(device_context);
+    ReleaseDC(0, device_context);
+    return display;
+}
+
+static void WineD3D_ReleaseFakeGLContext(void) {
+    GLXContext glCtx = glXGetCurrentContext();
+    TRACE_(d3d_caps)("decrementing ref from %i\n", wined3d_fake_gl_context_ref);
+    if (0 == InterlockedDecrement(&wined3d_fake_gl_context_ref)) {
+        if(!wined3d_fake_gl_context_foreign && glCtx) {
+            TRACE_(d3d_caps)("destroying fake GL context\n");
+            glXMakeCurrent(WineD3D_GetDisplay(), None, NULL);
+            glXDestroyContext(WineD3D_GetDisplay(), glCtx);
+        }
+        LEAVE_GL();
+    }
+    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 void WineD3D_CreateFakeGLContext(void) {
+    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;
+    Display*   display = WineD3D_GetDisplay();
+    XVisualInfo* visInfo = NULL;
+    GLXContext   glCtx = glXGetCurrentContext();
+
+    ENTER_GL();
+
+    if (!glCtx) {
+        wined3d_fake_gl_context_foreign = FALSE;
+        Drawable     drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");;
+
+        XVisualInfo  template;
+        Visual*      visual;
+        int          num;
+        XWindowAttributes win_attr;
+
+        TRACE_(d3d_caps)("Creating Fake GL Context\n");
+
+        /* Get the X visual */
+        if (XGetWindowAttributes(display, drawable, &win_attr)) {
+            visual = win_attr.visual;
+        } else {
+            visual = DefaultVisual(display, DefaultScreen(display));
+        }
+        template.visualid = XVisualIDFromVisual(visual);
+        visInfo = XGetVisualInfo(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(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(display, drawable, glCtx)) {
+            WARN_(d3d_caps)("Error setting default context as current for capabilities initialization\n");
+            goto fail;
         }
+
+        XFree(visInfo);
+
     }
+
+  ret:
+    InterlockedIncrement(&wined3d_fake_gl_context_ref);
+    return;
+  fail:
+    if(visInfo) XFree(visInfo);
+    if(glCtx) glXDestroyContext(display, glCtx);
 }
 
 /**********************************************************
@@ -292,18 +293,12 @@ BOOL IWineD3DImpl_FillGLCaps(IWineD3D *i
     GLfloat     gl_floatv[2];
     Bool        test = 0;
     int         major, minor;
-    WineD3D_Context *fake_ctx = NULL;
-    BOOL        gotContext    = FALSE;
+    BOOL        ret = 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  */
+    WineD3D_CreateFakeGLContext();
 
     TRACE_(d3d_caps)("(%p, %p)\n", gl_info, display);
 
@@ -997,15 +992,12 @@ #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;
-    }
+    if (wined3d_fake_gl_context_foreign)
+        ret = FALSE;
+    WineD3D_ReleaseFakeGLContext();
+    return ret;
 }
 
 /**********************************************************
@@ -1275,11 +1267,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 */
@@ -1329,17 +1318,17 @@ static HRESULT WINAPI IWineD3DImpl_GetAd
     return WINED3D_OK;
 }
 
-static BOOL IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(WineD3D_Context* ctx, GLXFBConfig cfgs, WINED3DFORMAT Format) {
+static BOOL IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(GLXFBConfig cfgs, WINED3DFORMAT Format) {
 #if 0 /* This code performs a strict test between the format and the current X11  buffer depth, which may give the best performance */
   int gl_test;
   int rb, gb, bb, ab, type, buf_sz;
 
-  gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_RED_SIZE,   &rb);
-  gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_GREEN_SIZE, &gb);
-  gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_BLUE_SIZE,  &bb);
-  gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_ALPHA_SIZE, &ab);
-  gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_RENDER_TYPE, &type);
-  gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_BUFFER_SIZE, &buf_sz);
+  gl_test = glXGetFBConfigAttrib(WineD3D_GetDisplay(), cfgs, GLX_RED_SIZE,   &rb);
+  gl_test = glXGetFBConfigAttrib(WineD3D_GetDisplay(), cfgs, GLX_GREEN_SIZE, &gb);
+  gl_test = glXGetFBConfigAttrib(WineD3D_GetDisplay(), cfgs, GLX_BLUE_SIZE,  &bb);
+  gl_test = glXGetFBConfigAttrib(WineD3D_GetDisplay(), cfgs, GLX_ALPHA_SIZE, &ab);
+  gl_test = glXGetFBConfigAttrib(WineD3D_GetDisplay(), cfgs, GLX_RENDER_TYPE, &type);
+  gl_test = glXGetFBConfigAttrib(WineD3D_GetDisplay(), cfgs, GLX_BUFFER_SIZE, &buf_sz);
 
   switch (Format) {
   case WINED3DFMT_X8R8G8B8:
@@ -1399,13 +1388,13 @@ return FALSE;
 #endif
 }
 
-static BOOL IWineD3DImpl_IsGLXFBConfigCompatibleWithDepthFmt(WineD3D_Context* ctx, GLXFBConfig cfgs, WINED3DFORMAT Format) {
+static BOOL IWineD3DImpl_IsGLXFBConfigCompatibleWithDepthFmt(GLXFBConfig cfgs, WINED3DFORMAT Format) {
 #if 0/* This code performs a strict test between the format and the current X11  buffer depth, which may give the best performance */
   int gl_test;
   int db, sb;
 
-  gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_DEPTH_SIZE, &db);
-  gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_STENCIL_SIZE, &sb);
+  gl_test = glXGetFBConfigAttrib(WineD3D_GetDisplay(), cfgs, GLX_DEPTH_SIZE, &db);
+  gl_test = glXGetFBConfigAttrib(WineD3D_GetDisplay(), cfgs, GLX_STENCIL_SIZE, &sb);
 
   switch (Format) {
   case WINED3DFMT_D16:
@@ -1464,7 +1453,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;
@@ -1480,32 +1468,25 @@ 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) {
+    WineD3D_CreateFakeGLContext();
+    if(wined3d_fake_gl_context_ref > 0)
+        cfgs = glXGetFBConfigs(WineD3D_GetDisplay(), DefaultScreen(WineD3D_GetDisplay()), &nCfgs);
+
+    if (cfgs) {
         for (it = 0; it < nCfgs; ++it) {
-            if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(ctx, cfgs[it], RenderTargetFormat)) {
-                if (IWineD3DImpl_IsGLXFBConfigCompatibleWithDepthFmt(ctx, cfgs[it], DepthStencilFormat)) {
+            if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(cfgs[it], RenderTargetFormat)) {
+                if (IWineD3DImpl_IsGLXFBConfigCompatibleWithDepthFmt(cfgs[it], DepthStencilFormat)) {
                     hr = WINED3D_OK;
                     break ;
                 }
             }
         }
         XFree(cfgs);
-        cfgs = NULL;
-    } else {
-        /* If there's a current context then we cannot create a fake one so pass everything */
+    } else
         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\b");
@@ -1549,6 +1530,11 @@ static HRESULT WINAPI IWineD3DImpl_Check
                                             WINED3DFORMAT DisplayFormat, WINED3DFORMAT BackBufferFormat, BOOL Windowed) {
 
     IWineD3DImpl *This = (IWineD3DImpl *)iface;
+    GLXFBConfig* cfgs = NULL;
+    int nCfgs = 0;
+    int it;
+    HRESULT hr = WINED3DERR_NOTAVAILABLE;
+
     TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, CheckType:(%x,%s), DispFmt:(%x,%s), BackBuf:(%x,%s), Win?%d): stub\n",
           This,
           Adapter,
@@ -1558,32 +1544,28 @@ static HRESULT WINAPI IWineD3DImpl_Check
           Windowed);
 
     if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
+        WARN_(d3d_caps)("Adapter >= IWineD3D_GetAdapterCount(iface), returning WINED3DERR_INVALIDCALL\n");
         return WINED3DERR_INVALIDCALL;
     }
 
-    {
-      GLXFBConfig* cfgs = NULL;
-      int nCfgs = 0;
-      int it;
-      HRESULT hr = WINED3DERR_NOTAVAILABLE;
-
-      WineD3D_Context* ctx = WineD3D_CreateFakeGLContext();
-      if (NULL != ctx) {
-        cfgs = glXGetFBConfigs(ctx->display, DefaultScreen(ctx->display), &nCfgs);
-        for (it = 0; it < nCfgs; ++it) {
-            if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(ctx, cfgs[it], DisplayFormat)) {
-                hr = WINED3D_OK;
-                break ;
-            }
-        }
-        XFree(cfgs);
-
-        WineD3D_ReleaseFakeGLContext(ctx);
-        return hr;
+    WineD3D_CreateFakeGLContext();
+    if (wined3d_fake_gl_context_ref > 0) {
+      cfgs = glXGetFBConfigs(WineD3D_GetDisplay(), DefaultScreen(WineD3D_GetDisplay()), &nCfgs);
+      for (it = 0; it < nCfgs; ++it) {
+          if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(cfgs[it], DisplayFormat)) {
+              hr = WINED3D_OK;
+              TRACE_(d3d_caps)("OK\n");
+              break ;
+          }
       }
+      XFree(cfgs);
+      WineD3D_ReleaseFakeGLContext();
     }
 
-    return WINED3DERR_NOTAVAILABLE;
+    if(hr != WINED3D_OK)
+        TRACE_(d3d_caps)("returning WINED3DERR_NOTAVAILABLE\n");
+
+    return hr;
 }
 
 static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, 
diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c
index 872165a..746c2c8 100644
--- a/dlls/wined3d/wined3d_main.c
+++ b/dlls/wined3d/wined3d_main.c
@@ -107,6 +107,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, 
        HKEY appkey = 0;
        DWORD len;
        wined3d_settings.emulated_textureram = 64*1024*1024;
+       wined3d_fake_gl_context_ref = 0;
 
        DisableThreadLibraryCalls(hInstDLL);
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 659e2cf..48f64f0 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -184,6 +184,9 @@ #define ENTER_GL() wine_tsx11_lock_ptr()
 #define LEAVE_GL() wine_tsx11_unlock_ptr()
 #endif
 
+extern int             wined3d_fake_gl_context_ref;
+extern BOOL            wined3d_fake_gl_context_foreign;
+
 /*****************************************************************************
  * Defines
  */
diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h
index 1cc6409..dbe5214 100644
--- a/include/wine/wined3d_gl.h
+++ b/include/wine/wined3d_gl.h
@@ -1795,14 +1795,6 @@ typedef struct _WineD3D_GL_Info {
 } WineD3D_GL_Info;
 #undef USE_GL_FUNC
 
-typedef struct _WineD3D_GLContext {
-  GLXContext   glCtx; 
-  XVisualInfo* visInfo;
-  Display*     display;
-  Drawable     drawable;
-  LONG         ref;
-} WineD3D_Context;
-
 #endif /* HAVE_OPENGL */
 
 #endif /* __WINE_WINED3D_GL */



More information about the wine-patches mailing list