WineD3D: Blit the offscreen texture into the drawable if needed

Stefan Dösinger stefan at codeweavers.com
Fri Mar 9 17:57:10 CST 2007


Deliberately no numbering because the patches should be independent of each 
other.

This time cube texture support is added. Hopefully the coords are right, I had 
no test app for them. If not it should be easy to spot the very 
characteristic flipping of the image.
-------------- next part --------------
From e9d4342e2a0ccd3dfa51141bcce29627cba1cee8 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Sat, 10 Mar 2007 00:55:08 +0100
Subject: [PATCH] WineD3D: Blit the offscreen texture into the drawable if needed

When using pbuffer or back buffer offscreen rendering the content of the drawable will have
been overwritten. Thus the texture has to be written into the drawable. An exception is the
(pretty common) case that the whole render target is cleared before rendering to it.
---
 dlls/wined3d/context.c         |    3 +
 dlls/wined3d/device.c          |   26 ++++++--
 dlls/wined3d/drawprim.c        |  128 ++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/wined3d_private.h |    2 +
 4 files changed, 153 insertions(+), 6 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index f7620aa..5fe2b58 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -710,6 +710,9 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU
              * Read the back buffer of the old drawable into the destination texture
              */
             IWineD3DSurface_PreLoad(This->lastActiveRenderTarget);
+
+            /* Assume that the drawable will be modified by some other things now */
+            ((IWineD3DSurfaceImpl *) This->lastActiveRenderTarget)->Flags &= ~SFLAG_INDRAWABLE;
         }
         This->lastActiveRenderTarget = target;
         if(oldRenderOffscreen != This->render_offscreen && This->depth_copy_state != WINED3D_DCS_NO_COPY) {
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 0998eec..ad82125 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -4124,6 +4124,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
                                         DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
 
     GLbitfield     glMask = 0;
     unsigned int   i;
@@ -4181,6 +4182,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
     }
 
     if (!curRect) {
+        /* In drawable flag is set below */
+
         glScissor(This->stateBlock->viewport.X,
                   (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
                   (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
@@ -4190,12 +4193,23 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
         glClear(glMask);
         checkGLcall("glClear");
     } else {
+        if(!(target->Flags & SFLAG_INDRAWABLE) &&
+           !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
+
+            if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
+               curRect[0].x2 < target->currentDesc.Width ||
+               curRect[0].y2 < target->currentDesc.Height) {
+                TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
+                blt_to_drawable(This, target);
+            }
+        }
+
         /* Now process each rect in turn */
         for (i = 0; i < Count; i++) {
             /* Note gl uses lower left, width/height */
             TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
                   curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
-                  curRect[i].x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2),
+                  curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
                   curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
 
             /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
@@ -4207,7 +4221,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
                 continue;
             }
 
-            glScissor(curRect[i].x1, ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2,
+            glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
                         curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
             checkGLcall("glScissor");
 
@@ -4234,11 +4248,11 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
      * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
      */
     if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
-        ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_INTEXTURE;
-        ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags &= ~SFLAG_INSYSMEM;
+        target->Flags |= SFLAG_INTEXTURE;
+        target->Flags &= ~SFLAG_INSYSMEM;
     } else {
-        ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_INDRAWABLE;
-        ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
+        target->Flags |= SFLAG_INDRAWABLE;
+        target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
     }
     return WINED3D_OK;
 }
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 4efd3e7..c34c642 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -989,6 +989,127 @@ inline void drawStridedInstanced(IWineD3DDevice *iface, WineDirect3DVertexStride
     }
 }
 
+struct coords {
+    int x, y, z;
+};
+
+void blt_to_drawable(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *surface) {
+    struct coords coords[4];
+    int low_coord;
+
+    /* TODO: This could be supported for lazy unlocking */
+    if(!(surface->Flags & SFLAG_INTEXTURE)) {
+        /* It is ok at init to be nowhere */
+        if(!(surface->Flags & SFLAG_INSYSMEM)) {
+            ERR("Blitting surfaces from sysmem not supported yet\n");
+        }
+        return;
+    }
+
+    ENTER_GL();
+    ActivateContext(This, This->render_targets[0], CTXUSAGE_BLIT);
+
+    if(surface->glDescription.target == GL_TEXTURE_2D) {
+        glBindTexture(GL_TEXTURE_2D, surface->glDescription.textureName);
+        checkGLcall("GL_TEXTURE_2D, This->glDescription.textureName)");
+
+        coords[0].x = 0;    coords[0].y = 0;    coords[0].z = 0;
+        coords[1].x = 0;    coords[1].y = 1;    coords[1].z = 0;
+        coords[2].x = 1;    coords[2].y = 1;    coords[2].z = 0;
+        coords[3].x = 1;    coords[3].y = 0;    coords[3].z = 0;
+
+        low_coord = 0;
+    } else {
+        /* Must be a cube map */
+        glDisable(GL_TEXTURE_2D);
+        checkGLcall("glDisable(GL_TEXTURE_2D)");
+        glEnable(GL_TEXTURE_CUBE_MAP_ARB);
+        checkGLcall("glEnable(surface->glDescription.target)");
+        glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, surface->glDescription.textureName);
+        checkGLcall("GL_TEXTURE_CUBE_MAP_ARB, This->glDescription.textureName)");
+
+        switch(surface->glDescription.target) {
+            case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+                coords[0].x =  1;   coords[0].y = -1;   coords[0].z =  1;
+                coords[1].x =  1;   coords[1].y =  1;   coords[1].z =  1;
+                coords[2].x =  1;   coords[2].y =  1;   coords[2].z = -1;
+                coords[3].x =  1;   coords[3].y = -1;   coords[3].z = -1;
+                break;
+
+            case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+                coords[0].x = -1;   coords[0].y = -1;   coords[0].z =  1;
+                coords[1].x = -1;   coords[1].y =  1;   coords[1].z =  1;
+                coords[2].x = -1;   coords[2].y =  1;   coords[2].z = -1;
+                coords[3].x = -1;   coords[3].y = -1;   coords[3].z = -1;
+                break;
+
+            case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+                coords[0].x = -1;   coords[0].y =  1;   coords[0].z =  1;
+                coords[1].x =  1;   coords[1].y =  1;   coords[1].z =  1;
+                coords[2].x =  1;   coords[2].y =  1;   coords[2].z = -1;
+                coords[3].x = -1;   coords[3].y =  1;   coords[3].z = -1;
+                break;
+
+            case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+                coords[0].x = -1;   coords[0].y = -1;   coords[0].z =  1;
+                coords[1].x =  1;   coords[1].y = -1;   coords[1].z =  1;
+                coords[2].x =  1;   coords[2].y = -1;   coords[2].z = -1;
+                coords[3].x = -1;   coords[3].y = -1;   coords[3].z = -1;
+                break;
+
+            case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+                coords[0].x = -1;   coords[0].y = -1;   coords[0].z =  1;
+                coords[1].x =  1;   coords[1].y = -1;   coords[1].z =  1;
+                coords[2].x =  1;   coords[2].y = -1;   coords[2].z =  1;
+                coords[3].x = -1;   coords[3].y = -1;   coords[3].z =  1;
+                break;
+
+            case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+                coords[0].x = -1;   coords[0].y = -1;   coords[0].z = -1;
+                coords[1].x =  1;   coords[1].y = -1;   coords[1].z = -1;
+                coords[2].x =  1;   coords[2].y = -1;   coords[2].z = -1;
+                coords[3].x = -1;   coords[3].y = -1;   coords[3].z = -1;
+
+            default:
+                ERR("Unexpected texture target \n");
+                LEAVE_GL();
+                return;
+        }
+
+        low_coord = -1;
+    }
+
+    if(This->render_offscreen) {
+        coords[0].y = coords[0].y == 1 ? low_coord : 1;
+        coords[1].y = coords[1].y == 1 ? low_coord : 1;
+        coords[2].y = coords[2].y == 1 ? low_coord : 1;
+        coords[3].y = coords[3].y == 1 ? low_coord : 1;
+    }
+
+    glBegin(GL_QUADS);
+        glTexCoord3iv((GLint *) &coords[0]);
+        glVertex2i(0, 0);
+
+        glTexCoord3iv((GLint *) &coords[1]);
+        glVertex2i(0, surface->pow2Height);
+
+        glTexCoord3iv((GLint *) &coords[2]);
+        glVertex2i(surface->pow2Width, surface->pow2Height);
+
+        glTexCoord3iv((GLint *) &coords[3]);
+        glVertex2i(surface->pow2Width, 0);
+    glEnd();
+    checkGLcall("glEnd");
+
+    if(surface->glDescription.target != GL_TEXTURE_2D) {
+        glEnable(GL_TEXTURE_2D);
+        checkGLcall("glEnable(GL_TEXTURE_2D)");
+        glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+        checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
+    }
+    LEAVE_GL();
+}
+
 /* Routine common to the draw primitive and draw indexed primitive routines */
 void drawPrimitive(IWineD3DDevice *iface,
                    int PrimitiveType,
@@ -1013,6 +1134,7 @@ void drawPrimitive(IWineD3DDevice *iface,
     /* Invalidate the back buffer memory so LockRect will read it the next time */
     for(i = 0; i < GL_LIMITS(buffers); i++) {
         target = (IWineD3DSurfaceImpl *) This->render_targets[i];
+
         /* TODO: Only do all that if we're going to change anything
          * Texture container dirtification does not work quite right yet
          */
@@ -1022,6 +1144,12 @@ void drawPrimitive(IWineD3DDevice *iface,
 
             if(i == 0) {
                 IWineD3DSurface_GetContainer((IWineD3DSurface *) target, &IID_IWineD3DSwapChain, (void **)&swapchain);
+
+                /* Need the surface in the drawable! */
+                if(!(target->Flags & SFLAG_INDRAWABLE) && (swapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO)) {
+                    blt_to_drawable(This, target);
+                }
+
                 if(swapchain) {
                     /* Onscreen target. Invalidate system memory copy and texture copy */
                     target->Flags &= ~(SFLAG_INSYSMEM | SFLAG_INTEXTURE);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index df0ff6a..9d80d83 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -427,6 +427,8 @@ void primitiveConvertFVFtoOffset(DWORD thisFVF,
 
 DWORD get_flexible_vertex_size(DWORD d3dvtVertexType);
 
+void blt_to_drawable(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *surface);
+
 #define eps 1e-8
 
 #define GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_num) \
-- 
1.4.4.3



More information about the wine-patches mailing list