Module: wine Branch: master Commit: 019f6a8534d49cf92e8c819a4fda33a5ab4c1ca1 URL: http://source.winehq.org/git/wine.git/?a=commit;h=019f6a8534d49cf92e8c819a4f...
Author: Henri Verbeet hverbeet@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;