"Implement" is somewhat debatable, as it works currently with both Mesa and NVidia blob drivers. However, we're not following the spec.
Based on a patch by Michael Müller.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/wined3d/context.c | 2 ++ dlls/wined3d/glsl_shader.c | 19 ++++++++++++++++--- dlls/wined3d/shader.c | 2 ++ dlls/wined3d/state.c | 27 +++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 9 ++++++--- 5 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index d9e3dfaa50..633d5176ba 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -3444,6 +3444,8 @@ static uint32_t find_draw_buffers_mask(const struct wined3d_context_gl *context_
rt_mask = ps ? ps->reg_maps.rt_mask : 1; rt_mask &= (1u << gl_info->limits.buffers) - 1; + if (state->blend_state && state->blend_state->dual_source) + rt_mask = 1;
mask = rt_mask; while (mask) diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 4a2fbce553..2c2ba33488 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -7772,7 +7772,10 @@ static GLuint shader_glsl_generate_fragment_shader(const struct wined3d_context_ { const struct wined3d_shader_signature *output_signature = &shader->output_signature;
- shader_addline(buffer, "vec4 ps_out[%u];\n", gl_info->limits.buffers); + if (args->dual_source_blend) + shader_addline(buffer, "vec4 ps_out[2];\n"); + else + shader_addline(buffer, "vec4 ps_out[%u];\n", gl_info->limits.buffers); if (output_signature->element_count) { for (i = 0; i < output_signature->element_count; ++i) @@ -7787,7 +7790,12 @@ static GLuint shader_glsl_generate_fragment_shader(const struct wined3d_context_ continue; } if (shader_glsl_use_explicit_attrib_location(gl_info)) - shader_addline(buffer, "layout(location = %u) ", output->semantic_idx); + { + if (args->dual_source_blend) + shader_addline(buffer, "layout(location = 0, index = %u) ", output->semantic_idx); + else + shader_addline(buffer, "layout(location = %u) ", output->semantic_idx); + } shader_addline(buffer, "out %s4 color_out%u;\n", component_type_info[output->component_type].glsl_vector_type, output->semantic_idx); } @@ -7800,7 +7808,12 @@ static GLuint shader_glsl_generate_fragment_shader(const struct wined3d_context_ { i = wined3d_bit_scan(&mask); if (shader_glsl_use_explicit_attrib_location(gl_info)) - shader_addline(buffer, "layout(location = %u) ", i); + { + if (args->dual_source_blend) + shader_addline(buffer, "layout(location = 0, index = %u) ", i); + else + shader_addline(buffer, "layout(location = %u) ", i); + } shader_addline(buffer, "out vec4 color_out%u;\n", i); } } diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index d9ef1a96e2..3e2a756757 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -4167,6 +4167,8 @@ void find_ps_compile_args(const struct wined3d_state *state, const struct wined3 if (rtv && rtv->format->id == WINED3DFMT_A8_UNORM && !is_identity_fixup(rtv->format->color_fixup)) args->rt_alpha_swizzle |= 1u << i; } + + args->dual_source_blend = state->blend_state && state->blend_state->dual_source; }
static HRESULT pixel_shader_init(struct wined3d_shader *shader, struct wined3d_device *device, diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index 6289317936..fb55bfe0f3 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -74,6 +74,11 @@ void * CDECL wined3d_blend_state_get_parent(const struct wined3d_blend_state *st return state->parent; }
+static BOOL is_dual_source(enum wined3d_blend state) +{ + return state >= WINED3D_BLEND_SRC1COLOR && state <= WINED3D_BLEND_INVSRC1ALPHA; +} + HRESULT CDECL wined3d_blend_state_create(struct wined3d_device *device, const struct wined3d_blend_state_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_blend_state **state) @@ -92,6 +97,12 @@ HRESULT CDECL wined3d_blend_state_create(struct wined3d_device *device, object->parent_ops = parent_ops; object->device = device;
+ object->dual_source = desc->rt[0].enable + && (is_dual_source(desc->rt[0].src) + || is_dual_source(desc->rt[0].dst) + || is_dual_source(desc->rt[0].src_alpha) + || is_dual_source(desc->rt[0].dst_alpha)); + TRACE("Created blend state %p.\n", object); *state = object;
@@ -650,6 +661,7 @@ static void blend_db2(struct wined3d_context *context, const struct wined3d_stat GLenum src_blend, dst_blend, src_blend_alpha, dst_blend_alpha; const struct wined3d_blend_state *b = state->blend_state; const struct wined3d_format *rt_format; + BOOL dual_source = b && b->dual_source; unsigned int i;
if (b && b->desc.alpha_to_coverage) @@ -658,6 +670,13 @@ static void blend_db2(struct wined3d_context *context, const struct wined3d_stat gl_info->gl_ops.gl.p_glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); checkGLcall("glEnable GL_SAMPLE_ALPHA_TO_COVERAGE");
+ if (context->last_was_dual_source_blend != dual_source) + { + /* Dual source blending changes the location of the output varyings. */ + context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL; + context->last_was_dual_source_blend = dual_source; + } + if (!b || !b->desc.independent) { blend(context, state, state_id); @@ -708,6 +727,7 @@ static void blend_dbb(struct wined3d_context *context, const struct wined3d_stat { const struct wined3d_gl_info *gl_info = wined3d_context_gl(context)->gl_info; const struct wined3d_blend_state *b = state->blend_state; + BOOL dual_source = b && b->dual_source; unsigned int i;
if (b && b->desc.alpha_to_coverage) @@ -716,6 +736,13 @@ static void blend_dbb(struct wined3d_context *context, const struct wined3d_stat gl_info->gl_ops.gl.p_glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); checkGLcall("glEnable GL_SAMPLE_ALPHA_TO_COVERAGE");
+ if (context->last_was_dual_source_blend != dual_source) + { + /* Dual source blending changes the location of the output varyings. */ + context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL; + context->last_was_dual_source_blend = dual_source; + } + if (!b || !b->desc.independent) { blend(context, state, state_id); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 9240b0e455..f8ee3c6446 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1394,7 +1394,8 @@ struct ps_compile_args DWORD alpha_test_func : 3; DWORD render_offscreen : 1; DWORD rt_alpha_swizzle : 8; /* MAX_RENDER_TARGET_VIEWS, 8 */ - DWORD padding : 18; + DWORD dual_source_blend : 1; + DWORD padding : 17; };
enum fog_src_type @@ -1954,7 +1955,7 @@ struct wined3d_context DWORD last_was_ffp_blit : 1; DWORD last_was_blit : 1; DWORD last_was_ckey : 1; - DWORD namedArraysLoaded : 1; + DWORD last_was_dual_source_blend : 1; DWORD texShaderBumpMap : 8; /* WINED3D_MAX_TEXTURES, 8 */ DWORD lastWasPow2Texture : 8; /* WINED3D_MAX_TEXTURES, 8 */ DWORD fixed_function_usage_map : 8; /* WINED3D_MAX_TEXTURES, 8 */ @@ -1971,7 +1972,8 @@ struct wined3d_context DWORD destroyed : 1; DWORD destroy_delayed : 1; DWORD clip_distance_mask : 8; /* WINED3D_MAX_CLIP_DISTANCES, 8 */ - DWORD padding : 14; + DWORD namedArraysLoaded : 1; + DWORD padding : 13;
DWORD constant_update_mask; DWORD numbered_array_mask; @@ -3140,6 +3142,7 @@ struct wined3d_blend_state { LONG refcount; struct wined3d_blend_state_desc desc; + BOOL dual_source;
void *parent; const struct wined3d_parent_ops *parent_ops;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/d3d10core/tests/d3d10core.c | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
diff --git a/dlls/d3d10core/tests/d3d10core.c b/dlls/d3d10core/tests/d3d10core.c index e84b4a47b5..ed0e4f1217 100644 --- a/dlls/d3d10core/tests/d3d10core.c +++ b/dlls/d3d10core/tests/d3d10core.c @@ -18287,6 +18287,73 @@ static void test_independent_blend(void) release_test_context(&test_context); }
+static void test_dual_source_blend(void) +{ + struct d3d10core_test_context test_context; + ID3D10BlendState *blend_state; + D3D10_BLEND_DESC blend_desc; + ID3D10PixelShader *ps; + ID3D10Device *device; + DWORD color; + HRESULT hr; + + static const DWORD ps_code[] = + { +#if 0 + void main(float4 position : SV_Position, + out float4 t0 : SV_Target0, out float4 t1 : SV_Target1) + { + t0 = float4(0.5, 0.5, 0.0, 1.0); + t1 = float4(0.0, 0.5, 0.5, 0.0); + } +#endif + 0x43425844, 0x87120d01, 0xa0014738, 0x3a32d86c, 0x9d757441, 0x00000001, 0x00000118, 0x00000003, + 0x0000002c, 0x00000060, 0x000000ac, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, + 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x505f5653, 0x7469736f, 0x006e6f69, + 0x4e47534f, 0x00000044, 0x00000002, 0x00000008, 0x00000038, 0x00000000, 0x00000000, 0x00000003, + 0x00000000, 0x0000000f, 0x00000038, 0x00000001, 0x00000000, 0x00000003, 0x00000001, 0x0000000f, + 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x00000064, 0x00000040, 0x00000019, 0x03000065, + 0x001020f2, 0x00000000, 0x03000065, 0x001020f2, 0x00000001, 0x08000036, 0x001020f2, 0x00000000, + 0x00004002, 0x3f000000, 0x3f000000, 0x00000000, 0x3f000000, 0x08000036, 0x001020f2, 0x00000001, + 0x00004002, 0x00000000, 0x3f000000, 0x3f000000, 0x00000000, 0x0100003e + }; + + static const float clear_color[] = {0.7f, 0.0f, 1.0f, 1.0f}; + + if (!init_test_context(&test_context)) + return; + + device = test_context.device; + + hr = ID3D10Device_CreatePixelShader(device, ps_code, sizeof(ps_code), &ps); + ok(SUCCEEDED(hr), "Failed to create pixel shader, hr %#x.\n", hr); + ID3D10Device_PSSetShader(device, ps); + + memset(&blend_desc, 0, sizeof(blend_desc)); + blend_desc.BlendEnable[0] = TRUE; + blend_desc.SrcBlend = D3D10_BLEND_SRC1_COLOR; + blend_desc.DestBlend = D3D10_BLEND_SRC1_COLOR; + blend_desc.BlendOp = D3D10_BLEND_OP_ADD; + blend_desc.SrcBlendAlpha = D3D10_BLEND_ONE; + blend_desc.DestBlendAlpha = D3D10_BLEND_ZERO; + blend_desc.BlendOpAlpha = D3D10_BLEND_OP_ADD; + blend_desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL; + + hr = ID3D10Device_CreateBlendState(device, &blend_desc, &blend_state); + ok(hr == S_OK, "Failed to create blend state, hr %#x.\n", hr); + ID3D10Device_OMSetBlendState(device, blend_state, NULL, D3D10_DEFAULT_SAMPLE_MASK); + + ID3D10Device_ClearRenderTargetView(device, test_context.backbuffer_rtv, clear_color); + draw_quad(&test_context); + + color = get_texture_color(test_context.backbuffer, 320, 240); + ok(compare_color(color, 0x80804000, 1), "Got unexpected color 0x%08x.\n", color); + + ID3D10BlendState_Release(blend_state); + ID3D10PixelShader_Release(ps); + release_test_context(&test_context); +} + START_TEST(d3d10core) { unsigned int argc, i; @@ -18407,6 +18474,7 @@ START_TEST(d3d10core) queue_test(test_desktop_window); queue_test(test_color_mask); queue_test(test_independent_blend); + queue_test(test_dual_source_blend);
run_queued_tests();
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/d3d11/tests/d3d11.c | 71 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+)
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index 0a076ef67d..812eaf698a 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -29994,6 +29994,76 @@ static void test_independent_blend(void) release_test_context(&test_context); }
+static void test_dual_source_blend(void) +{ + struct d3d11_test_context test_context; + ID3D11BlendState *blend_state; + ID3D11DeviceContext *context; + ID3D11PixelShader *ps; + ID3D11Device *device; + DWORD color; + HRESULT hr; + + static const DWORD ps_code[] = + { +#if 0 + void main(float4 position : SV_Position, + out float4 t0 : SV_Target0, out float4 t1 : SV_Target1) + { + t0 = float4(0.5, 0.5, 0.0, 1.0); + t1 = float4(0.0, 0.5, 0.5, 0.0); + } +#endif + 0x43425844, 0x87120d01, 0xa0014738, 0x3a32d86c, 0x9d757441, 0x00000001, 0x00000118, 0x00000003, + 0x0000002c, 0x00000060, 0x000000ac, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, + 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x505f5653, 0x7469736f, 0x006e6f69, + 0x4e47534f, 0x00000044, 0x00000002, 0x00000008, 0x00000038, 0x00000000, 0x00000000, 0x00000003, + 0x00000000, 0x0000000f, 0x00000038, 0x00000001, 0x00000000, 0x00000003, 0x00000001, 0x0000000f, + 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x00000064, 0x00000040, 0x00000019, 0x03000065, + 0x001020f2, 0x00000000, 0x03000065, 0x001020f2, 0x00000001, 0x08000036, 0x001020f2, 0x00000000, + 0x00004002, 0x3f000000, 0x3f000000, 0x00000000, 0x3f000000, 0x08000036, 0x001020f2, 0x00000001, + 0x00004002, 0x00000000, 0x3f000000, 0x3f000000, 0x00000000, 0x0100003e + }; + + static const D3D11_BLEND_DESC blend_desc = + { + .RenderTarget[0].BlendEnable = TRUE, + .RenderTarget[0].SrcBlend = D3D11_BLEND_SRC1_COLOR, + .RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_COLOR, + .RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD, + .RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE, + .RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO, + .RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD, + .RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL, + }; + + static const float clear_color[] = {0.7f, 0.0f, 1.0f, 1.0f}; + + if (!init_test_context(&test_context, NULL)) + return; + + device = test_context.device; + context = test_context.immediate_context; + + hr = ID3D11Device_CreatePixelShader(device, ps_code, sizeof(ps_code), NULL, &ps); + ok(hr == S_OK, "Failed to create pixel shader, hr %#x.\n", hr); + ID3D11DeviceContext_PSSetShader(context, ps, NULL, 0); + + hr = ID3D11Device_CreateBlendState(device, &blend_desc, &blend_state); + ok(hr == S_OK, "Failed to create blend state, hr %#x.\n", hr); + ID3D11DeviceContext_OMSetBlendState(context, blend_state, NULL, D3D11_DEFAULT_SAMPLE_MASK); + ID3D11BlendState_Release(blend_state); + + ID3D11DeviceContext_ClearRenderTargetView(context, test_context.backbuffer_rtv, clear_color); + draw_quad(&test_context); + + color = get_texture_color(test_context.backbuffer, 320, 240); + ok(compare_color(color, 0x80804000, 1), "Got unexpected color 0x%08x.\n", color); + + ID3D11PixelShader_Release(ps); + release_test_context(&test_context); +} + START_TEST(d3d11) { unsigned int argc, i; @@ -30156,6 +30226,7 @@ START_TEST(d3d11) queue_test(test_sample_attached_rtv); queue_test(test_color_mask); queue_test(test_independent_blend); + queue_test(test_dual_source_blend);
run_queued_tests(); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=67389
Your paranoid android.
=== w1064v1809_he (32 bit report) ===
d3d11: d3d11.c:5776: Test failed: Got unexpected IAVertices count: 0. d3d11.c:5777: Test failed: Got unexpected IAPrimitives count: 0. d3d11.c:5778: Test failed: Got unexpected VSInvocations count: 0. d3d11.c:5781: Test failed: Got unexpected CInvocations count: 0. d3d11.c:5782: Test failed: Got unexpected CPrimitives count: 0.
=== w2008s64 (64 bit report) ===
d3d11: d3d11.c:5776: Test failed: Got unexpected IAVertices count: 1. d3d11.c:5777: Test failed: Got unexpected IAPrimitives count: 1. d3d11.c:5778: Test failed: Got unexpected VSInvocations count: 16. d3d11.c:5779: Test failed: Got unexpected GSInvocations count: 1. d3d11.c:5780: Test failed: Got unexpected GSPrimitives count: 1. d3d11.c:5781: Test failed: Got unexpected CInvocations count: 1. d3d11.c:5784: Test failed: Got unexpected PSInvocations count: 1. d3d11.c:6106: Test failed: Got unexpected NumPrimitivesWritten: 4285164192. d3d11.c:6109: Test failed: Got unexpected PrimitivesStorageNeeded: 4294967295.