[WINED3D] Pbuffer/ActiveRender cleanup #2

Ivan Gyurdiev ivg231 at gmail.com
Sun Sep 17 05:24:59 CDT 2006


This patch should be a no-op in functionality (mostly).
Reports of upside-down rendering caused by the last cleanup should be 
resolved here.

The patch is large, but all of it's related functionality.

Changelog:
===========
- break up functionality in ActiveRender into separate functions
    - change current device_reapply_stateblock() function to 
device_switch_render_context(), which is really what we're trying to do 
(that's why we reapply the stateblock). Move the glXMakeCurrent call here.
    - add function device_render_onscreen()

- break up pbuffer functionality in ActiveRender into separate 
functions. Split into:
      - device_pbuffer_find_context (previously FindGLContext)
      - device_pbuffer_init_context (previously "This really should be 
in FindGLContext")
      - device_pbuffer_render_offscreen (makes use of above two and 
device_switch_render_context())

- remove GL_VERSION_1_3 check
      - it's wrong, should be GLX_VERSION_1_3
      - my last cleanup moved code outside the ifdef by accident, and 
nobody has complained.
      - it's being replaced here with proper extension support: 
SGIX_PBUFFER, SGIX_FBCONFIG. It's been noted that ATI doesn't support 
this properly. Given the number of things ATI doesn't support properly 
(glXDestroyPbuffer?), I don't think ATI pbuffer support should be 
maintained - should use FBOs for ATI, until their drivers are fixed.

- rename render_to_texture to render_upside_down, and make sure to call 
it in the case of offscreen rendering where pbuffers are not supported [ 
see EndScene to see what makes the render flip necessary - it is not 
conditional on pbuffer_support ].
-------------- next part --------------
---
 dlls/wined3d/device.c          |  540 +++++++++++++++++++++-------------------
 dlls/wined3d/directx.c         |   27 ++
 dlls/wined3d/utils.c           |    4 
 dlls/wined3d/wined3d_private.h |    9 +
 include/wine/wined3d_gl.h      |   41 +++
 5 files changed, 360 insertions(+), 261 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 34026db..f9e23cf 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -7202,7 +7202,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl
 }
 
 
-#ifdef GL_VERSION_1_3
 /* Internal functions not in DirectX */
  /** TODO: move this off to the opengl context manager
  *(the swapchain doesn't need to know anything about offscreen rendering!)
@@ -7222,76 +7221,31 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     return WINED3D_OK;
 }
 
-/* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
-static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
-    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int i;
-    unsigned int width;
-    unsigned int height;
-    WINED3DFORMAT format;
-    WINED3DSURFACE_DESC surfaceDesc;
-    memset(&surfaceDesc, 0, sizeof(surfaceDesc));
-    surfaceDesc.Width  = &width;
-    surfaceDesc.Height = &height;
-    surfaceDesc.Format = &format;
-    IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
-    *context = NULL;
-    /* I need a get width/height function (and should do something with the format) */
-    for (i = 0; i < CONTEXT_CACHE; ++i) {
-        /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
-        ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
-        the pSurface can be set to 0 allowing it to be reused from cache **/
-        if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
-          && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
-            *context = &This->contextCache[i];
-            break;
-        }
-        if (This->contextCache[i].Width == 0) {
-            This->contextCache[i].pSurface = pSurface;
-            This->contextCache[i].Width    = width;
-            This->contextCache[i].Height   = height;
-            *context = &This->contextCache[i];
-            break;
-        }
-    }
-    if (i == CONTEXT_CACHE) {
-        int minUsage = 0x7FFFFFFF; /* MAX_INT */
-        glContext *dropContext = 0;
-        for (i = 0; i < CONTEXT_CACHE; i++) {
-            if (This->contextCache[i].usedcount < minUsage) {
-                dropContext = &This->contextCache[i];
-                minUsage = This->contextCache[i].usedcount;
-            }
-        }
-        /* clean up the context (this doesn't work for ATI at the moment */
-#if 0
-        glXDestroyContext(swapchain->display, dropContext->context);
-        glXDestroyPbuffer(swapchain->display, dropContext->drawable);
-#endif
-        FIXME("Leak\n");
-        dropContext->Width = 0;
-        dropContext->pSurface = pSurface;
-        *context = dropContext;
-    } else {
-        if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
-          for (i = 0; i < CONTEXT_CACHE; i++) {
-             This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
-          }
-        }
-    }
-    if (*context != NULL)
-        return WINED3D_OK;
-    else
-        return E_OUTOFMEMORY;
-}
-#endif
-
-/* Reapply the device stateblock */
-static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
+/**********************************************************
+ * Device (rendering) helper functions follow.
+ **********************************************************/
 
-    BOOL oldRecording;  
+/* Switch the rendering context for the current render target. */
+static void device_switch_render_context(
+    IWineD3DDeviceImpl* This,
+    IWineD3DSwapChain* currentSwapchain,
+    Display* display,
+    GLXDrawable drawable,
+    GLXContext context) {
+    
+    BOOL oldRecording;
     IWineD3DStateBlockImpl *oldUpdateStateBlock;
+    IWineD3DSwapChainImpl *currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
 
+    /* Change rendering context */
+    if (glXMakeCurrent(display, drawable, context) == False) {
+        ERR("Error in setting current context: context %p drawable %ld !\n", context, drawable);
+        return;
+    }
+
+    /* Clean the old render context */
+    IWineD3DDeviceImpl_CleanRender((IWineD3DDevice*) This, currentSwapchainImpl);
+ 
     /* Disable recording */
     oldUpdateStateBlock = This->updateStateBlock;
     oldRecording= This->isRecordingState;
@@ -7306,10 +7260,8 @@ static void device_reapply_stateblock(IW
     This->updateStateBlock = oldUpdateStateBlock;
 }
 
-/* Set the device to render to a texture, or not.
- * This involves changing renderUpsideDown */
-
-static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
+/* Set the device to render upside down */
+static void device_render_upside_down(IWineD3DDeviceImpl* This, BOOL upsideDown) {
 
     DWORD cullMode;
     BOOL oldRecording;
@@ -7323,7 +7275,7 @@ static void device_render_to_texture(IWi
 
     /* Set upside-down rendering, and update the cull mode */
     /* The surface must be rendered upside down to cancel the flip produced by glCopyTexImage */
-    This->renderUpsideDown = isTexture;
+    This->renderUpsideDown = upsideDown;
     This->last_was_rhw = FALSE;
     This->proj_valid = FALSE;
     IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
@@ -7334,15 +7286,52 @@ static void device_render_to_texture(IWi
     This->updateStateBlock = oldUpdateStateBlock;
 }
 
+static void device_render_onscreen(
+    IWineD3DDeviceImpl *This,
+    IWineD3DSwapChain *currentSwapchain,
+    IWineD3DSwapChain *renderSurfaceSwapchain,
+    IWineD3DSurface *renderSurface) {
+
+    IWineD3DSwapChainImpl* renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
+
+    BOOL backbuf = FALSE;
+    int i;
+
+    /* We also need to make sure that the lights &co are also in the context of the swapchains */
+    /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
+    for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
+        if(renderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
+            backbuf = TRUE;
+            break;
+        }
+    }
+    if (backbuf) {
+    } else {
+        /* This could be flagged so that some operations work directly with the front buffer */
+        FIXME("Attempting to set the  renderTarget to the frontBuffer\n");
+    }
+    
+    /* Change rendering context */
+    device_switch_render_context(This, currentSwapchain,
+        renderSurfaceSwapchainImpl->display,
+        renderSurfaceSwapchainImpl->win,
+        renderSurfaceSwapchainImpl->glCtx);
+    
+    return;
+}
+   
+/***********************************************************
+ * PBuffer helper functions follow
+ ***********************************************************/
+
 /* Returns an array of compatible FBconfig(s).
  * The array must be freed with XFree. Requires ENTER_GL() */
 
-static GLXFBConfig* device_find_fbconfigs(
+static GLXFBConfigSGIX* device_pbuffer_find_fbconfigs(
     IWineD3DDeviceImpl* This,
-    IWineD3DSwapChainImpl* implicitSwapchainImpl,
     IWineD3DSurface* RenderSurface) {
 
-    GLXFBConfig* cfgs = NULL;
+    GLXFBConfigSGIX* cfgs = NULL;
     int nCfgs = 0;
     int attribs[256];
     int nAttribs = 0;
@@ -7350,6 +7339,8 @@ static GLXFBConfig* device_find_fbconfig
     IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
     D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
     D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
+    IWineD3DSwapChain *implicitSwapchain = This->swapchains[0];
+    IWineD3DSwapChainImpl *implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
 
     /**TODO:
         if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off, 
@@ -7361,16 +7352,17 @@ #define PUSH2(att,value)  attribs[nAttri
 
     /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
 
-    PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
-    PUSH2(GLX_X_RENDERABLE,  TRUE);
+    PUSH2(GLX_DRAWABLE_TYPE_SGIX, GLX_PBUFFER_BIT);
+    PUSH2(GLX_X_RENDERABLE_SGIX,  TRUE);
     PUSH2(GLX_DOUBLEBUFFER,  TRUE);
     TRACE("calling makeglcfg\n");
     D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
     PUSH1(None);
     TRACE("calling chooseFGConfig\n");
-    cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
+    cfgs = GL_EXTCALL(glXChooseFBConfigSGIX(implicitSwapchainImpl->display,
                              DefaultScreen(implicitSwapchainImpl->display),
-                             attribs, &nCfgs);
+                             attribs, &nCfgs));
+
     if (cfgs == NULL) {
         /* OK we didn't find the exact config, so use any reasonable match */
         /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
@@ -7378,16 +7370,16 @@ #define PUSH2(att,value)  attribs[nAttri
         MESSAGE("Failed to find exact match, finding alternative but you may "
             "suffer performance issues, try changing xfree's depth to match the requested depth\n");
         nAttribs = 0;
-        PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
-        /* PUSH2(GLX_X_RENDERABLE,  TRUE); */
-        PUSH2(GLX_RENDER_TYPE,   GLX_RGBA_BIT);
+        PUSH2(GLX_DRAWABLE_TYPE_SGIX, GLX_PBUFFER_BIT_SGIX | GLX_WINDOW_BIT_SGIX);
+        /* PUSH2(GLX_X_RENDERABLE_SGIX,  TRUE); */
+        PUSH2(GLX_RENDER_TYPE_SGIX,   GLX_RGBA_BIT_SGIX);
         PUSH2(GLX_DOUBLEBUFFER, FALSE);
         TRACE("calling makeglcfg\n");
         D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
         PUSH1(None);
-        cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
+        cfgs = GL_EXTCALL(glXChooseFBConfigSGIX(implicitSwapchainImpl->display,
                                  DefaultScreen(implicitSwapchainImpl->display),
-                                 attribs, &nCfgs);
+                                 attribs, &nCfgs));
     }
                                                                                                                                                                       
     if (cfgs == NULL) {
@@ -7423,201 +7415,231 @@ #undef PUSH2
    return cfgs;
 }
 
-/** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
-* the functionality needs splitting up so that we don't do more than we should do.
-* this only seems to impact performance a little.
- ******************************/
+static HRESULT device_pbuffer_find_context(
+    IWineD3DDeviceImpl *This,
+    IWineD3DSurface *pSurface,
+    glContext **newContext) {
+    
+    int i;
+    unsigned int width;
+    unsigned int height;
+    WINED3DFORMAT format;
+    WINED3DSURFACE_DESC surfaceDesc;
+    glContext* context = NULL;
+    
+    /* Fetch some information about this surface */
+    memset(&surfaceDesc, 0, sizeof(surfaceDesc));
+    surfaceDesc.Width  = &width;
+    surfaceDesc.Height = &height;
+    surfaceDesc.Format = &format;
+    IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
+
+    /* Look for the context in the context cache */
+    for (i = 0; i < CONTEXT_CACHE; ++i) {
+    
+        /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
+         * ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
+         * the pSurface can be set to 0 allowing it to be reused from cache **/
+
+        /* I need a get width/height function (and should do something with the format) */
+        if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
+          && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
+            context = &This->contextCache[i];
+            break;
+        }
+
+        if (This->contextCache[i].Width == 0) {
+            This->contextCache[i].pSurface = pSurface;
+            This->contextCache[i].Width    = width;
+            This->contextCache[i].Height   = height;
+            context = &This->contextCache[i];
+            break;
+        }
+    }
+
+    /* Not found: evict another context from the cache */
+    if (i == CONTEXT_CACHE) {
+        int minUsage = 0x7FFFFFFF; /* MAX_INT */
+        glContext *dropContext = 0;
+        for (i = 0; i < CONTEXT_CACHE; i++) {
+            if (This->contextCache[i].usedcount < minUsage) {
+                dropContext = &This->contextCache[i];
+                minUsage = This->contextCache[i].usedcount;
+            }
+        }
+        /* clean up the context (this doesn't work for ATI at the moment */
+#if 0
+        glXDestroyContext(swapchain->display, dropContext->context);
+        GL_EXTCALL(glXDestroyGLXPbufferSGIX(swapchain->display, dropContext->drawable));
+#endif
+        FIXME("Leak\n");
+        dropContext->Width = 0;
+        dropContext->pSurface = pSurface;
+        context = dropContext;
+
+    /* Found in the cache */
+    } else {
+        if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
+            for (i = 0; i < CONTEXT_CACHE; i++)
+                This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
+        }
+    }
+
+    if (context == NULL)
+        goto err;
+
+    *newContext = context;
+    return WINED3D_OK;
+
+    err:
+    return E_FAIL;
+}
+
+static HRESULT device_pbuffer_init_context(
+    IWineD3DDeviceImpl* This,
+    IWineD3DSurface* renderSurface,
+    glContext* context) {
+
+    XVisualInfo *visinfo = NULL;
+    GLXFBConfigSGIX *cfgs = NULL;
+
+    IWineD3DSwapChain *implicitSwapchain = This->swapchains[0];
+    IWineD3DSwapChainImpl *implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
+
+    /* Already initialized, do nothing */
+    if (context->context != NULL)
+        goto exit;
+
+    /* Try fo find a valid fbconfig for this surface */
+    cfgs = device_pbuffer_find_fbconfigs(This, renderSurface);
+    if (!cfgs)
+        goto err;
+
+    /* Create a new pbuffer, set drawable field */
+    context->drawable = GL_EXTCALL(glXCreateGLXPbufferSGIX(
+        implicitSwapchainImpl->display, cfgs[0], context->Width, context->Height, NULL));
+
+    /* Find a visual */
+    visinfo = GL_EXTCALL(glXGetVisualFromFBConfigSGIX(implicitSwapchainImpl->display, cfgs[0]));
+    if (visinfo == NULL) {
+        ERR("Error: couldn't get an RGBA, double-buffered visual\n");
+        goto err;
+    }
+
+    /* Create context from visual, set context field */
+    context->context = glXCreateContext(
+       implicitSwapchainImpl->display, visinfo, implicitSwapchainImpl->glCtx, GL_TRUE);
+    if (context->context == NULL) {
+        ERR("(%p) : Failed to create GLX context for surface %p\n", This, renderSurface);
+        goto err;
+    }
+
+    exit:
+    if (cfgs != NULL)                 XFree(cfgs);
+    if (visinfo != NULL)              XFree(visinfo);
+    return WINED3D_OK;
+
+    err:
+    if (cfgs != NULL)                 XFree(cfgs);
+    if (visinfo != NULL)              XFree(visinfo);
+    return E_FAIL;
+}
+
+static void device_pbuffer_render_offscreen(   
+    IWineD3DDeviceImpl* This,
+    IWineD3DSwapChain* currentSwapchain,
+    IWineD3DSurface* initialRenderTarget) {
+
+    /***********************************************************************
+     * This is a quickly hacked out implementation of offscreen textures.
+     * It will work in most cases but there may be problems if the client
+     * modifies the texture directly, or expects the contents of the rendertarget
+     * to be persistent.
+     *
+     * There are some real speed vs compatibility issues here:
+     *    we should really use a new context for every texture, but that eats ram.
+     *    we should also be restoring the texture to the pbuffer but that eats CPU
+     *    we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
+     *    but if this means reusing the display backbuffer then we need to make sure that
+     *    states are correctly preserved.
+     * In many cases I would expect that we can 'skip' some functions, such as preserving states,
+     * and gain a good performance increase at the cost of compatibility.
+     * I would suggest that, when this is the case, a user configurable flag be made
+     * available, allowing the user to choose the best emulated experience for them.
+     *********************************************************************/
+    
+    IWineD3DSwapChain *implicitSwapchain = This->swapchains[0];
+    IWineD3DSwapChainImpl *implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
+    
+    glContext *newContext; 
+
+    TRACE("Switching to offscreen rendering.\n");
+
+    /* Here were using a shared context model */
+    if (device_pbuffer_find_context(This, initialRenderTarget, &newContext) != WINED3D_OK) {
+        FIXME("(%p) : Failed to find a context for surface %p\n", This, initialRenderTarget);
+        return;
+    }
+    
+    if (device_pbuffer_init_context(This, initialRenderTarget, newContext) != WINED3D_OK) {
+        FIXME("(%p) : Failed to initialize a context for surface %p\n", This, initialRenderTarget);
+        return;
+    }
+
+    /* Change rendering context */
+    device_switch_render_context(This, currentSwapchain,
+         implicitSwapchainImpl->display, newContext->drawable, newContext->context);
+
+    implicitSwapchainImpl->render_ctx = newContext->context;
+    implicitSwapchainImpl->drawable = newContext->drawable;
+}
+
 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
                                                IWineD3DSurface *RenderSurface) {
 
-    /**
-    * Currently only active for GLX >= 1.3
-    * for others versions we'll have to use GLXPixmaps
-    *
-    * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
-    * as they implement GLX 1.3 but only define GLX_VERSION_1_2
-    * so only check OpenGL version
-    * ..........................
-    * I don't believe that it is a problem with NVidia headers,
-    * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
-    * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
-    * ATI Note:
-    * Your application will report GLX version 1.2 on glXQueryVersion.
-    * However, it is safe to call the GLX 1.3 functions as described below.
-    */
-#if defined(GL_VERSION_1_3)
-
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    IWineD3DSurface *tmp;
-    GLXFBConfig* cfgs = NULL;
-    IWineD3DSwapChain     *currentSwapchain;
-    IWineD3DSwapChainImpl *currentSwapchainImpl;
-    IWineD3DSwapChain     *implicitSwapchain;
-    IWineD3DSwapChainImpl *implicitSwapchainImpl;
-    IWineD3DSwapChain     *renderSurfaceSwapchain;
-    IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
-
-    /* Obtain a reference to the device implicit swapchain,
-     * the swapchain of the current render target,
+    BOOL offscreenRendering = FALSE;
+    IWineD3DSwapChain *currentSwapchain;
+    IWineD3DSwapChain *renderSurfaceSwapchain;
+
+    /* Obtain a reference to the swapchain of the current render target,
      * and the swapchain of the new render target.
      * Fallback to device implicit swapchain if the current render target doesn't have one */
-    IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
     IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
     IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
     if (currentSwapchain == NULL)
         IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
 
-    currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
-    implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
-    renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
+    offscreenRendering = (renderSurfaceSwapchain == NULL);
 
     ENTER_GL();
 
-    /**
-    * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
-    *  renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
-     **********************************************************************/
-    if (renderSurfaceSwapchain != NULL) {
-
-        /* We also need to make sure that the lights &co are also in the context of the swapchains */
-        /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
-        TRACE("making swapchain active\n");
-        if (RenderSurface != This->renderTarget) {
-            BOOL backbuf = FALSE;
-            int i;
+    /* Onscreen rendering */
+    if (!offscreenRendering) {
+        device_render_onscreen (This, currentSwapchain, renderSurfaceSwapchain, RenderSurface);
+        device_render_upside_down(This, FALSE);
 
-            for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
-                if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
-                    backbuf = TRUE;
-                    break;
-                }
-            }
-
-            if (backbuf) {
-            } else {
-                /* This could be flagged so that some operations work directly with the front buffer */
-                FIXME("Attempting to set the  renderTarget to the frontBuffer\n");
-            }
-            if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
-                               renderSurfaceSwapchainImpl->win,
-                               renderSurfaceSwapchainImpl->glCtx) == False) {
-
-                TRACE("Error in setting current context: context %p drawable %ld !\n",
-                       implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
-            }
-            checkGLcall("glXMakeContextCurrent");
-
-            /* Clean up the old context */
-            IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
-
-            /* Reapply the stateblock, and set the device not to render to texture */
-            device_reapply_stateblock(This);
-            device_render_to_texture(This, FALSE);
-        }
-
-    /* Offscreen rendering: PBuffers (currently disabled).
-     * Also note that this path is never reached if FBOs are supported */
-    } else if (pbuffer_support &&
-               (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
-
-        /** ********************************************************************
-        * This is a quickly hacked out implementation of offscreen textures.
-        * It will work in most cases but there may be problems if the client
-        * modifies the texture directly, or expects the contents of the rendertarget
-        * to be persistent.
-        *
-        * There are some real speed vs compatibility issues here:
-        *    we should really use a new context for every texture, but that eats ram.
-        *    we should also be restoring the texture to the pbuffer but that eats CPU
-        *    we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
-        *    but if this means reusing the display backbuffer then we need to make sure that
-        *    states are correctly preserved.
-        * In many cases I would expect that we can 'skip' some functions, such as preserving states,
-        * and gain a good performance increase at the cost of compatibility.
-        * I would suggest that, when this is the case, a user configurable flag be made
-        * available, allowing the user to choose the best emulated experience for them.
-         *********************************************************************/
-
-        XVisualInfo *visinfo;
-        glContext   *newContext;
-
-        /* Here were using a shared context model */
-        if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
-            FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
-        }
-
-        /* If the context doesn't exist then create a new one */
-        /* TODO: This should really be part of findGlContext */
-        if (NULL == newContext->context) {
-
-            int attribs[256];
-            int nAttribs = 0;
-
-            TRACE("making new buffer\n");
-            attribs[nAttribs++] = GLX_PBUFFER_WIDTH; 
-            attribs[nAttribs++] = newContext->Width;
-            attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
-            attribs[nAttribs++] = newContext->Height;
-            attribs[nAttribs++] = None;
-
-            newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
-
-            /** ****************************************
-            *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
-            *they note:
-            *   In future releases, we may provide the calls glXCreateNewContext,
-            *   glXQueryDrawable and glXMakeContextCurrent.
-            *    so until then we have to use glXGetVisualFromFBConfig &co..
-            ********************************************/
-
-            visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
-            if (!visinfo) {
-                ERR("Error: couldn't get an RGBA, double-buffered visual\n");
-            } else {
-                newContext->context = glXCreateContext(
-                    implicitSwapchainImpl->display, visinfo,
-                    implicitSwapchainImpl->glCtx, GL_TRUE);
-
-                XFree(visinfo);
-            }
-        }
-        if (NULL == newContext || NULL == newContext->context) {
-            ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
-        } else {
-            /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
-            if (glXMakeCurrent(implicitSwapchainImpl->display,
-                newContext->drawable, newContext->context) == False) {
-
-                TRACE("Error in setting current context: context %p drawable %ld\n",
-                    newContext->context, newContext->drawable);
-            }
-            checkGLcall("glXMakeContextCurrent");
-
-            /* Clean up the old context */
-            IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
-
-            /* Reapply stateblock, and set device to render to a texture */
-            device_reapply_stateblock(This);
-            device_render_to_texture(This, TRUE);
+    /* Offscreen rendering: PBuffers */
+    } else if (wined3d_settings.offscreen_selected_mode == OFFSCREEN_PBUFFER) {
+        device_pbuffer_render_offscreen(This, currentSwapchain, This->renderTarget);
+        device_render_upside_down(This, TRUE);
+ 
+    /* Offscreen rendering will be done onscreen, but result will
+     * still be written to texture afterwards */
+    } else
+        device_render_upside_down(This, TRUE);
 
-            /* Set the current context of the swapchain to the new context */
-            implicitSwapchainImpl->drawable   = newContext->drawable;
-            implicitSwapchainImpl->render_ctx = newContext->context;
-        }
-    }
+    LEAVE_GL();
 
     /* Replace the render target */
-    tmp = This->renderTarget;
+    IWineD3DSurface_AddRef(RenderSurface);
+    IWineD3DSurface_Release(This->renderTarget);
     This->renderTarget = RenderSurface;
-    IWineD3DSurface_AddRef(This->renderTarget);
-    IWineD3DSurface_Release(tmp);
+    This->offscreenRendering = offscreenRendering;
 
-    if (cfgs != NULL)                   XFree(cfgs);
-    if (implicitSwapchain != NULL)       IWineD3DSwapChain_Release(implicitSwapchain);
     if (currentSwapchain != NULL)       IWineD3DSwapChain_Release(currentSwapchain);
     if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
-    LEAVE_GL();
-#endif
+
     return WINED3D_OK;
 }
 
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 19e3172..909b88c 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -237,6 +237,22 @@ static void select_shader_mode(
     }
 }
 
+/* Select the offscreen mode, based on the given capabilities */
+static void select_offscreen_mode(
+    WineD3D_GL_Info *gl_info,
+    int* offscreen_selected) {
+   
+    /* FBOs currently not supported.
+     * PBUFFERs currently disabled */
+ 
+    if (FALSE && gl_info->supported[EXT_FRAMEBUFFER_OBJECT])
+        *offscreen_selected = OFFSCREEN_FBO;
+    else if (pbuffer_support && gl_info->glx_supported[SGIX_FBCONFIG] && gl_info->glx_supported[SGIX_PBUFFER])
+        *offscreen_selected = OFFSCREEN_PBUFFER;
+    else
+        *offscreen_selected = OFFSCREEN_NONE;
+}      
+
 /** Select the number of report maximum shader constants based on the selected shader modes */
 void select_shader_max_constants(WineD3D_GL_Info *gl_info) {
 
@@ -975,6 +991,15 @@ #undef USE_GL_FUNC
                 }
                 memcpy(ThisExtn, Start, (GLX_Extensions - Start));
                 TRACE_(d3d_caps)("- %s\n", ThisExtn);
+
+                if (strcmp(ThisExtn, "GLX_SGIX_pbuffer") == 0) {
+                    TRACE_(d3d_caps)(" FOUND: SGIX Pixel Buffer support\n");
+                    gl_info->glx_supported[SGIX_PBUFFER] = TRUE;
+                } else if (strcmp(ThisExtn, "GLX_SGIX_fbconfig") == 0) {
+                    TRACE_(d3d_caps)(" FOUND: SGIX Framebuffer Config support\n");
+                    gl_info->glx_supported[SGIX_FBCONFIG] = TRUE;
+                }
+
                 if (*GLX_Extensions == ' ') GLX_Extensions++;
             }
         }
@@ -1810,6 +1835,7 @@ static HRESULT WINAPI IWineD3DImpl_GetDe
     }
     select_shader_mode(&This->gl_info, DeviceType,
         &wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode);
+    select_offscreen_mode(&This->gl_info, &wined3d_settings.offscreen_selected_mode);
     select_shader_max_constants(&This->gl_info);
 
     /* ------------------------------------------------
@@ -2400,6 +2426,7 @@ static HRESULT  WINAPI IWineD3DImpl_Crea
     LEAVE_GL();
     select_shader_mode(&This->gl_info, DeviceType,
         &wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode);
+    select_offscreen_mode(&This->gl_info, &wined3d_settings.offscreen_selected_mode);
     select_shader_max_constants(&This->gl_info);
 
     temp_result = allocate_shader_constants(object->updateStateBlock);
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 2d072fa..e60b0ee 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -2281,13 +2281,13 @@ #define PUSH2(att,value)  attribs[(*nAtt
     switch (BackBufferFormat) {
         /* color buffer */
     case WINED3DFMT_P8:
-        PUSH2(GLX_RENDER_TYPE,  GLX_COLOR_INDEX_BIT);
+        PUSH2(GLX_RENDER_TYPE_SGIX,  GLX_COLOR_INDEX_BIT_SGIX);
         PUSH2(GLX_BUFFER_SIZE,  8);
         PUSH2(GLX_DOUBLEBUFFER, TRUE);
         break;
 
     case WINED3DFMT_R3G3B2:
-        PUSH2(GLX_RENDER_TYPE,  GLX_RGBA_BIT);
+        PUSH2(GLX_RENDER_TYPE_SGIX,  GLX_RGBA_BIT_SGIX);
         PUSH2(GLX_RED_SIZE,     3);
         PUSH2(GLX_GREEN_SIZE,   3);
         PUSH2(GLX_BLUE_SIZE,    2);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 9b36a70..1615b56 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -127,6 +127,10 @@ #define VS_SW      2
 #define PS_NONE    0
 #define PS_HW      1
 
+#define OFFSCREEN_NONE    0
+#define OFFSCREEN_PBUFFER 1
+#define OFFSCREEN_FBO     2
+
 #define VBO_NONE   0
 #define VBO_HW     1
 
@@ -156,6 +160,7 @@ typedef struct wined3d_settings_s {
   BOOL glslRequested;
   int vs_selected_mode;
   int ps_selected_mode;
+  int offscreen_selected_mode;
 /* nonpower 2 function */
   int nonpower2_mode;
   int rendertargetlock_mode;
@@ -188,6 +193,7 @@ #endif
 /* GL related defines */
 /* ------------------ */
 #define GL_SUPPORT(ExtName)           (GLINFO_LOCATION.supported[ExtName] != 0)
+#define GLX_SUPPORT(ExtName)          (GLINFO_LOCATION.glx_supported[ExtName] != 0)
 #define GL_LIMITS(ExtName)            (GLINFO_LOCATION.max_##ExtName)
 #define GL_EXTCALL(FuncName)          (GLINFO_LOCATION.FuncName)
 #define GL_VEND(_VendName)            (GLINFO_LOCATION.gl_vendor == VENDOR_##_VendName ? TRUE : FALSE)
@@ -543,6 +549,9 @@ #define                         NEEDS_DI
     /* For rendering to a texture using glCopyTexImage */
     BOOL                    renderUpsideDown;
 
+    /* Offscreen rendering */
+    BOOL offscreenRendering;
+
     /* Cursor management */
     BOOL                    bCursorVisible;
     UINT                    xHotSpot;
diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h
index 1a589a5..31fa32c 100644
--- a/include/wine/wined3d_gl.h
+++ b/include/wine/wined3d_gl.h
@@ -1023,6 +1023,7 @@ #define GL_HILO8_NV                     
 #define GL_SIGNED_HILO8_NV                0x885F
 #define GL_FORCE_BLUE_TO_ONE_NV           0x8860
 #endif
+
 /* GL_ATI_texture_env_combine3 */
 #ifndef GL_ATI_texture_env_combine3
 #define GL_ATI_texture_env_combine3 1
@@ -1305,6 +1306,32 @@ #endif
  *  defines and functions pointer
  ****************************************************/
 
+/* GLX_SGIX_fbconfig */
+#ifndef GLX_SGIX_fbconfig
+#define GLX_SGIX_fbconfig 1
+typedef struct WINE_GLXFBConfigSGIX* GLXFBConfigSGIX;
+#define GLX_WINDOW_BIT_SGIX              0x00000001
+#define GLX_PIXMAP_BIT_SGIX              0x00000002
+#define GLX_RGBA_BIT_SGIX                0x00000001
+#define GLX_COLOR_INDEX_BIT_SGIX         0x00000002
+#define GLX_DRAWABLE_TYPE_SGIX           0x8010
+#define GLX_RENDER_TYPE_SGIX             0x8011
+#define GLX_X_RENDERABLE_SGIX            0x8012
+#define GLX_RGBA_TYPE_SGIX               0x8014
+#define GLX_COLOR_INDEX_TYPE_SGIX        0x8015
+#endif
+typedef GLXFBConfigSGIX * (APIENTRY * PGLXFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);
+typedef XVisualInfo     * (APIENTRY * PGLXFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfig config);
+
+/* GLX_SGIX_pbuffer */
+#ifndef GLX_SGIX_pbuffer
+#define GLX_SGIX_pbuffer 1
+typedef struct WINE_GLXPbufferSGIX* GLXPbufferSGIX;
+#define GLX_PBUFFER_SGIX                  0x8023
+#define GLX_PBUFFER_BIT_SGIX              0x00000004
+#endif
+typedef GLXPbufferSGIX (APIENTRY * PGLXFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int* attrib_list);
+typedef void           (APIENTRY * PGLXFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer);
 
 /****************************************************
  * OpenGL GLX Official Version
@@ -1467,6 +1494,13 @@ typedef enum _GL_SupportedExt {
   OPENGL_SUPPORTED_EXT_END
 } GL_SupportedExt;
 
+/* GLX Supported Extensions */
+typedef enum _GLX_SupportedExt {
+  SGIX_FBCONFIG,
+  SGIX_PBUFFER,
+
+  GLX_SUPPORTED_EXT_END
+} GLX_SupportedExt;
 
 /****************************************************
  * #Defines       
@@ -1715,6 +1749,12 @@ #define GL2_FUNCS_GEN \
     USE_GL_FUNC(PGLFNVERTEXATTRIBPOINTERPROC, glVertexAttribPointer); \
 
 #define GLX_EXT_FUNCS_GEN \
+    /** GLX_SGIX_fbconfig **/ \
+    USE_GL_FUNC(PGLXFNGLXCHOOSEFBCONFIGSGIXPROC,     glXChooseFBConfigSGIX); \
+    USE_GL_FUNC(PGLXFNGLXGETVISUALFROMFBCONFIGSGIXPROC, glXGetVisualFromFBConfigSGIX); \
+    /** GLX_SGIX_pbuffer **/ \
+    USE_GL_FUNC(PGLXFNGLXCREATEGLXPBUFFERSGIXPROC,   glXCreateGLXPbufferSGIX); \
+    USE_GL_FUNC(PGLXFNGLXDESTROYGLXPBUFFERSGIXPROC,  glXDestroyGLXPbufferSGIX); \
     /** GLX_VERSION_1_3 **/ \
     USE_GL_FUNC(PGLXFNGLXCREATEPBUFFERPROC,          glXCreatePbuffer); \
     USE_GL_FUNC(PGLXFNGLXDESTROYPBUFFERPROC,         glXDestroyPbuffer); \
@@ -1782,6 +1822,7 @@ typedef struct _WineD3D_GL_Info {
   GL_VSVersion vs_ati_version;
 
   BOOL supported[OPENGL_SUPPORTED_EXT_END + 1];
+  BOOL glx_supported[GLX_SUPPORTED_EXT_END + 1];
 
   /** OpenGL EXT and ARB functions ptr */
   GL_EXT_FUNCS_GEN;
-- 
1.4.1



More information about the wine-patches mailing list