[3/4] WineD3D: Blit the offscreen texture into the drawable if needed

Stefan Dösinger stefan at codeweavers.com
Tue Mar 6 19:43:34 CST 2007


-------------- next part --------------
From ddd07e0507fe5728de92c7115d8c8506074714b4 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Wed, 7 Mar 2007 01:29:32 +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        |   60 ++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/wined3d_private.h |    2 +
 4 files changed, 85 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 fb4c17b..dcf4daa 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..d862234 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -989,6 +989,59 @@ inline void drawStridedInstanced(IWineD3DDevice *iface, WineDirect3DVertexStride
     }
 }
 
+void blt_to_drawable(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *surface) {
+
+    /* 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;
+    }
+
+    ERR("Blitting!!\n");
+
+    ENTER_GL();
+    ActivateContext(This, This->render_targets[0], CTXUSAGE_BLIT);
+
+    if(surface->glDescription.target != GL_TEXTURE_2D) {
+        /* D3D can do offscreen rendering only to cube maps and 2D surfaces */
+        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)");
+    } else {
+        glBindTexture(GL_TEXTURE_2D, surface->glDescription.textureName);
+        checkGLcall("GL_TEXTURE_2D, This->glDescription.textureName)");
+    }
+
+    glBegin(GL_QUADS);
+        glTexCoord2i(0, This->render_offscreen ? 1 : 0);
+        glVertex2i(0, 0);
+
+        glTexCoord2i(0, This->render_offscreen ? 0 : 1);
+        glVertex2i(0, surface->pow2Height);
+
+        glTexCoord2i(1, This->render_offscreen ? 0 : 1);
+        glVertex2i(surface->pow2Width, surface->pow2Height);
+
+        glTexCoord2i(1, This->render_offscreen ? 1 : 0);
+        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 +1066,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 +1076,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 9f9c865..d5c88af 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -429,6 +429,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