[5/10] WineD3D: Accelerated blits from and to offscreen render targets

Stefan Dösinger stefan at codeweavers.com
Wed Feb 14 20:02:39 CST 2007


-------------- next part --------------
From 8be81d9bb0cdf3ecb0f31b7c38733420d375f172 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Mon, 5 Feb 2007 09:10:01 +0100
Subject: [PATCH] WineD3D: Accelerated blits from and to offscreen render targets

---
 dlls/wined3d/surface.c |  581 ++++++++++++++++++++++++------------------------
 1 files changed, 290 insertions(+), 291 deletions(-)

diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index dabee6d..03247db 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -2120,7 +2120,7 @@ static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3D
     /* Bind the target texture */
     glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
     checkGLcall("glBindTexture");
-    if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
+    if(!swapchain || (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0])) {
         glReadBuffer(GL_BACK);
     } else {
         glReadBuffer(GL_FRONT);
@@ -2228,7 +2228,7 @@ static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWine
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     checkGLcall("glTexParameteri");
 
-    if((IWineD3DSurface *) This == swapchain->backBuffer[0] || TRUE) {
+    if(!swapchain || (IWineD3DSurface *) This == swapchain->backBuffer[0]) {
         src = backup;
     } else {
         glReadBuffer(GL_FRONT);
@@ -2341,21 +2341,25 @@ static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWine
 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
     WINED3DRECT rect;
     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
-    IWineD3DSwapChainImpl *swapchain = NULL;
+    IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
     BOOL SrcOK = TRUE;
 
     TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
 
     /* Get the swapchain. One of the surfaces has to be a primary surface */
-    IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
-    if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
-    else if(Src) {
-        IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
-        if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
-        else return WINED3DERR_INVALIDCALL;
-    } else {
-        swapchain = NULL;
+    IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
+    if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
+    if(Src) {
+        IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
+        if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
+    }
+
+    /* Early sort out of cases where no render target is used */
+    if(!dstSwapchain && !srcSwapchain &&
+        SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
+        TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
+        return WINED3DERR_INVALIDCALL;
     }
 
     if (DestRect) {
@@ -2370,12 +2374,11 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *
         rect.y2 = This->currentDesc.Height;
     }
 
-    /* Half-life does a Blt from the back buffer to the front buffer,
-     * Full surface size, no flags... Use present instead
-     */
-    if(Src)
-    {
-        /* First, check if we can do a Flip */
+    /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
+    if(dstSwapchain && dstSwapchain == srcSwapchain) {
+        /* Half-life does a Blt from the back buffer to the front buffer,
+         * Full surface size, no flags... Use present instead
+         */
 
         /* Check rects - IWineD3DDevice_Present doesn't handle them */
         if( SrcRect ) {
@@ -2396,9 +2399,10 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *
             /* These flags are unimportant for the flag check, remove them */
 
             if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
-                if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
+                if( dstSwapchain->backBuffer && ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) &&
+                    SrcSurface == dstSwapchain->backBuffer[0] ) {
 
-                    D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
+                    D3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
 
                     /* The idea behind this is that a glReadPixels and a glDrawPixels call
                      * take very long, while a flip is fast.
@@ -2412,328 +2416,323 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *
                      * and to set it back after the flip.
                      */
 
-                    swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
+                    dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
 
                     TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
                     IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
                                             NULL, NULL, 0, NULL);
 
-                    swapchain->presentParms.SwapEffect = orig_swap;
+                    dstSwapchain->presentParms.SwapEffect = orig_swap;
 
                     return WINED3D_OK;
                 }
             }
         }
 
-        /* Blt from texture to rendertarget? */
-        if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
-              ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
-              &&
-              ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
-                ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
-            float glTexCoord[4];
-            DWORD oldCKey;
-            DDCOLORKEY oldBltCKey = {0,0};
-            RECT SourceRectangle;
-            GLint oldDraw;
-
-            TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
-
-            if(SrcRect) {
-                SourceRectangle.left = SrcRect->left;
-                SourceRectangle.right = SrcRect->right;
-                SourceRectangle.top = SrcRect->top;
-                SourceRectangle.bottom = SrcRect->bottom;
-            } else {
-                SourceRectangle.left = 0;
-                SourceRectangle.right = Src->currentDesc.Width;
-                SourceRectangle.top = 0;
-                SourceRectangle.bottom = Src->currentDesc.Height;
-            }
+        TRACE("Unsupported blit between buffers on the same swapchain\n");
+        return WINED3DERR_INVALIDCALL;
+    } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) &&
+              (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) {
+        ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
+        return WINED3DERR_INVALIDCALL;
+    }
 
-            if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
-                /* Fall back to software */
-                WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
-                     SourceRectangle.left, SourceRectangle.top,
-                     SourceRectangle.right, SourceRectangle.bottom);
-                return WINED3DERR_INVALIDCALL;
-            }
+    if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) {
+        /* Blit from render target to texture */
+        WINED3DRECT srect;
+        BOOL upsideDown, stretchx;
 
-            /* Color keying: Check if we have to do a color keyed blt,
-             * and if not check if a color key is activated.
-             */
-            oldCKey = Src->CKeyFlags;
-            if(!(Flags & DDBLT_KEYSRC) && 
-               Src->CKeyFlags & DDSD_CKSRCBLT) {
-                /* Ok, the surface has a color key, but we shall not use it -
-                 * Deactivate it for now, LoadTexture will catch this
-                 */
-                Src->CKeyFlags &= ~DDSD_CKSRCBLT;
+        /* Call preload for the surface to make sure it isn't dirty */
+        IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
+
+        /* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
+            * glCopyTexSubImage is a bit picky about the parameters we pass to it
+            */
+        if(SrcRect) {
+            if(SrcRect->top < SrcRect->bottom) {
+                srect.y1 = SrcRect->top;
+                srect.y2 = SrcRect->bottom;
+                upsideDown = FALSE;
+            } else {
+                srect.y1 = SrcRect->bottom;
+                srect.y2 = SrcRect->top;
+                upsideDown = TRUE;
             }
+            srect.x1 = SrcRect->left;
+            srect.x2 = SrcRect->right;
+        } else {
+            srect.x1 = 0;
+            srect.y1 = 0;
+            srect.x2 = Src->currentDesc.Width;
+            srect.y2 = Src->currentDesc.Height;
+            upsideDown = FALSE;
+        }
+        if(rect.x1 > rect.x2) {
+            UINT tmp = rect.x2;
+            rect.x2 = rect.x1;
+            rect.x1 = tmp;
+            upsideDown = !upsideDown;
+        }
 
-            /* Color keying */
-            if(Flags & DDBLT_KEYDEST) {
-                oldBltCKey = This->SrcBltCKey;
-                /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
-                 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
-                 */
-                This->SrcBltCKey = This->DestBltCKey;
-            } else if (Flags & DDBLT_KEYSRC)
-                oldBltCKey = This->SrcBltCKey;
+        if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
+            stretchx = TRUE;
+        } else {
+            stretchx = FALSE;
+        }
 
-            /* Now load the surface */
-            IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
+        /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
+         * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
+         * not implemented by now). Otherwise:
+         *
+         * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
+         * -> If the app wants a image width an unscaled width, copy it line per line
+         * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
+         *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
+         *    back buffer. This is slower than reading line per line, thus not used for flipping
+         * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
+         *    pixel by pixel
+         */
+        if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
+            TRACE("Using GL_EXT_framebuffer_blit for copying\n");
+        } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
+                                    rect.y2 - rect.y1 > Src->currentDesc.Height) {
+            TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
+            fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
+        } else {
+            TRACE("Using hardware stretching to flip / stretch the texture\n");
+            fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
+        }
 
-            ENTER_GL();
+        if(!(This->Flags & SFLAG_DONOTFREE)) {
+            HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
+            This->resource.allocatedMemory = NULL;
+        } else {
+            This->Flags |= SFLAG_GLDIRTY;
+        }
 
-            ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
+        return WINED3D_OK;
+    } else if(Src) {
+        /* Blit from offscreen surface to render target */
+        float glTexCoord[4];
+        DWORD oldCKey;
+        DDCOLORKEY oldBltCKey = {0,0};
+        RECT SourceRectangle;
+        GLint oldDraw;
+
+        TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
+
+        if(SrcRect) {
+            SourceRectangle.left = SrcRect->left;
+            SourceRectangle.right = SrcRect->right;
+            SourceRectangle.top = SrcRect->top;
+            SourceRectangle.bottom = SrcRect->bottom;
+        } else {
+            SourceRectangle.left = 0;
+            SourceRectangle.right = Src->currentDesc.Width;
+            SourceRectangle.top = 0;
+            SourceRectangle.bottom = Src->currentDesc.Height;
+        }
 
-            glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
-            if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
-                TRACE("Drawing to front buffer\n");
-                glDrawBuffer(GL_FRONT);
-                checkGLcall("glDrawBuffer GL_FRONT");
-            }
+        if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
+            /* Fall back to software */
+            WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
+                    SourceRectangle.left, SourceRectangle.top,
+                    SourceRectangle.right, SourceRectangle.bottom);
+            return WINED3DERR_INVALIDCALL;
+        }
 
-            /* Bind the texture */
-            glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
-            checkGLcall("glBindTexture");
-
-            /* No filtering for blts */
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
-                            GL_NEAREST);
-            checkGLcall("glTexParameteri");
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
-                            GL_NEAREST);
-            checkGLcall("glTexParameteri");
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-            checkGLcall("glTexEnvi");
-
-            /* This is for color keying */
-            if(Flags & DDBLT_KEYSRC) {
-                glEnable(GL_ALPHA_TEST);
-                checkGLcall("glEnable GL_ALPHA_TEST");
-                glAlphaFunc(GL_NOTEQUAL, 0.0);
-                checkGLcall("glAlphaFunc\n");
-            } else {
-                glDisable(GL_ALPHA_TEST);
-                checkGLcall("glDisable GL_ALPHA_TEST");
-            }
+        /* Color keying: Check if we have to do a color keyed blt,
+         * and if not check if a color key is activated.
+         */
+        oldCKey = Src->CKeyFlags;
+        if(!(Flags & DDBLT_KEYSRC) &&
+            Src->CKeyFlags & DDSD_CKSRCBLT) {
+            /* Ok, the surface has a color key, but we shall not use it -
+             * Deactivate it for now, LoadTexture will catch this
+             */
+            Src->CKeyFlags &= ~DDSD_CKSRCBLT;
+        }
 
-            /* Draw a textured quad
+        /* Color keying */
+        if(Flags & DDBLT_KEYDEST) {
+            oldBltCKey = This->SrcBltCKey;
+            /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
+             * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
              */
-            glBegin(GL_QUADS);
-
-            glColor3d(1.0f, 1.0f, 1.0f);
-            glTexCoord2f(glTexCoord[0], glTexCoord[2]);
-            glVertex3f(rect.x1,
-                       rect.y1,
-                       0.0);
-
-            glTexCoord2f(glTexCoord[0], glTexCoord[3]);
-            glVertex3f(rect.x1, rect.y2, 0.0);
-
-            glTexCoord2f(glTexCoord[1], glTexCoord[3]);
-            glVertex3f(rect.x2,
-                       rect.y2,
-                       0.0);
-
-            glTexCoord2f(glTexCoord[1], glTexCoord[2]);
-            glVertex3f(rect.x2,
-                       rect.y1,
-                       0.0);
-            glEnd();
-            checkGLcall("glEnd");
-
-            /* Unbind the texture */
-            glBindTexture(GL_TEXTURE_2D, 0);
-            checkGLcall("glEnable glBindTexture");
-
-            if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
-                glDrawBuffer(oldDraw);
-            }
+            This->SrcBltCKey = This->DestBltCKey;
+        } else if (Flags & DDBLT_KEYSRC)
+            oldBltCKey = This->SrcBltCKey;
 
-            /* Restore the color key flags */
-            if(oldCKey != Src->CKeyFlags) {
-                Src->CKeyFlags = oldCKey;
-            }
+        /* Now load the surface */
+        IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
 
-            /* Restore the old color key */
-            if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
-                This->SrcBltCKey = oldBltCKey;
+        ENTER_GL();
 
-            LEAVE_GL();
+        /* Activate the destination context, set it up for blitting */
+        ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
 
-            /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
-            This->Flags |= SFLAG_GLDIRTY;
+        glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
+        if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer) {
+            TRACE("Drawing to front buffer\n");
+            glDrawBuffer(GL_FRONT);
+            checkGLcall("glDrawBuffer GL_FRONT");
+        }
 
-            return WINED3D_OK;
+        /* Bind the texture */
+        glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
+        checkGLcall("glBindTexture");
+
+        /* No filtering for blts */
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+                        GL_NEAREST);
+        checkGLcall("glTexParameteri");
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                        GL_NEAREST);
+        checkGLcall("glTexParameteri");
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+        checkGLcall("glTexEnvi");
+
+        /* This is for color keying */
+        if(Flags & DDBLT_KEYSRC) {
+            glEnable(GL_ALPHA_TEST);
+            checkGLcall("glEnable GL_ALPHA_TEST");
+            glAlphaFunc(GL_NOTEQUAL, 0.0);
+            checkGLcall("glAlphaFunc\n");
+        } else {
+            glDisable(GL_ALPHA_TEST);
+            checkGLcall("glDisable GL_ALPHA_TEST");
         }
 
+        /* Draw a textured quad
+            */
+        glBegin(GL_QUADS);
+
+        glColor3d(1.0f, 1.0f, 1.0f);
+        glTexCoord2f(glTexCoord[0], glTexCoord[2]);
+        glVertex3f(rect.x1,
+                    rect.y1,
+                    0.0);
+
+        glTexCoord2f(glTexCoord[0], glTexCoord[3]);
+        glVertex3f(rect.x1, rect.y2, 0.0);
+
+        glTexCoord2f(glTexCoord[1], glTexCoord[3]);
+        glVertex3f(rect.x2,
+                    rect.y2,
+                    0.0);
+
+        glTexCoord2f(glTexCoord[1], glTexCoord[2]);
+        glVertex3f(rect.x2,
+                    rect.y1,
+                    0.0);
+        glEnd();
+        checkGLcall("glEnd");
+
+        /* Unbind the texture */
+        glBindTexture(GL_TEXTURE_2D, 0);
+        checkGLcall("glEnable glBindTexture");
 
-        /* Blt from rendertarget to texture? */
-        if( (SrcSurface == swapchain->frontBuffer) ||
-            (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
-            if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
-                ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
-                WINED3DRECT srect;
-                BOOL upsideDown, stretchx;
+        if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && oldDraw == GL_BACK) {
+            glDrawBuffer(oldDraw);
+        }
 
-                TRACE("Blt from rendertarget to texture\n");
+        /* Restore the color key flags */
+        if(oldCKey != Src->CKeyFlags) {
+            Src->CKeyFlags = oldCKey;
+        }
 
-                /* Call preload for the surface to make sure it isn't dirty */
-                IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
+        /* Restore the old color key */
+        if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
+            This->SrcBltCKey = oldBltCKey;
 
-                /* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
-                 * glCopyTexSubImage is a bit picky about the parameters we pass to it
-                 */
-                if(SrcRect) {
-                    if(SrcRect->top < SrcRect->bottom) {
-                        srect.y1 = SrcRect->top;
-                        srect.y2 = SrcRect->bottom;
-                        upsideDown = FALSE;
-                    } else {
-                        srect.y1 = SrcRect->bottom;
-                        srect.y2 = SrcRect->top;
-                        upsideDown = TRUE;
-                    }
-                    srect.x1 = SrcRect->left;
-                    srect.x2 = SrcRect->right;
-                } else {
-                    srect.x1 = 0;
-                    srect.y1 = 0;
-                    srect.x2 = Src->currentDesc.Width;
-                    srect.y2 = Src->currentDesc.Height;
-                    upsideDown = FALSE;
-                }
-                if(rect.x1 > rect.x2) {
-                    UINT tmp = rect.x2;
-                    rect.x2 = rect.x1;
-                    rect.x1 = tmp;
-                    upsideDown = !upsideDown;
-                }
+        LEAVE_GL();
 
-                if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
-                    stretchx = TRUE;
-                } else {
-                    stretchx = FALSE;
-                }
+        /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
+        This->Flags |= SFLAG_GLDIRTY;
 
-                /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
-                 * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
-                 * not implemented by now). Otherwise:
-                 *
-                 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
-                 * -> If the app wants a image width an unscaled width, copy it line per line
-                 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
-                 *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
-                 *    back buffer. This is slower than reading line per line, thus not used for flipping
-                 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
-                 *    pixel by pixel
-                 */
-                if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
-                    TRACE("Using GL_EXT_framebuffer_blit for copying\n");
-                } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
-                                         rect.y2 - rect.y1 > Src->currentDesc.Height) {
-                    TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
-                    fb_copy_to_texture_direct(This, SrcSurface, swapchain, &srect, &rect, upsideDown);
+        return WINED3D_OK;
+    } else {
+        /* Source-Less Blit to render target */
+        if (Flags & DDBLT_COLORFILL) {
+            /* This is easy to handle for the D3D Device... */
+            DWORD color;
+
+            TRACE("Colorfill\n");
+
+            /* The color as given in the Blt function is in the format of the frame-buffer...
+             * 'clear' expect it in ARGB format => we need to do some conversion :-)
+             */
+            if (This->resource.format == WINED3DFMT_P8) {
+                if (This->palette) {
+                    color = ((0xFF000000) |
+                            (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
+                            (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
+                            (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
                 } else {
-                    TRACE("Using hardware stretching to flip / stretch the texture\n");
-                    fb_copy_to_texture_hwstretch(This, SrcSurface, swapchain, &srect, &rect, upsideDown);
+                    color = 0xFF000000;
                 }
-
-                if(!(This->Flags & SFLAG_DONOTFREE)) {
-                    HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
-                    This->resource.allocatedMemory = NULL;
+            }
+            else if (This->resource.format == WINED3DFMT_R5G6B5) {
+                if (DDBltFx->u5.dwFillColor == 0xFFFF) {
+                    color = 0xFFFFFFFF;
                 } else {
-                    This->Flags |= SFLAG_GLDIRTY;
+                    color = ((0xFF000000) |
+                            ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
+                            ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
+                            ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
                 }
-
-                return WINED3D_OK;
             }
-        }
-    }
-
-    if (Flags & DDBLT_COLORFILL) {
-        /* This is easy to handle for the D3D Device... */
-        DWORD color;
-        IWineD3DSwapChainImpl *implSwapChain;
-
-        TRACE("Colorfill\n");
-
-        /* The color as given in the Blt function is in the format of the frame-buffer...
-         * 'clear' expect it in ARGB format => we need to do some conversion :-)
-         */
-        if (This->resource.format == WINED3DFMT_P8) {
-            if (This->palette) {
-                color = ((0xFF000000) |
-                          (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
-                          (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
-                          (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
-            } else {
-                color = 0xFF000000;
+            else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
+                    (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
+                color = 0xFF000000 | DDBltFx->u5.dwFillColor;
             }
-        }
-        else if (This->resource.format == WINED3DFMT_R5G6B5) {
-            if (DDBltFx->u5.dwFillColor == 0xFFFF) {
-                color = 0xFFFFFFFF;
+            else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
+                color = DDBltFx->u5.dwFillColor;
+            }
+            else {
+                ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
+                return WINED3DERR_INVALIDCALL;
+            }
+
+            TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
+            if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
+                glDrawBuffer(GL_BACK);
+                checkGLcall("glDrawBuffer(GL_BACK)");
+            } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
+                glDrawBuffer(GL_FRONT);
+                checkGLcall("glDrawBuffer(GL_FRONT)");
+            } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
+                glDrawBuffer(GL_BACK);
+                checkGLcall("glDrawBuffer(GL_BACK)");
             } else {
-                color = ((0xFF000000) |
-                          ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
-                          ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
-                          ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
+                TRACE("Surface is higher back buffer, falling back to software\n");
+                return WINED3DERR_INVALIDCALL;
             }
-        }
-        else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
-                  (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
-            color = 0xFF000000 | DDBltFx->u5.dwFillColor;
-        }
-        else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
-            color = DDBltFx->u5.dwFillColor;
-        }
-        else {
-            ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
-            return WINED3DERR_INVALIDCALL;
-        }
 
-        TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
-        IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
-        IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
-        if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
-            glDrawBuffer(GL_BACK);
-            checkGLcall("glDrawBuffer(GL_BACK)");
-        }
-        else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
-            glDrawBuffer(GL_FRONT);
-            checkGLcall("glDrawBuffer(GL_FRONT)");
-        }
-        else {
-            ERR("Wrong surface type for BLT override(not on swapchain) !\n");
-            return WINED3DERR_INVALIDCALL;
-        }
+            TRACE("(%p) executing Render Target override, color = %x\n", This, color);
 
-        TRACE("(%p) executing Render Target override, color = %x\n", This, color);
+            IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
+                                1 /* Number of rectangles */,
+                                &rect,
+                                WINED3DCLEAR_TARGET,
+                                color,
+                                0.0 /* Z */,
+                                0 /* Stencil */);
 
-        IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
-                              1 /* Number of rectangles */,
-                              &rect,
-                              WINED3DCLEAR_TARGET,
-                              color,
-                              0.0 /* Z */,
-                              0 /* Stencil */);
+            /* Restore the original draw buffer */
+            if(!dstSwapchain || (dstSwapchain->backBuffer && dstSwapchain->backBuffer[0])) {
+                glDrawBuffer(GL_BACK);
+                vcheckGLcall("glDrawBuffer");
+            }
 
-        /* Restore the original draw buffer */
-        if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
-            glDrawBuffer(GL_BACK);
-            vcheckGLcall("glDrawBuffer");
+            return WINED3D_OK;
         }
-
-        return WINED3D_OK;
     }
 
-    /* Default: Fall back to the generic blt */
+    /* Default: Fall back to the generic blt. Not an error, a TRACE is enought */
+    TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
     return WINED3DERR_INVALIDCALL;
 }
 
-- 
1.4.4.3



More information about the wine-patches mailing list