Implement the use of PBuffers for offscreen textures.

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 8ce38c2..73cc587 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -53,6 +53,12 @@
 /* Memory tracking and object counting */
 static unsigned int emulated_textureram = 64*1024*1024;
 
+/* TODO: setup some flags in the regestry to enable, disable pbuffer support */
+/* enable pbuffer support for offscreen textures */
+BOOL pbuffer_support     = TRUE;
+/* allocate one pbuffer per surface */
+BOOL pbuffer_per_surface = FALSE;
+
 /* helper macros */
 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return D3DERR_OUTOFVIDEOMEMORY;}
 
@@ -4370,7 +4376,8 @@
 
         /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
         IUnknown *targetContainer = NULL;
-        if (D3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)) {
+        if (D3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
+            || D3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
             TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
             /** always dirtify for now. we must find a better way to see that surface have been modified
             (Modifications should will only occur via draw-primitive, but we do need better locking
@@ -4381,19 +4388,9 @@
             IWineD3DSurface_PreLoad(This->renderTarget);
             IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
             IUnknown_Release(targetContainer);
-        } else
-        if (D3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
-                /* The surface is stand-alone, so doesn't currently have a context of it's own */
-                TRACE("(%p) : standalone rendertarget %p\n", This, This->renderTarget);
-                IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
-                IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
-                IWineD3DSurface_PreLoad(This->renderTarget);
-                IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
-                IUnknown_Release(targetContainer);
         }
-
     }
-
+    This->sceneEnded = TRUE;
     LEAVE_GL();
     return D3D_OK;
 }
@@ -5135,15 +5132,17 @@
 
 HRESULT WINAPI static IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain);
 
+HRESULT WINAPI static IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context);
+
 HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
     HRESULT  hr = D3D_OK;
     WINED3DVIEWPORT viewport;
 
     TRACE("(%p) Swapping rendertarget\n",This);
-    if (RenderTargetIndex>0) {
+    if (RenderTargetIndex > 0) {
         FIXME("(%p) Render targets other than the first are not supported\n",This);
-        RenderTargetIndex=0;
+        RenderTargetIndex = 0;
     }
 
     /* MSDN says that null disables the render target
@@ -5157,7 +5156,7 @@
         FIXME("Trying to set render target 0 to NULL\n");
         return D3DERR_INVALIDCALL;
     }
-    /* TODO: raplce Impl* usage with interface usage */
+    /* TODO: replace Impl* usage with interface usage */
     if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & D3DUSAGE_RENDERTARGET) {
         FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of D3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
         return D3DERR_INVALIDCALL;
@@ -5170,6 +5169,10 @@
         TRACE("Trying to do a NOP SetRenderTarget operation\n");
     } else {
         /* Otherwise, set the render target up */
+
+        if (FALSE == This->sceneEnded) {
+            IWineD3DDevice_EndScene(iface);
+        }
         TRACE("clearing renderer\n");
         /* IWineD3DDeviceImpl_CleanRender(iface); */
         /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
@@ -5190,23 +5193,23 @@
         viewport.MaxZ   = 1.0f;
         viewport.MinZ   = 0.0f;
         IWineD3DDeviceImpl_SetViewport(iface, &viewport);
-    }else{
+    } else {
         FIXME("Unknown error setting the render target\n");
     }
+    This->sceneEnded = FALSE;
     return hr;
 }
 
 HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
     HRESULT  hr = D3D_OK;
-    WINED3DVIEWPORT viewport;
     IWineD3DSurface *tmp;
 
     TRACE("(%p) Swapping z-buffer\n",This);
 
     if (pNewZStencil == This->stencilBufferTarget) {
         TRACE("Trying to do a NOP SetRenderTarget operation\n");
-    }else{
+    } else {
         /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
         * depending on the renter target implementation being used.
         * A shared context implementation will share all buffers between all rendertargets (including swapchains),
@@ -5226,18 +5229,6 @@
           **********************************************************/
     }
 
-    if (SUCCEEDED(hr)) {
-        /* Finally, reset the viewport as the MSDN states.*/
-        /* TODO: get ridd of Impl usage */
-        viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
-        viewport.Width  = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
-        viewport.X      = 0;
-        viewport.Y      = 0;
-        viewport.MaxZ   = 1.0f;
-        viewport.MinZ   = 0.0f;
-        IWineD3DDeviceImpl_SetViewport(iface, &viewport);
-    }
-
     return hr;
 }
 
@@ -5254,22 +5245,73 @@
     TRACE("(%p), %p\n", This, swapchain);
 
     if (swapchain->win != swapchain->drawable) {
-#if defined(GL_VERSION_1_3) /* @see comments on ActiveRender */
-        ENTER_GL();
-        if (swapchain->glCtx != swapchain->render_ctx) {
-            FIXME("Destroying context %p \n", swapchain->render_ctx);
-            glXDestroyContext(swapchain->display, swapchain->render_ctx);
-
-        }
-        FIXME("glXDestroyPbuffer %ld \n", swapchain->drawable);
-        glXDestroyPbuffer(swapchain->display, swapchain->drawable);
-        LEAVE_GL();
-#endif
         /* Set everything back the way it ws */
         swapchain->render_ctx = swapchain->glCtx;
-        swapchain->drawable = swapchain->win;
+        swapchain->drawable   = swapchain->win;
     }
-  return D3D_OK;
+    return D3D_OK;
+}
+/* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
+HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    int i;
+    int width;
+    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 D3D_OK;
+    else
+        return E_OUTOFMEMORY;
 }
 
 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
@@ -5279,25 +5321,25 @@
 HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
                                                IWineD3DSurface *RenderSurface) {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-#ifndef USE_RENDER_MANAGER
 
-  IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
-  HRESULT ret =  D3DERR_INVALIDCALL;
-  /**
-   * 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.
-   */
+    IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
+    HRESULT ret =  D3DERR_INVALIDCALL;
+    IWineD3DSurface *tmp;
+    /**
+    * 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)
 
     /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
@@ -5312,11 +5354,6 @@
     ** *********************************************************/
     D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
     D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
-#if 0
-    UINT Width = ((IWineD3DSurfaceImpl *) RenderSurface)->currentDesc.Width;
-    UINT Height = ((IWineD3DSurfaceImpl *) RenderSurface)->currentDesc.Height;
-#endif
-    IWineD3DSurface *tmp;
 
     /**TODO:
         if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
@@ -5339,13 +5376,11 @@
 
     PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
     PUSH2(GLX_X_RENDERABLE,  TRUE);
-    PUSH2(GLX_DOUBLEBUFFER, TRUE);
+    PUSH2(GLX_DOUBLEBUFFER,  TRUE);
     TRACE("calling makeglcfg\n");
     D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
-
     PUSH1(None);
 
-
     TRACE("calling chooseFGConfig\n");
     cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
                                                      attribs, &nCfgs);
@@ -5366,7 +5401,7 @@
                                                         attribs, &nCfgs);
     }
 
-#if 0
+    if (NULL != cfgs) {
 #ifdef EXTRA_TRACES
         int i;
         for (i = 0; i < nCfgs; ++i) {
@@ -5374,21 +5409,20 @@
             debug_d3dformat(BackBufferFormat), StencilBufferFormat,
             debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
         }
-#endif
-#endif
-    if (NULL != This->renderTarget) {
-#ifdef EXTRA_TRACES
-        glFlush();
-        vcheckGLcall("glFlush");
-        /** This is only useful if the old render target was a swapchain,
-        * we need to supercede this with a function that displays
-        * the current buffer on the screen. This is easy to do in glx1.3 but
-        * we need to do copy-write pixels in glx 1.2.
-         ************************************************/
-        glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
 
-        printf("Hit Enter to get next frame ...\n");
-        getchar();
+        if (NULL != This->renderTarget) {
+            glFlush();
+            vcheckGLcall("glFlush");
+            /** This is only useful if the old render target was a swapchain,
+            * we need to supercede this with a function that displays
+            * the current buffer on the screen. This is easy to do in glx1.3 but
+            * we need to do copy-write pixels in glx 1.2.
+            ************************************************/
+            glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
+
+            printf("Hit Enter to get next frame ...\n");
+            getchar();
+        }
 #endif
     }
 
@@ -5417,131 +5451,102 @@
                        impSwapChain->glCtx, impSwapChain->win);
             }
 
-
-#if 0 /* TODO: apply the state block to the 'possibly' new context. */
-            BOOL oldRecording;
-            IWineD3DStateBlockImpl *oldUpdateStateBlock;
-            oldUpdateStateBlock = This->updateStateBlock;
-            oldRecording= This->isRecordingState;
-            This->isRecordingState = FALSE;
-            This->updateStateBlock = This->stateBlock;
-            IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
-
-            This->isRecordingState = oldRecording;
-            This->updateStateBlock = oldUpdateStateBlock;
-#endif
-
             IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
         }
         checkGLcall("glXMakeContextCurrent");
 
         IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
     }
-#if 0
-    else
-    if (NULL != cfgs  &&
-               (((IWineD3DSwapChainImpl *)currentSwapchain)->drawable == ((IWineD3DSwapChainImpl *)currentSwapchain)->win
-                ||  BackBufferFormat != ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Format
-                || (Width > ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width
-                ||  Height > ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height))) {
+    else if (pbuffer_support == TRUE && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
 
         /** ********************************************************************
-        * This code is far too leaky to be useful. IWineD3DDeviceImpl_CleanRender
-        * doesn't seem to work properly and creating a new context every time is 'extremely' overkill.
-        * The code does however work, and should be moved to a context manager to
-        * manage caching of pbuffers or render to texture are appropriate.
+        * This is a quickley hacked out implementation of offscreen textures
+        * it will work in most cases but there may be problems if the client
+        * modifies the textre directly, or expects the contenst of the rendertarget
+        * to be persistant.
         *
-        * There are some real speed vs compatibility issues here:
+        * There are some real speed vs compatability 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.
+        * and gain a good performance increase at the cost of compatability.
         * 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.
+        * available, alowing the user to choose the best emmulated experiance for them.
          *********************************************************************/
 
-        /**
-        * TODO: support for faces of cube textures, possibly volumes
-        * (this should be easy for ATI as I have examples)
-        **/
-
-        GLXContext  newContext;
-        Drawable    newDrawable;
         XVisualInfo *visinfo;
+        glContext   *newContext;
 
-        TRACE("making new buffer\n");
-        nAttribs = 0;
-        PUSH2(GLX_PBUFFER_WIDTH,  Width);
-        PUSH2(GLX_PBUFFER_HEIGHT, Height);
+        /* Here were using a shared context model */
+        if (D3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
+            FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
+        }
 
-#if 0 /* ATI render to texture support */
-        PUSH2(GLX_LARGEST_PBUFFER, True);/* This is ignored by ATI */
-        PUSH2(GLX_TEXTURE_FORMAT_ATI, GLX_TEXTURE_RGBA_ATI);
-        PUSH2(GLX_TEXTURE_TARGET_ATI, cubemap? GLX_TEXTURE_CUBE_MAP_ATI : GLX_TEXTURE_2D_ATI);
-        PUSH2(GLX_MIPMAP_TEXTURE_ATI, mipmapped? True : False);
-#endif
+        /* If the context doesn't exist then create a new one */
+        /* TODO: This should really be part of findGlContext */
+        if (NULL == newContext->context) {
 
-#if 0
-        /* TODO: discardable Pbuffer */
-        PUSH2(GLX_PRESERVED_CONTENTS, FALSE);
-#endif
+            TRACE("making new buffer\n");
+            nAttribs = 0;
+            PUSH2(GLX_PBUFFER_WIDTH,  newContext->Width);
+            PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
+            PUSH1(None);
 
-        PUSH1(None);
-        newDrawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
+            newContext->drawable  = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
 
-        /** ****************************************
-        *GLX1.3 isn't supported by XFree 'yet' untill 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..
-         ********************************************/
+            /** ****************************************
+            *GLX1.3 isn't supported by XFree 'yet' untill 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(impSwapChain->display, cfgs[0]);
             if (!visinfo) {
                 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
+            } else {
+                newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx,  GL_TRUE);
+                XFree(visinfo);
             }
-            newContext = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx,  GL_TRUE);
-            XFree(visinfo);
-
-        /* Make sure that the sorface exists as a glTexture */
-        IWineD3DSurface_PreLoad(RenderSurface);
-
-        newContext = glXCreateNewContext(impSwapChain->display, cfgs[0], GLX_RGBA_TYPE, impSwapChain->glCtx, TRUE);
-
-        if (NULL == newContext) {
-            ERR("cannot create glxContext\n");
-        }else{
+        }
+        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 */
-            FIXME("Created context %p drawable %ld \n", newContext, newDrawable);
+            if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
+                TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
+            }
 
-                if (glXMakeCurrent(impSwapChain->display, newDrawable, newContext) == False) {
-
-            TRACE("Error in setting current context: context %p drawable %ld\n", newContext, newDrawable);
+            /* Clean up the old context */
+            IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
+            /* Set the current context of the swapchain to the new context */
+            impSwapChain->drawable   = newContext->drawable;
+            impSwapChain->render_ctx = newContext->context;
         }
-
-        /* TODO: find out what of the current context needs to be coppied accross */
-
-        checkGLcall("glXMakeContextCurrent");
-
-        /* clean renderer should become part of the context manager so I'm not goint to put in in SwapChain just to remove it */
-        IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
-        /** TODO: We may need to copy the bits into the buffer,
-        * this should !!ONLY!! be done if an operation is performed on the target
-        * without it being cleared and the buffer is not discardable.
-        * (basically only bother preserving the contents if there's a possibility that it will be reused)
-        ** *********************************************************************/
-        impSwapChain->drawable = newDrawable;
-        impSwapChain->render_ctx = newContext;
-
-        }
-
     }
+
+#if 0 /* Apply the stateblock to the new context
+FIXME: This is a bit of a hack, each context should know it's own state,
+the directX current directX state should then be applied to the context */
+
+        BOOL oldRecording;
+        IWineD3DStateBlockImpl *oldUpdateStateBlock;
+        oldUpdateStateBlock = This->updateStateBlock;
+        oldRecording= This->isRecordingState;
+        This->isRecordingState = FALSE;
+        This->updateStateBlock = This->stateBlock;
+        IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
+
+        This->isRecordingState = oldRecording;
+        This->updateStateBlock = oldUpdateStateBlock;
 #endif
+
+
     /* clean up the current rendertargets swapchain (if it belonged to one) */
     if (currentSwapchain != NULL) {
         IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
@@ -5595,20 +5600,7 @@
     LEAVE_GL();
 
 #endif
-#else
-
-    IWineD3DSurface *tmp;
-    /* This should be handled outside of this function */
-    tmp = This->renderTarget;
-    This->renderTarget = RenderSurface;
-    IWineD3DSurface_AddRef(This->renderTarget);
-    IWineD3DSurface_Release( tmp);
-    tmp = This->stencilBufferTarget;
-    This->stencilBufferTarget = StencilSurface;
-
-#endif
     return ret;
-
 }
 
 HRESULT  WINAPI  IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 0f69221..7175925 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -371,6 +371,35 @@
 
 extern const IWineD3DVtbl IWineD3D_Vtbl;
 
+
+/** Hacked out start of a context manager!! **/
+typedef struct glContext {
+    int Width;
+    int Height;
+    int usedcount;
+    GLXContext context;
+
+    Drawable drawable;
+    IWineD3DSurface *pSurface;
+#if 0 /* TODO: someway to represent the state of the context */
+    IWineD3DStateBlock *pStateBlock;
+#endif
+/* a few other things like format */
+} glContext;
+
+/* TODO: setup some flags in the regestry to enable, disable pbuffer support
+(since it will break quite a few things until contexts are managed properly!) */
+extern BOOL pbuffer_support;
+/* allocate one pbuffer per surface */
+extern BOOL pbuffer_per_surface;
+
+/* Maximum number of contexts/pbuffers to keep in cache,
+set to 100 because ATI's drivers don't support deleting pBuffers properly
+this needs to be migrated to a list and some option availalbe for controle the cache size.
+*/
+#define CONTEXT_CACHE 100
+
+
 /*****************************************************************************
  * IWineD3DDevice implementation structure
  */
@@ -444,6 +473,11 @@
     /* Debug stream management */
     BOOL                     debug;
 
+    /* Screen buffer resources */
+    glContext contextCache[CONTEXT_CACHE];
+
+    /* A flag to check if endscene has been called before changing the render tartet */
+    BOOL sceneEnded;
 } IWineD3DDeviceImpl;
 
 extern const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl;