Henri Verbeet : wined3d: Mask out writes to unused render targets.

Alexandre Julliard julliard at winehq.org
Wed May 25 11:28:13 CDT 2011


Module: wine
Branch: master
Commit: 019f6a8534d49cf92e8c819a4fda33a5ab4c1ca1
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=019f6a8534d49cf92e8c819a4fda33a5ab4c1ca1

Author: Henri Verbeet <hverbeet at codeweavers.com>
Date:   Tue May 24 22:24:12 2011 +0200

wined3d: Mask out writes to unused render targets.

Outputs not written by the pixel shader are undefined in GL, but in D3D the
render target is unmodified.

---

 dlls/wined3d/arb_program_shader.c |    4 ++--
 dlls/wined3d/context.c            |   30 ++++++++++++++++++++++--------
 dlls/wined3d/device.c             |    3 +++
 dlls/wined3d/shader.c             |    7 ++++++-
 dlls/wined3d/wined3d_private.h    |    4 +++-
 5 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index 55b31bc..cefb6e5 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -1118,7 +1118,7 @@ static void shader_arb_get_register_name(const struct wined3d_shader_instruction
             else
             {
                 if(ctx->cur_ps_args->super.srgb_correction) FIXME("sRGB correction on higher render targets\n");
-                if (reg_maps->highest_render_target > 0)
+                if (reg_maps->rt_mask > 1)
                 {
                     sprintf(register_name, "result.color[%u]", reg->idx);
                 }
@@ -3615,7 +3615,7 @@ static GLuint shader_arb_generate_pshader(struct wined3d_shader *shader,
         priv_ctx.target_version = ARB;
     }
 
-    if (reg_maps->highest_render_target > 0)
+    if (reg_maps->rt_mask > 1)
     {
         shader_addline(buffer, "OPTION ARB_draw_buffers;\n");
     }
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 5def575..f5d237e 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -1977,9 +1977,9 @@ static struct wined3d_context *FindContext(struct wined3d_device *device, struct
 }
 
 /* Context activation is done by the caller. */
-static void context_apply_draw_buffers(struct wined3d_context *context, UINT rt_count, struct wined3d_surface **rts)
+static void context_apply_draw_buffers(struct wined3d_context *context, DWORD rt_mask, struct wined3d_surface **rts)
 {
-    if (!rt_count)
+    if (!rt_mask)
     {
         ENTER_GL();
         glDrawBuffer(GL_NONE);
@@ -1999,19 +1999,22 @@ static void context_apply_draw_buffers(struct wined3d_context *context, UINT rt_
         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
         {
             const struct wined3d_gl_info *gl_info = context->gl_info;
-            unsigned int i;
+            unsigned int i = 0;
 
-            for (i = 0; i < rt_count; ++i)
+            while (rt_mask)
             {
-                if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
+                if ((rt_mask & 1) && rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
                     context->draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i;
                 else
                     context->draw_buffers[i] = GL_NONE;
+
+                rt_mask >>= 1;
+                ++i;
             }
 
             if (gl_info->supported[ARB_DRAW_BUFFERS])
             {
-                GL_EXTCALL(glDrawBuffersARB(rt_count, context->draw_buffers));
+                GL_EXTCALL(glDrawBuffersARB(i, context->draw_buffers));
                 checkGLcall("glDrawBuffers()");
             }
             else
@@ -2153,6 +2156,7 @@ BOOL context_apply_clear_state(struct wined3d_context *context, struct wined3d_d
         UINT rt_count, struct wined3d_surface **rts, struct wined3d_surface *depth_stencil)
 {
     const struct StateEntry *state_table = device->StateTable;
+    DWORD rt_mask = 0;
     UINT i;
 
     if (!context_validate_rt_config(rt_count, rts, depth_stencil))
@@ -2170,6 +2174,7 @@ BOOL context_apply_clear_state(struct wined3d_context *context, struct wined3d_d
             for (i = 0; i < rt_count; ++i)
             {
                 context->blit_targets[i] = rts[i];
+                rt_mask |= (1 << i);
             }
             while (i < context->gl_info->limits.buffers)
             {
@@ -2183,12 +2188,17 @@ BOOL context_apply_clear_state(struct wined3d_context *context, struct wined3d_d
         else
         {
             context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
+            rt_mask = 1;
         }
 
         LEAVE_GL();
     }
+    else
+    {
+        rt_mask = 1;
+    }
 
-    context_apply_draw_buffers(context, rt_count, rts);
+    context_apply_draw_buffers(context, rt_mask, rts);
     context->draw_buffer_dirty = TRUE;
 
     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
@@ -2261,7 +2271,11 @@ BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_de
 
     if (context->draw_buffer_dirty)
     {
-        context_apply_draw_buffers(context, context->gl_info->limits.buffers, fb->render_targets);
+        const struct wined3d_shader *ps = device->stateBlock->state.pixel_shader;
+        DWORD rt_mask = ps ? ps->reg_maps.rt_mask : 1;
+
+        rt_mask &= device->valid_rt_mask;
+        context_apply_draw_buffers(context, rt_mask, fb->render_targets);
         context->draw_buffer_dirty = FALSE;
     }
 
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index ab40d18..8724cdf 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1166,6 +1166,9 @@ HRESULT CDECL wined3d_device_init_3d(struct wined3d_device *device,
     device->updateStateBlock = device->stateBlock;
     wined3d_stateblock_incref(device->updateStateBlock);
 
+    device->valid_rt_mask = 0;
+    for (i = 0; i < gl_info->limits.buffers; ++i)
+        device->valid_rt_mask |= (1 << i);
     device->fb.render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
             sizeof(*device->fb.render_targets) * gl_info->limits.buffers);
 
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index f5c45f3..79a2759 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -418,7 +418,7 @@ static void shader_record_register_usage(struct wined3d_shader *shader, struct w
             break;
 
         case WINED3DSPR_COLOROUT:
-            reg_maps->highest_render_target = max(reg_maps->highest_render_target, reg->idx);
+            reg_maps->rt_mask |= (1 << reg->idx);
             break;
 
         default:
@@ -821,6 +821,11 @@ static HRESULT shader_get_registers_used(struct wined3d_shader *shader, const st
     }
     reg_maps->loop_depth = max_loop_depth;
 
+    /* PS before 2.0 don't have explicit color outputs. Instead the value of
+     * R0 is written to the render target. */
+    if (shader_version.major < 2 && shader_version.type == WINED3D_SHADER_TYPE_PIXEL)
+        reg_maps->rt_mask |= (1 << 0);
+
     shader->functionLength = ((const char *)ptr - (const char *)byte_code);
 
     return WINED3D_OK;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 43481ae..5ac7ee4 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -560,9 +560,10 @@ struct wined3d_shader_reg_maps
     WORD usespow        : 1;
     WORD padding        : 3;
 
+    DWORD rt_mask; /* Used render targets, 32 max. */
+
     /* Whether or not loops are used in this shader, and nesting depth */
     unsigned loop_depth;
-    unsigned highest_render_target;
     UINT min_rel_offset, max_rel_offset;
 };
 
@@ -1716,6 +1717,7 @@ struct wined3d_device
     unsigned int            highest_dirty_ps_const, highest_dirty_vs_const;
 
     /* Render Target Support */
+    DWORD valid_rt_mask;
     struct wined3d_fb_state fb;
     struct wined3d_surface *onscreen_depth_stencil;
     struct wined3d_surface *auto_depth_stencil;




More information about the wine-cvs mailing list