[PATCH 1/5] wined3d: Avoid some needless depth buffer copies.

Henri Verbeet hverbeet at codeweavers.com
Wed Apr 28 17:08:59 CDT 2010


If an application switches between render targets of a different size, but
with the same depth/stencil surface it'll typically clear the depth/stencil
surface before drawing. However, in case of the smaller render target that
wouldn't be a full clear, so we'd have to do a depth copy if we also switched
between onscreen and offscreen rendering. Keeping track of which part of the
depth/stencil surface is current for onscreen/offscreen allows us to avoid
most of these kinds of copies. The current scheme requires the current/dirty
rectangle to have an origin at (0,0). This could be extended to an arbitrary
rectangle, but the bookkeeping becomes somewhat more complex in that case, and
it's not clear that there would be much of a benefit at this point.
---
 dlls/wined3d/arb_program_shader.c |   78 +++++++++++++++++++++++++++++------
 dlls/wined3d/device.c             |   70 ++++++++++++++++++++++++++++---
 dlls/wined3d/drawprim.c           |   23 +++++++++-
 dlls/wined3d/glsl_shader.c        |   83 +++++++++++++++++++++++++++++++------
 dlls/wined3d/shader.c             |    2 +-
 dlls/wined3d/surface.c            |   21 ++++++++--
 dlls/wined3d/swapchain.c          |    4 +-
 dlls/wined3d/wined3d_private.h    |    6 ++-
 8 files changed, 243 insertions(+), 44 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index db4324d..f0db9cf 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -287,7 +287,8 @@ struct shader_arb_priv
     const struct arb_ps_compiled_shader *compiled_fprog;
     const struct arb_vs_compiled_shader *compiled_vprog;
     GLuint                  depth_blt_vprogram_id;
-    GLuint                  depth_blt_fprogram_id[tex_type_count];
+    GLuint                  depth_blt_fprogram_id_full[tex_type_count];
+    GLuint                  depth_blt_fprogram_id_masked[tex_type_count];
     BOOL                    use_arbfp_fixed_func;
     struct wine_rb_tree     fragment_shaders;
     BOOL                    last_ps_const_clamped;
@@ -3103,12 +3104,14 @@ static GLuint create_arb_blt_vertex_program(const struct wined3d_gl_info *gl_inf
 }
 
 /* GL locking is done by the caller */
-static GLuint create_arb_blt_fragment_program(const struct wined3d_gl_info *gl_info, enum tex_types tex_type)
+static GLuint create_arb_blt_fragment_program(const struct wined3d_gl_info *gl_info,
+        enum tex_types tex_type, BOOL masked)
 {
     GLuint program_id = 0;
+    const char *fprogram;
     GLint pos;
 
-    static const char * const blt_fprograms[tex_type_count] =
+    static const char * const blt_fprograms_full[tex_type_count] =
     {
         /* tex_1d */
         NULL,
@@ -3134,7 +3137,46 @@ static GLuint create_arb_blt_fragment_program(const struct wined3d_gl_info *gl_i
         "END\n",
     };
 
-    if (!blt_fprograms[tex_type])
+    static const char * const blt_fprograms_masked[tex_type_count] =
+    {
+        /* tex_1d */
+        NULL,
+        /* tex_2d */
+        "!!ARBfp1.0\n"
+        "PARAM mask = program.local[0];\n"
+        "TEMP R0;\n"
+        "SLT R0.xy, fragment.position, mask.zwzw;\n"
+        "MUL R0.x, R0.x, R0.y;\n"
+        "KIL -R0.x;\n"
+        "TEX R0.x, fragment.texcoord[0], texture[0], 2D;\n"
+        "MOV result.depth.z, R0.x;\n"
+        "END\n",
+        /* tex_3d */
+        NULL,
+        /* tex_cube */
+        "!!ARBfp1.0\n"
+        "PARAM mask = program.local[0];\n"
+        "TEMP R0;\n"
+        "SLT R0.xy, fragment.position, mask.zwzw;\n"
+        "MUL R0.x, R0.x, R0.y;\n"
+        "KIL -R0.x;\n"
+        "TEX R0.x, fragment.texcoord[0], texture[0], CUBE;\n"
+        "MOV result.depth.z, R0.x;\n"
+        "END\n",
+        /* tex_rect */
+        "!!ARBfp1.0\n"
+        "PARAM mask = program.local[0];\n"
+        "TEMP R0;\n"
+        "SLT R0.xy, fragment.position, mask.zwzw;\n"
+        "MUL R0.x, R0.x, R0.y;\n"
+        "KIL -R0.x;\n"
+        "TEX R0.x, fragment.texcoord[0], texture[0], RECT;\n"
+        "MOV result.depth.z, R0.x;\n"
+        "END\n",
+    };
+
+    fprogram = masked ? blt_fprograms_masked[tex_type] : blt_fprograms_full[tex_type];
+    if (!fprogram)
     {
         FIXME("tex_type %#x not supported\n", tex_type);
         tex_type = tex_2d;
@@ -3142,8 +3184,7 @@ static GLuint create_arb_blt_fragment_program(const struct wined3d_gl_info *gl_i
 
     GL_EXTCALL(glGenProgramsARB(1, &program_id));
     GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program_id));
-    GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
-            strlen(blt_fprograms[tex_type]), blt_fprograms[tex_type]));
+    GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fprogram), fprogram));
     checkGLcall("glProgramStringARB()");
 
     glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
@@ -3151,7 +3192,7 @@ static GLuint create_arb_blt_fragment_program(const struct wined3d_gl_info *gl_i
     {
         FIXME("Fragment program error at position %d: %s\n\n", pos,
             debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
-        shader_arb_dump_program_source(blt_fprograms[tex_type]);
+        shader_arb_dump_program_source(fprogram);
     }
     else
     {
@@ -4444,18 +4485,23 @@ static void shader_arb_select(const struct wined3d_context *context, BOOL usePS,
 }
 
 /* GL locking is done by the caller */
-static void shader_arb_select_depth_blt(IWineD3DDevice *iface, enum tex_types tex_type) {
+static void shader_arb_select_depth_blt(IWineD3DDevice *iface, enum tex_types tex_type, const SIZE *ds_mask_size)
+{
+    const float mask[] = {0.0f, 0.0f, (float)ds_mask_size->cx, (float)ds_mask_size->cy};
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    BOOL masked = ds_mask_size->cx && ds_mask_size->cy;
     struct shader_arb_priv *priv = This->shader_priv;
-    GLuint *blt_fprogram = &priv->depth_blt_fprogram_id[tex_type];
     const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
+    GLuint *blt_fprogram;
 
     if (!priv->depth_blt_vprogram_id) priv->depth_blt_vprogram_id = create_arb_blt_vertex_program(gl_info);
     GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->depth_blt_vprogram_id));
     glEnable(GL_VERTEX_PROGRAM_ARB);
 
-    if (!*blt_fprogram) *blt_fprogram = create_arb_blt_fragment_program(gl_info, tex_type);
+    blt_fprogram = masked ? &priv->depth_blt_fprogram_id_masked[tex_type] : &priv->depth_blt_fprogram_id_full[tex_type];
+    if (!*blt_fprogram) *blt_fprogram = create_arb_blt_fragment_program(gl_info, tex_type, masked);
     GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, *blt_fprogram));
+    if (masked) GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, mask));
     glEnable(GL_FRAGMENT_PROGRAM_ARB);
 }
 
@@ -4595,9 +4641,15 @@ static void shader_arb_free(IWineD3DDevice *iface) {
     if(priv->depth_blt_vprogram_id) {
         GL_EXTCALL(glDeleteProgramsARB(1, &priv->depth_blt_vprogram_id));
     }
-    for (i = 0; i < tex_type_count; ++i) {
-        if (priv->depth_blt_fprogram_id[i]) {
-            GL_EXTCALL(glDeleteProgramsARB(1, &priv->depth_blt_fprogram_id[i]));
+    for (i = 0; i < tex_type_count; ++i)
+    {
+        if (priv->depth_blt_fprogram_id_full[i])
+        {
+            GL_EXTCALL(glDeleteProgramsARB(1, &priv->depth_blt_fprogram_id_full[i]));
+        }
+        if (priv->depth_blt_fprogram_id_masked[i])
+        {
+            GL_EXTCALL(glDeleteProgramsARB(1, &priv->depth_blt_fprogram_id_masked[i]));
         }
     }
     LEAVE_GL();
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index f285053..20c509d 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -563,7 +563,7 @@ void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *c
     device->contexts = new_array;
 }
 
-static void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
+void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
 {
     IWineD3DStateBlockImpl *stateblock = device->stateBlock;
     WINED3DVIEWPORT *vp = &stateblock->viewport;
@@ -582,7 +582,9 @@ void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
     if (device->onscreen_depth_stencil)
     {
         surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
-        surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN);
+        surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
+                device->onscreen_depth_stencil->ds_current_size.cx,
+                device->onscreen_depth_stencil->ds_current_size.cy);
         IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
     }
     device->onscreen_depth_stencil = depth_stencil;
@@ -4371,6 +4373,61 @@ static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, co
     return TRUE;
 }
 
+static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
+        DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
+{
+    RECT current_rect, r;
+
+    if (ds->Flags & location)
+        SetRect(&current_rect, 0, 0,
+                ds->ds_current_size.cx,
+                ds->ds_current_size.cy);
+    else
+        SetRectEmpty(&current_rect);
+
+    IntersectRect(&r, draw_rect, &current_rect);
+    if (EqualRect(&r, draw_rect))
+    {
+        /* current_rect ⊇ draw_rect, modify only. */
+        surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
+        return;
+    }
+
+    if (EqualRect(&r, &current_rect))
+    {
+        /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
+
+        if (!clear_rect)
+        {
+            /* Full clear, modify only. */
+            surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
+            return;
+        }
+
+        if (rect_count > 1)
+        {
+            /* Multiple clear rects, full load. Strictly speaking this can
+             * also be a full draw_rect clear, but it's probably rare enough
+             * that we don't care. */
+            surface_load_ds_location(ds, context, location);
+            surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
+            return;
+        }
+
+        IntersectRect(&r, draw_rect, clear_rect);
+        if (EqualRect(&r, draw_rect))
+        {
+            /* clear_rect ⊇ draw_rect, modify only. */
+            surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
+            return;
+        }
+    }
+
+    /* Full load. */
+    surface_load_ds_location(ds, context, location);
+    surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
+}
+
 /* Not called from the VTable (internal subroutine) */
 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
         const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
@@ -4456,10 +4513,7 @@ HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfac
 
         if (location == SFLAG_DS_ONSCREEN && depth_stencil != This->onscreen_depth_stencil)
             device_switch_onscreen_ds(This, context, depth_stencil);
-
-        if (!(depth_stencil->Flags & location) && !is_full_clear(depth_stencil, &draw_rect, clear_rect))
-            surface_load_ds_location(depth_stencil, context, location);
-        surface_modify_ds_location(depth_stencil, location);
+        prepare_ds_clear(depth_stencil, context, location, &draw_rect, Count, clear_rect);
 
         glDepthMask(GL_TRUE);
         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
@@ -5941,7 +5995,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *
         if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
                 || This->depth_stencil->Flags & SFLAG_DISCARD)
         {
-            surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED);
+            surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
+                    This->depth_stencil->currentDesc.Width,
+                    This->depth_stencil->currentDesc.Height);
             if (This->depth_stencil == This->onscreen_depth_stencil)
             {
                 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 146d73a..5f88f4e 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -613,12 +613,29 @@ void drawPrimitive(IWineD3DDevice *iface, UINT index_count, UINT StartIdx, UINT
         if (This->stateBlock->renderState[WINED3DRS_ZWRITEENABLE]
                 || This->stateBlock->renderState[WINED3DRS_ZENABLE])
         {
+            RECT current_rect, draw_rect, r;
+
             if (location == SFLAG_DS_ONSCREEN && This->depth_stencil != This->onscreen_depth_stencil)
                 device_switch_onscreen_ds(This, context, This->depth_stencil);
-            surface_load_ds_location(This->depth_stencil, context, location);
+
+            if (This->depth_stencil->Flags & location)
+                SetRect(&current_rect, 0, 0,
+                        This->depth_stencil->ds_current_size.cx,
+                        This->depth_stencil->ds_current_size.cy);
+            else
+                SetRectEmpty(&current_rect);
+
+            device_get_draw_rect(This, &draw_rect);
+
+            IntersectRect(&r, &draw_rect, &current_rect);
+            if (!EqualRect(&r, &draw_rect))
+                surface_load_ds_location(This->depth_stencil, context, location);
+
+            if (This->stateBlock->renderState[WINED3DRS_ZWRITEENABLE])
+                surface_modify_ds_location(This->depth_stencil, location,
+                        This->depth_stencil->ds_current_size.cx,
+                        This->depth_stencil->ds_current_size.cy);
         }
-        if (This->stateBlock->renderState[WINED3DRS_ZWRITEENABLE])
-            surface_modify_ds_location(This->depth_stencil, location);
     }
 
     /* Ok, we will be updating the screen from here onwards so grab the lock */
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 7648d15..aca9d0e 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -89,7 +89,8 @@ struct shader_glsl_priv {
     struct constant_heap vconst_heap;
     struct constant_heap pconst_heap;
     unsigned char *stack;
-    GLhandleARB depth_blt_program[tex_type_count];
+    GLhandleARB depth_blt_program_full[tex_type_count];
+    GLhandleARB depth_blt_program_masked[tex_type_count];
     UINT next_constant_version;
 };
 
@@ -4463,10 +4464,12 @@ static void set_glsl_shader_program(const struct wined3d_context *context,
 }
 
 /* GL locking is done by the caller */
-static GLhandleARB create_glsl_blt_shader(const struct wined3d_gl_info *gl_info, enum tex_types tex_type)
+static GLhandleARB create_glsl_blt_shader(const struct wined3d_gl_info *gl_info, enum tex_types tex_type, BOOL masked)
 {
     GLhandleARB program_id;
     GLhandleARB vshader_id, pshader_id;
+    const char *blt_pshader;
+
     static const char *blt_vshader[] =
     {
         "#version 120\n"
@@ -4478,7 +4481,7 @@ static GLhandleARB create_glsl_blt_shader(const struct wined3d_gl_info *gl_info,
         "}\n"
     };
 
-    static const char *blt_pshaders[tex_type_count] =
+    static const char *blt_pshaders_full[tex_type_count] =
     {
         /* tex_1d */
         NULL,
@@ -4508,7 +4511,44 @@ static GLhandleARB create_glsl_blt_shader(const struct wined3d_gl_info *gl_info,
         "}\n",
     };
 
-    if (!blt_pshaders[tex_type])
+    static const char *blt_pshaders_masked[tex_type_count] =
+    {
+        /* tex_1d */
+        NULL,
+        /* tex_2d */
+        "#version 120\n"
+        "uniform sampler2D sampler;\n"
+        "uniform vec4 mask;\n"
+        "void main(void)\n"
+        "{\n"
+        "    if (all(lessThan(gl_FragCoord.xy, mask.zw))) discard;\n"
+        "    gl_FragDepth = texture2D(sampler, gl_TexCoord[0].xy).x;\n"
+        "}\n",
+        /* tex_3d */
+        NULL,
+        /* tex_cube */
+        "#version 120\n"
+        "uniform samplerCube sampler;\n"
+        "uniform vec4 mask;\n"
+        "void main(void)\n"
+        "{\n"
+        "    if (all(lessThan(gl_FragCoord.xy, mask.zw))) discard;\n"
+        "    gl_FragDepth = textureCube(sampler, gl_TexCoord[0].xyz).x;\n"
+        "}\n",
+        /* tex_rect */
+        "#version 120\n"
+        "#extension GL_ARB_texture_rectangle : enable\n"
+        "uniform sampler2DRect sampler;\n"
+        "uniform vec4 mask;\n"
+        "void main(void)\n"
+        "{\n"
+        "    if (all(lessThan(gl_FragCoord.xy, mask.zw))) discard;\n"
+        "    gl_FragDepth = texture2DRect(sampler, gl_TexCoord[0].xy).x;\n"
+        "}\n",
+    };
+
+    blt_pshader = masked ? blt_pshaders_masked[tex_type] : blt_pshaders_full[tex_type];
+    if (!blt_pshader)
     {
         FIXME("tex_type %#x not supported\n", tex_type);
         tex_type = tex_2d;
@@ -4519,7 +4559,7 @@ static GLhandleARB create_glsl_blt_shader(const struct wined3d_gl_info *gl_info,
     GL_EXTCALL(glCompileShaderARB(vshader_id));
 
     pshader_id = GL_EXTCALL(glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB));
-    GL_EXTCALL(glShaderSourceARB(pshader_id, 1, &blt_pshaders[tex_type], NULL));
+    GL_EXTCALL(glShaderSourceARB(pshader_id, 1, &blt_pshader, NULL));
     GL_EXTCALL(glCompileShaderARB(pshader_id));
 
     program_id = GL_EXTCALL(glCreateProgramObjectARB());
@@ -4581,21 +4621,34 @@ static void shader_glsl_select(const struct wined3d_context *context, BOOL usePS
 }
 
 /* GL locking is done by the caller */
-static void shader_glsl_select_depth_blt(IWineD3DDevice *iface, enum tex_types tex_type) {
+static void shader_glsl_select_depth_blt(IWineD3DDevice *iface,
+        enum tex_types tex_type, const SIZE *ds_mask_size)
+{
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
     const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
+    BOOL masked = ds_mask_size->cx && ds_mask_size->cy;
     struct shader_glsl_priv *priv = This->shader_priv;
-    GLhandleARB *blt_program = &priv->depth_blt_program[tex_type];
+    GLhandleARB *blt_program;
+    GLint loc;
 
-    if (!*blt_program) {
-        GLint loc;
-        *blt_program = create_glsl_blt_shader(gl_info, tex_type);
+    blt_program = masked ? &priv->depth_blt_program_masked[tex_type] : &priv->depth_blt_program_full[tex_type];
+    if (!*blt_program)
+    {
+        *blt_program = create_glsl_blt_shader(gl_info, tex_type, masked);
         loc = GL_EXTCALL(glGetUniformLocationARB(*blt_program, "sampler"));
         GL_EXTCALL(glUseProgramObjectARB(*blt_program));
         GL_EXTCALL(glUniform1iARB(loc, 0));
-    } else {
+    }
+    else
+    {
         GL_EXTCALL(glUseProgramObjectARB(*blt_program));
     }
+
+    if (masked)
+    {
+        loc = GL_EXTCALL(glGetUniformLocationARB(*blt_program, "mask"));
+        GL_EXTCALL(glUniform4fARB(loc, 0.0f, 0.0f, (float)ds_mask_size->cx, (float)ds_mask_size->cy));
+    }
 }
 
 /* GL locking is done by the caller */
@@ -4831,9 +4884,13 @@ static void shader_glsl_free(IWineD3DDevice *iface) {
     ENTER_GL();
     for (i = 0; i < tex_type_count; ++i)
     {
-        if (priv->depth_blt_program[i])
+        if (priv->depth_blt_program_full[i])
+        {
+            GL_EXTCALL(glDeleteObjectARB(priv->depth_blt_program_full[i]));
+        }
+        if (priv->depth_blt_program_masked[i])
         {
-            GL_EXTCALL(glDeleteObjectARB(priv->depth_blt_program[i]));
+            GL_EXTCALL(glDeleteObjectARB(priv->depth_blt_program_masked[i]));
         }
     }
     LEAVE_GL();
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index 6836532..b015178 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -1403,7 +1403,7 @@ static void shader_cleanup(IWineD3DBaseShader *iface)
 
 static void shader_none_handle_instruction(const struct wined3d_shader_instruction *ins) {}
 static void shader_none_select(const struct wined3d_context *context, BOOL usePS, BOOL useVS) {}
-static void shader_none_select_depth_blt(IWineD3DDevice *iface, enum tex_types tex_type) {}
+static void shader_none_select_depth_blt(IWineD3DDevice *iface, enum tex_types tex_type, const SIZE *ds_mask_size) {}
 static void shader_none_deselect_depth_blt(IWineD3DDevice *iface) {}
 static void shader_none_update_float_vertex_constants(IWineD3DDevice *iface, UINT start, UINT count) {}
 static void shader_none_update_float_pixel_constants(IWineD3DDevice *iface, UINT start, UINT count) {}
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 8a934a8..6ec3ed9 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -4092,7 +4092,8 @@ static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl
     glGetIntegerv(info.binding, &old_binding);
     glBindTexture(info.bind_target, texture);
 
-    device->shader_backend->shader_select_depth_blt((IWineD3DDevice *)device, info.tex_type);
+    device->shader_backend->shader_select_depth_blt((IWineD3DDevice *)device,
+            info.tex_type, &This->ds_current_size);
 
     glBegin(GL_TRIANGLE_STRIP);
     glTexCoord3fv(info.coords[0]);
@@ -4112,13 +4113,16 @@ static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl
     device->shader_backend->shader_deselect_depth_blt((IWineD3DDevice *)device);
 }
 
-void surface_modify_ds_location(IWineD3DSurfaceImpl *surface, DWORD location)
+void surface_modify_ds_location(IWineD3DSurfaceImpl *surface,
+        DWORD location, UINT w, UINT h)
 {
-    TRACE("surface %p, new location %#x.\n", surface, location);
+    TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
 
     if (location & ~SFLAG_DS_LOCATIONS)
         FIXME("Invalid location (%#x) specified.\n", location);
 
+    surface->ds_current_size.cx = w;
+    surface->ds_current_size.cy = h;
     surface->Flags &= ~SFLAG_DS_LOCATIONS;
     surface->Flags |= location;
 }
@@ -4134,7 +4138,14 @@ void surface_load_ds_location(IWineD3DSurfaceImpl *surface, struct wined3d_conte
     /* TODO: Make this work for modes other than FBO */
     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
 
-    if (surface->Flags & location)
+    if (!(surface->Flags & location))
+    {
+        surface->ds_current_size.cx = 0;
+        surface->ds_current_size.cy = 0;
+    }
+
+    if (surface->ds_current_size.cx == surface->currentDesc.Width
+            && surface->ds_current_size.cy == surface->currentDesc.Height)
     {
         TRACE("Location (%#x) is already up to date.\n", location);
         return;
@@ -4250,6 +4261,8 @@ void surface_load_ds_location(IWineD3DSurfaceImpl *surface, struct wined3d_conte
     }
 
     surface->Flags |= location;
+    surface->ds_current_size.cx = surface->currentDesc.Width;
+    surface->ds_current_size.cy = surface->currentDesc.Height;
 }
 
 static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) {
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index e1cb2ad..a7b6a70 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -468,7 +468,9 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO
         if (This->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
                 || This->device->depth_stencil->Flags & SFLAG_DISCARD)
         {
-            surface_modify_ds_location(This->device->depth_stencil, SFLAG_DS_DISCARDED);
+            surface_modify_ds_location(This->device->depth_stencil, SFLAG_DS_DISCARDED,
+                    This->device->depth_stencil->currentDesc.Width,
+                    This->device->depth_stencil->currentDesc.Height);
             if (This->device->depth_stencil == This->device->onscreen_depth_stencil)
             {
                 IWineD3DSurface_Release((IWineD3DSurface *)This->device->onscreen_depth_stencil);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 3e54ad8..c2e17b1 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -713,7 +713,7 @@ struct wined3d_context;
 typedef struct {
     void (*shader_handle_instruction)(const struct wined3d_shader_instruction *);
     void (*shader_select)(const struct wined3d_context *context, BOOL usePS, BOOL useVS);
-    void (*shader_select_depth_blt)(IWineD3DDevice *iface, enum tex_types tex_type);
+    void (*shader_select_depth_blt)(IWineD3DDevice *iface, enum tex_types tex_type, const SIZE *ds_mask_size);
     void (*shader_deselect_depth_blt)(IWineD3DDevice *iface);
     void (*shader_update_float_vertex_constants)(IWineD3DDevice *iface, UINT start, UINT count);
     void (*shader_update_float_pixel_constants)(IWineD3DDevice *iface, UINT start, UINT count);
@@ -1725,6 +1725,7 @@ struct IWineD3DDeviceImpl
 
 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context) DECLSPEC_HIDDEN;
 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context) DECLSPEC_HIDDEN;
+void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect) DECLSPEC_HIDDEN;
 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
         UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
         IUnknown *parent, IWineD3DDeviceParent *device_parent) DECLSPEC_HIDDEN;
@@ -2090,6 +2091,7 @@ struct IWineD3DSurfaceImpl
 
     struct list               renderbuffers;
     renderbuffer_entry_t      *current_renderbuffer;
+    SIZE ds_current_size;
 
     /* DirectDraw clippers */
     IWineD3DClipper           *clipper;
@@ -2677,7 +2679,7 @@ void surface_add_dirty_rect(IWineD3DSurfaceImpl *surface, const RECT *dirty_rect
 GLenum surface_get_gl_buffer(IWineD3DSurfaceImpl *surface) DECLSPEC_HIDDEN;
 void surface_load_ds_location(IWineD3DSurfaceImpl *surface,
         struct wined3d_context *context, DWORD location) DECLSPEC_HIDDEN;
-void surface_modify_ds_location(IWineD3DSurfaceImpl *surface, DWORD location) DECLSPEC_HIDDEN;
+void surface_modify_ds_location(IWineD3DSurfaceImpl *surface, DWORD location, UINT w, UINT h) DECLSPEC_HIDDEN;
 void surface_set_compatible_renderbuffer(IWineD3DSurfaceImpl *surface,
         unsigned int width, unsigned int height) DECLSPEC_HIDDEN;
 void surface_set_texture_name(IWineD3DSurfaceImpl *surface, GLuint name, BOOL srgb_name) DECLSPEC_HIDDEN;
-- 
1.6.4.4




More information about the wine-patches mailing list