Implement dual source blending in wined3d Accepted

Revisions: 

Revision 1

user image Michael Müller Author
18 Aug. 17

The assignment of draw buffers differs between Direct3d11 and OpenGL when dual blending is active. D3D11 simply interprets SV_TARGET1 as the second color (instead of the second render target), when dual blending is enabled. OpenGL distinguishes between the two cases and requires (layout = 0, index =1) instead of (layout = 1). The current behavior is therefore broken and the set of patches fixes the problem by re-compiling the shader based on the currently active blending mode.

Single files Merged diff Tar archive
You have unsaved changes. Press CTRL + ENTER in a text field to submit your comments.

0001-wined3d-Unroll-glsl-pixel-shader-output.patch

From e0eb96965bae5852ae8d8a483dce20508bfc1564 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Fri, 18 Aug 2017 19:55:37 +0200
Subject: wined3d: Unroll glsl pixel shader output.
---
dlls/wined3d/glsl_shader.c | 58 ++++++++++++++++++++++++++--------------------
1 file changed, 33 insertions(+), 25 deletions(-)
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 0f2f3052ec..02f9fc1c7d 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -2142,11 +2142,6 @@ static void shader_glsl_declare_shader_outputs(const struct wined3d_gl_info *gl_
declare_out_varying(gl_info, buffer, FALSE, "vec4 ps_link[%u];\n", element_count);
}
-static const char *get_fragment_output(const struct wined3d_gl_info *gl_info)
-{
- return needs_legacy_glsl_syntax(gl_info) ? "gl_FragData" : "ps_out";
-}
-
static const char *glsl_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)
{
switch (primitive_type)
@@ -2904,7 +2899,8 @@ static void shader_glsl_get_register_name(const struct wined3d_shader_register *
WARN("Write to render target %u, only %d supported.\n",
reg->idx[0].offset, gl_info->limits.buffers);
- sprintf(register_name, "%s[%u]", get_fragment_output(gl_info), reg->idx[0].offset);
+ sprintf(register_name, needs_legacy_glsl_syntax(gl_info) ? "gl_FragData[%u]" : "ps_out%u",
+ reg->idx[0].offset);
break;
case WINED3DSPR_RASTOUT:
@@ -7153,20 +7149,20 @@ static void shader_glsl_generate_patch_constant_setup(struct wined3d_string_buff
static void shader_glsl_generate_srgb_write_correction(struct wined3d_string_buffer *buffer,
const struct wined3d_gl_info *gl_info)
{
- const char *output = get_fragment_output(gl_info);
+ const char *output = needs_legacy_glsl_syntax(gl_info) ? "gl_FragData[0]" : "ps_out0";
- shader_addline(buffer, "tmp0.xyz = pow(%s[0].xyz, vec3(srgb_const0.x));\n", output);
+ shader_addline(buffer, "tmp0.xyz = pow(%s.xyz, vec3(srgb_const0.x));\n", output);
shader_addline(buffer, "tmp0.xyz = tmp0.xyz * vec3(srgb_const0.y) - vec3(srgb_const0.z);\n");
- shader_addline(buffer, "tmp1.xyz = %s[0].xyz * vec3(srgb_const0.w);\n", output);
- shader_addline(buffer, "bvec3 srgb_compare = lessThan(%s[0].xyz, vec3(srgb_const1.x));\n", output);
- shader_addline(buffer, "%s[0].xyz = mix(tmp0.xyz, tmp1.xyz, vec3(srgb_compare));\n", output);
- shader_addline(buffer, "%s[0] = clamp(%s[0], 0.0, 1.0);\n", output, output);
+ shader_addline(buffer, "tmp1.xyz = %s.xyz * vec3(srgb_const0.w);\n", output);
+ shader_addline(buffer, "bvec3 srgb_compare = lessThan(%s.xyz, vec3(srgb_const1.x));\n", output);
+ shader_addline(buffer, "%s.xyz = mix(tmp0.xyz, tmp1.xyz, vec3(srgb_compare));\n", output);
+ shader_addline(buffer, "%s = clamp(%s, 0.0, 1.0);\n", output, output);
}
static void shader_glsl_generate_fog_code(struct wined3d_string_buffer *buffer,
const struct wined3d_gl_info *gl_info, enum wined3d_ffp_ps_fog_mode mode)
{
- const char *output = get_fragment_output(gl_info);
+ const char *output = needs_legacy_glsl_syntax(gl_info) ? "gl_FragData[0]" : "ps_out0";
switch (mode)
{
@@ -7191,13 +7187,15 @@ static void shader_glsl_generate_fog_code(struct wined3d_string_buffer *buffer,
return;
}
- shader_addline(buffer, "%s[0].xyz = mix(ffp_fog.color.xyz, %s[0].xyz, clamp(fog, 0.0, 1.0));\n",
+ shader_addline(buffer, "%s.xyz = mix(ffp_fog.color.xyz, %s.xyz, clamp(fog, 0.0, 1.0));\n",
output, output);
}
static void shader_glsl_generate_alpha_test(struct wined3d_string_buffer *buffer,
const struct wined3d_gl_info *gl_info, enum wined3d_cmp_func alpha_func)
{
+ const char *output = needs_legacy_glsl_syntax(gl_info) ? "gl_FragData[0]" : "ps_out0";
+
/* alpha_func is the PASS condition, not the DISCARD condition. Instead of
* flipping all the operators here, just negate the comparison below. */
static const char * const comparison_operator[] =
@@ -7216,8 +7214,8 @@ static void shader_glsl_generate_alpha_test(struct wined3d_string_buffer *buffer
return;
if (alpha_func != WINED3D_CMP_NEVER)
- shader_addline(buffer, "if (!(%s[0].a %s alpha_test_ref))\n",
- get_fragment_output(gl_info), comparison_operator[alpha_func - WINED3D_CMP_NEVER]);
+ shader_addline(buffer, "if (!(%s.a %s alpha_test_ref))\n",
+ output, comparison_operator[alpha_func - WINED3D_CMP_NEVER]);
shader_addline(buffer, " discard;\n");
}
@@ -7259,10 +7257,11 @@ static void shader_glsl_generate_ps_epilogue(const struct wined3d_gl_info *gl_in
const struct ps_compile_args *args)
{
const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps;
+ const char *output = needs_legacy_glsl_syntax(gl_info) ? "gl_FragData[0]" : "ps_out0";
/* Pixel shaders < 2.0 place the resulting color in R0 implicitly. */
if (reg_maps->shader_version.major < 2)
- shader_addline(buffer, "%s[0] = R0;\n", get_fragment_output(gl_info));
+ shader_addline(buffer, "%s = R0;\n", output);
if (args->srgb_correction)
shader_glsl_generate_srgb_write_correction(buffer, gl_info);
@@ -7451,9 +7450,12 @@ static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context
if (!needs_legacy_glsl_syntax(gl_info))
{
- if (shader_glsl_use_explicit_attrib_location(gl_info))
- shader_addline(buffer, "layout(location = 0) ");
- shader_addline(buffer, "out vec4 ps_out[%u];\n", gl_info->limits.buffers);
+ for (i = 0; i < gl_info->limits.buffers; i++)
+ {
+ if (shader_glsl_use_explicit_attrib_location(gl_info))
+ shader_addline(buffer, "layout(location = %u) ", i);
+ shader_addline(buffer, "out vec4 ps_out%u;\n", i);
+ }
}
if (shader->limits->constant_float + extra_constants_needed >= gl_info->limits.glsl_ps_float_constants)
@@ -9017,6 +9019,7 @@ static void shader_glsl_ffp_fragment_op(struct wined3d_string_buffer *buffer, un
static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *priv,
const struct ffp_frag_settings *settings, const struct wined3d_context *context)
{
+ const char *output = needs_legacy_glsl_syntax(context->gl_info) ? "gl_FragData[0]" : "ps_out0";
struct wined3d_string_buffer *tex_reg_name = string_buffer_get(&priv->string_buffers);
enum wined3d_cmp_func alpha_test_func = settings->alpha_test_func + 1;
struct wined3d_string_buffer *buffer = &priv->shader_buffer;
@@ -9105,7 +9108,7 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *
{
if (shader_glsl_use_explicit_attrib_location(gl_info))
shader_addline(buffer, "layout(location = 0) ");
- shader_addline(buffer, "out vec4 ps_out[1];\n");
+ shader_addline(buffer, "out vec4 ps_out0;\n");
}
shader_addline(buffer, "vec4 tmp0, tmp1;\n");
@@ -9436,8 +9439,7 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *
}
}
- shader_addline(buffer, "%s[0] = ffp_varying_specular * specular_enable + ret;\n",
- get_fragment_output(gl_info));
+ shader_addline(buffer, "%s = ffp_varying_specular * specular_enable + ret;\n", output);
if (settings->sRGB_write)
shader_glsl_generate_srgb_write_correction(buffer, gl_info);
@@ -9981,8 +9983,14 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
if (!needs_legacy_glsl_syntax(gl_info))
{
- GL_EXTCALL(glBindFragDataLocation(program_id, 0, "ps_out"));
- checkGLcall("glBindFragDataLocation");
+ for (i = 0; i < gl_info->limits.buffers; i++)
+ {
+ char var[12];
+
+ sprintf(var, "ps_out%u", i);
+ GL_EXTCALL(glBindFragDataLocation(program_id, i, var));
+ checkGLcall("glBindFragDataLocation");
+ }
}
}
--
2.13.2

0002-d3d11-tests-Add-basic-dual-source-blend-test.patch

From c12d216cec1aae4a7308a13eabbb31145c71e4a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Fri, 18 Aug 2017 23:22:16 +0200
Subject: d3d11/tests: Add basic dual source blend test.
---
dlls/d3d11/tests/d3d11.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 169 insertions(+)
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index e3314cec26..6e460d1bf3 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -21902,6 +21902,174 @@ static void test_early_depth_stencil(void)
release_test_context(&test_context);
}
+static void test_dual_blending(void)
+{
+ struct d3d11_test_context test_context;
+ D3D11_TEXTURE2D_DESC texture_desc;
+ ID3D11Texture2D *render_target;
+ ID3D11RenderTargetView *rtv[2];
+ ID3D11BlendState *blend_state;
+ ID3D11DeviceContext *context;
+ ID3D11VertexShader *vs;
+ ID3D11PixelShader *ps;
+ D3D11_BLEND_DESC desc;
+ ID3D11Device *device;
+ HRESULT hr;
+
+ static const DWORD vs_code[] =
+ {
+#if 0
+ struct output
+ {
+ float4 position : SV_PoSiTion;
+ float4 color0 : COLOR0;
+ float4 color1 : COLOR1;
+ };
+
+ void main(uint id : SV_VertexID, out output o)
+ {
+ float2 coords = float2((id << 1) & 2, id & 2);
+ o.position = float4(coords * float2(2, -2) + float2(-1, 1), 0, 1);
+ o.color0 = float4(1.0f, 0.0f, 0.0f, 1.0f);
+ o.color1 = float4(0.0f, 1.0f, 0.0f, 1.0f);
+ }
+#endif
+ 0x43425844, 0x93c216a1, 0xbaa7e8d4, 0xd5368c6a, 0x4e889e07, 0x00000001, 0x00000224, 0x00000003,
+ 0x0000002c, 0x00000060, 0x000000cc, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
+ 0x00000000, 0x00000006, 0x00000001, 0x00000000, 0x00000101, 0x565f5653, 0x65747265, 0x00444978,
+ 0x4e47534f, 0x00000064, 0x00000003, 0x00000008, 0x00000050, 0x00000000, 0x00000001, 0x00000003,
+ 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x0000000f,
+ 0x0000005c, 0x00000001, 0x00000000, 0x00000003, 0x00000002, 0x0000000f, 0x505f5653, 0x5469536f,
+ 0x006e6f69, 0x4f4c4f43, 0xabab0052, 0x52444853, 0x00000150, 0x00010040, 0x00000054, 0x04000060,
+ 0x00101012, 0x00000000, 0x00000006, 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x03000065,
+ 0x001020f2, 0x00000001, 0x03000065, 0x001020f2, 0x00000002, 0x02000068, 0x00000001, 0x07000029,
+ 0x00100012, 0x00000000, 0x0010100a, 0x00000000, 0x00004001, 0x00000001, 0x07000001, 0x00100012,
+ 0x00000000, 0x0010000a, 0x00000000, 0x00004001, 0x00000002, 0x07000001, 0x00100042, 0x00000000,
+ 0x0010100a, 0x00000000, 0x00004001, 0x00000002, 0x05000056, 0x00100032, 0x00000000, 0x00100086,
+ 0x00000000, 0x0f000032, 0x00102032, 0x00000000, 0x00100046, 0x00000000, 0x00004002, 0x40000000,
+ 0xc0000000, 0x00000000, 0x00000000, 0x00004002, 0xbf800000, 0x3f800000, 0x00000000, 0x00000000,
+ 0x08000036, 0x001020c2, 0x00000000, 0x00004002, 0x00000000, 0x00000000, 0x00000000, 0x3f800000,
+ 0x08000036, 0x001020f2, 0x00000001, 0x00004002, 0x3f800000, 0x00000000, 0x00000000, 0x3f800000,
+ 0x08000036, 0x001020f2, 0x00000002, 0x00004002, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000,
+ 0x0100003e,
+ };
+ static const DWORD ps_code[] =
+ {
+#if 0
+ struct input
+ {
+ float4 position : SV_PoSiTiOn;
+ float4 color1 : COLOR1;
+ float4 color0 : COLOR0;
+ };
+
+ struct output
+ {
+ float4 target0 : SV_Target0;
+ float4 target1 : SV_Target1;
+ };
+
+ void main(const in input i, out output o)
+ {
+ o.target0 = i.color0;
+ o.target1 = i.color1;
+ }
+#endif
+ 0x43425844, 0x620ef963, 0xed8f19fe, 0x7b3a0a53, 0x126ce021, 0x00000001, 0x00000150, 0x00000003,
+ 0x0000002c, 0x00000098, 0x000000e4, 0x4e475349, 0x00000064, 0x00000003, 0x00000008, 0x00000050,
+ 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000001, 0x00000000,
+ 0x00000003, 0x00000001, 0x00000f0f, 0x0000005c, 0x00000000, 0x00000000, 0x00000003, 0x00000002,
+ 0x00000f0f, 0x505f5653, 0x5469536f, 0x006e4f69, 0x4f4c4f43, 0xabab0052, 0x4e47534f, 0x00000044,
+ 0x00000002, 0x00000008, 0x00000038, 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x0000000f,
+ 0x00000038, 0x00000001, 0x00000000, 0x00000003, 0x00000001, 0x0000000f, 0x545f5653, 0x65677261,
+ 0xabab0074, 0x52444853, 0x00000064, 0x00000040, 0x00000019, 0x03001062, 0x001010f2, 0x00000001,
+ 0x03001062, 0x001010f2, 0x00000002, 0x03000065, 0x001020f2, 0x00000000, 0x03000065, 0x001020f2,
+ 0x00000001, 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000002, 0x05000036, 0x001020f2,
+ 0x00000001, 0x00101e46, 0x00000001, 0x0100003e,
+ };
+
+ static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ if (!init_test_context(&test_context, NULL))
+ return;
+
+ device = test_context.device;
+ context = test_context.immediate_context;
+
+ hr = ID3D11Device_CreateVertexShader(device, vs_code, sizeof(vs_code), NULL, &vs);
+ ok(SUCCEEDED(hr), "Failed to create vertex shader, hr %#x.\n", hr);
+ hr = ID3D11Device_CreatePixelShader(device, ps_code, sizeof(ps_code), NULL, &ps);
+ ok(SUCCEEDED(hr), "Failed to create pixel shader, hr %#x.\n", hr);
+
+ ID3D11Texture2D_GetDesc(test_context.backbuffer, &texture_desc);
+ hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &render_target);
+ ok(SUCCEEDED(hr), "Failed to create texture, hr %#x.\n", hr);
+
+ rtv[0] = test_context.backbuffer_rtv;
+ hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)render_target, NULL, &rtv[1]);
+ ok(SUCCEEDED(hr), "Failed to create render target view, hr %#x.\n", hr);
+
+ ID3D11DeviceContext_VSSetShader(context, vs, NULL, 0);
+ ID3D11DeviceContext_PSSetShader(context, ps, NULL, 0);
+ ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ ID3D11DeviceContext_OMSetRenderTargets(context, 2, rtv, NULL);
+
+ ID3D11DeviceContext_ClearRenderTargetView(context, rtv[0], white);
+ ID3D11DeviceContext_ClearRenderTargetView(context, rtv[1], white);
+ ID3D11DeviceContext_Draw(context, 3, 0);
+
+ check_texture_color(test_context.backbuffer, 0xff00ff00, 0);
+ check_texture_color(render_target, 0xff0000ff, 0);
+
+ memset(&desc, 0, sizeof(desc));
+ desc.AlphaToCoverageEnable = FALSE;
+ desc.IndependentBlendEnable = FALSE;
+ desc.RenderTarget[0].BlendEnable = TRUE;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_COLOR;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_COLOR;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC1_ALPHA;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+
+ hr = ID3D11Device_CreateBlendState(device, &desc, &blend_state);
+ ok(SUCCEEDED(hr), "Failed to create blend state, hr %#x.\n", hr);
+
+ ID3D11DeviceContext_OMSetBlendState(context, blend_state, NULL, D3D11_DEFAULT_SAMPLE_MASK);
+ ID3D11DeviceContext_ClearRenderTargetView(context, rtv[0], white);
+ ID3D11DeviceContext_ClearRenderTargetView(context, rtv[1], white);
+ ID3D11DeviceContext_Draw(context, 3, 0);
+
+ todo_wine check_texture_color(test_context.backbuffer, 0xff00ffff, 0);
+ todo_wine check_texture_color(render_target, 0xff0000ff, 0);
+
+ ID3D11BlendState_Release(blend_state);
+
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
+ hr = ID3D11Device_CreateBlendState(device, &desc, &blend_state);
+ ok(SUCCEEDED(hr), "Failed to create blend state, hr %#x.\n", hr);
+
+ ID3D11DeviceContext_OMSetBlendState(context, blend_state, NULL, D3D11_DEFAULT_SAMPLE_MASK);
+ ID3D11DeviceContext_ClearRenderTargetView(context, rtv[0], white);
+ ID3D11DeviceContext_ClearRenderTargetView(context, rtv[1], white);
+ ID3D11DeviceContext_Draw(context, 3, 0);
+
+ check_texture_color(test_context.backbuffer, 0xff00ff00, 0);
+ check_texture_color(render_target, 0xff0000ff, 0);
+
+ ID3D11BlendState_Release(blend_state);
+
+ ID3D11RenderTargetView_Release(rtv[1]);
+ ID3D11Texture2D_Release(render_target);
+ ID3D11PixelShader_Release(ps);
+ ID3D11VertexShader_Release(vs);
+ release_test_context(&test_context);
+}
+
START_TEST(d3d11)
{
test_create_device();
@@ -22004,4 +22172,5 @@ START_TEST(d3d11)
test_fractional_viewports();
test_negative_viewports();
test_early_depth_stencil();
+ test_dual_blending();
}
--
2.13.2

0003-wined3d-Implement-dual-source-blending.patch (2 comments)

From 0b0b810b5861e68adc83f67b1024129c143c2c9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Fri, 18 Aug 2017 23:51:59 +0200
Subject: wined3d: Implement dual source blending.
---
dlls/d3d11/tests/d3d11.c | 2 +-
dlls/wined3d/context.c | 10 +++++++++-
dlls/wined3d/directx.c | 10 ++++++++++
dlls/wined3d/glsl_shader.c | 45 ++++++++++++++++++++++++++++++++----------
dlls/wined3d/shader.c | 2 ++
dlls/wined3d/state.c | 5 +++++
dlls/wined3d/wined3d_private.h | 26 ++++++++++++++++++++++--
7 files changed, 86 insertions(+), 14 deletions(-)
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index 6e460d1bf3..f3ab33222c 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -22041,7 +22041,7 @@ static void test_dual_blending(void)
ID3D11DeviceContext_ClearRenderTargetView(context, rtv[1], white);
ID3D11DeviceContext_Draw(context, 3, 0);
- todo_wine check_texture_color(test_context.backbuffer, 0xff00ffff, 0);
+ check_texture_color(test_context.backbuffer, 0xff00ffff, 0);
todo_wine check_texture_color(render_target, 0xff0000ff, 0);
ID3D11BlendState_Release(blend_state);
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index e3951c1a0a..ebf1752065 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -3046,8 +3046,16 @@ static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const
else if (!context->render_offscreen)
return context_generate_rt_mask_from_resource(rts[0]->resource);
+ /* If we attach more buffers than supported in dual blend mode, the NVIDIA
+ * driver generates the following error:
+ * GL_INVALID_OPERATION error generated. State(s) are invalid: blend.
+ * DX11 does not treat this configuration as invalid, so disable the unused ones.
+ */
rt_mask = ps ? ps->reg_maps.rt_mask : 1;
- rt_mask &= context->d3d_info->valid_rt_mask;
+ if (wined3d_dualblend_enabled(state, context->gl_info))
+ rt_mask &= context->d3d_info->valid_dual_rt_mask;
+ else
+ rt_mask &= context->d3d_info->valid_rt_mask;
rt_mask_bits = rt_mask;
i = 0;
while (rt_mask_bits)
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 22c09e2e02..33c0e3dc65 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -3525,6 +3525,12 @@ static void wined3d_adapter_init_limits(struct wined3d_gl_info *gl_info)
gl_info->limits.buffers = gl_max;
TRACE("Max draw buffers: %u.\n", gl_max);
}
+ if (gl_info->supported[ARB_BLEND_FUNC_EXTENDED])
+ {
+ gl_info->gl_ops.gl.p_glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &gl_max);
+ gl_info->limits.dual_buffers = gl_max;
+ TRACE("Max draw dual source buffers: %u.\n", gl_max);
+ }
if (gl_info->supported[ARB_MULTITEXTURE])
{
if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
@@ -4288,6 +4294,10 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter,
for (i = 0; i < gl_info->limits.buffers; ++i)
adapter->d3d_info.valid_rt_mask |= (1u << i);
+ adapter->d3d_info.valid_dual_rt_mask = 0;
+ for (i = 0; i < gl_info->limits.dual_buffers; ++i)
+ adapter->d3d_info.valid_dual_rt_mask |= (1u << i);
+
if (!adapter->d3d_info.shader_color_key)
{
/* We do not want to deal with re-creating immutable texture storage for color keying emulation. */
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 02f9fc1c7d..19d70a37c3 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -2895,6 +2895,7 @@ static void shader_glsl_get_register_name(const struct wined3d_shader_register *
break;
case WINED3DSPR_COLOROUT:
+ /* FIXME: should check dual_buffers when dual blending is enabled */
if (reg->idx[0].offset >= gl_info->limits.buffers)
WARN("Write to render target %u, only %d supported.\n",
reg->idx[0].offset, gl_info->limits.buffers);
@@ -7450,11 +7451,23 @@ static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context
if (!needs_legacy_glsl_syntax(gl_info))
{
- for (i = 0; i < gl_info->limits.buffers; i++)
+ if (args->dual_source_blend && gl_info->supported[ARB_BLEND_FUNC_EXTENDED])
{
- if (shader_glsl_use_explicit_attrib_location(gl_info))
- shader_addline(buffer, "layout(location = %u) ", i);
- shader_addline(buffer, "out vec4 ps_out%u;\n", i);
+ for (i = 0; i < gl_info->limits.dual_buffers * 2; i++)
+ {
+ if (shader_glsl_use_explicit_attrib_location(gl_info))
+ shader_addline(buffer, "layout(location = %u, index = %u) ", i / 2, i % 2);
+ shader_addline(buffer, "out vec4 ps_out%u;\n", i);
+ }
+ }
+ else
+ {
+ for (i = 0; i < gl_info->limits.buffers; i++)
+ {
+ if (shader_glsl_use_explicit_attrib_location(gl_info))
+ shader_addline(buffer, "layout(location = %u) ", i);
+ shader_addline(buffer, "out vec4 ps_out%u;\n", i);
+ }
}
}
@@ -9983,13 +9996,25 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
if (!needs_legacy_glsl_syntax(gl_info))
{
- for (i = 0; i < gl_info->limits.buffers; i++)
- {
- char var[12];
+ char var[12];
- sprintf(var, "ps_out%u", i);
- GL_EXTCALL(glBindFragDataLocation(program_id, i, var));
- checkGLcall("glBindFragDataLocation");
+ if (wined3d_dualblend_enabled(state, gl_info))
+ {
+ for (i = 0; i < gl_info->limits.dual_buffers * 2; i++)
+ {
+ sprintf(var, "ps_out%u", i);
+ GL_EXTCALL(glBindFragDataLocationIndexed(program_id, i / 2, i % 2, var));
+ checkGLcall("glBindFragDataLocation");
+ }
+ }
+ else
+ {
+ for (i = 0; i < gl_info->limits.buffers; i++)
+ {
+ sprintf(var, "ps_out%u", i);
+ GL_EXTCALL(glBindFragDataLocation(program_id, i, var));
+ checkGLcall("glBindFragDataLocation");
+ }
}
}
}
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index dd39d7f65e..ad0002b57d 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -3935,6 +3935,8 @@ void find_ps_compile_args(const struct wined3d_state *state, const struct wined3
args->render_offscreen = shader->reg_maps.vpos && gl_info->supported[ARB_FRAGMENT_COORD_CONVENTIONS]
? context->render_offscreen : 0;
+
+ args->dual_source_blend = wined3d_dualblend_enabled(state, gl_info);
}
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 4424da4e85..b81dbdc421 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -530,6 +530,11 @@ static void state_blend(struct wined3d_context *context, const struct wined3d_st
checkGLcall("glBlendFunc");
}
+ /* dual state blending changes the assignment of the output variables */
+ if (context->last_was_dual_blend != wined3d_dualblend_enabled(state, context->gl_info))
+ context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL;
+ context->last_was_dual_blend = wined3d_dualblend_enabled(state, context->gl_info);
+
/* Colorkey fixup for stage 0 alphaop depends on
* WINED3D_RS_ALPHABLENDENABLE state, so it may need updating. */
if (state->render_states[WINED3D_RS_COLORKEYENABLE])
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index d561d5bf7f..3da303a57d 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -191,6 +191,7 @@ struct wined3d_d3d_info
BOOL vs_clipping;
BOOL shader_color_key;
DWORD valid_rt_mask;
+ DWORD valid_dual_rt_mask;
DWORD wined3d_creation_flags;
BOOL shader_double_precision;
};
@@ -1340,7 +1341,8 @@ struct ps_compile_args {
DWORD flatshading : 1;
DWORD alpha_test_func : 3;
DWORD render_offscreen : 1;
- DWORD padding : 26;
+ DWORD dual_source_blend : 1;
+ DWORD padding : 25;
};
enum fog_src_type {
@@ -1887,7 +1889,8 @@ struct wined3d_context
DWORD destroy_delayed : 1;
DWORD transform_feedback_active : 1;
DWORD transform_feedback_paused : 1;
- DWORD padding : 7;
+ DWORD last_was_dual_blend : 1;
+ DWORD padding : 6;
DWORD last_swizzle_map; /* MAX_ATTRIBS, 16 */
DWORD shader_update_mask;
DWORD constant_update_mask;
@@ -2489,6 +2492,7 @@ struct wined3d_fbo_ops
struct wined3d_gl_limits
{
UINT buffers;
+ UINT dual_buffers;
UINT lights;
UINT textures;
UINT texture_coords;
@@ -2823,6 +2827,24 @@ struct wined3d_state
struct wined3d_rasterizer_state *rasterizer_state;
};
+static inline BOOL wined3d_dualblend_enabled(const struct wined3d_state *state, const struct wined3d_gl_info *gl_info)
+{
+ if (!gl_info->supported[ARB_BLEND_FUNC_EXTENDED]) return FALSE;
+
user image Michael Müller Author
19 Aug. 17

Please insert if (!state->render_states[WINED3D_RS_ALPHABLENDENABLE]) return FALSE; here before applying the patch

+#define IS_DUAL_SOURCE_BLEND(x) ((x) >= WINED3D_BLEND_SRC1COLOR && (x) <= WINED3D_BLEND_INVSRC1ALPHA)
+ if (IS_DUAL_SOURCE_BLEND(state->render_states[WINED3D_RS_SRCBLEND])) return TRUE;
+ if (IS_DUAL_SOURCE_BLEND(state->render_states[WINED3D_RS_DESTBLEND])) return TRUE;
+
+ if (state->render_states[WINED3D_RS_ALPHABLENDENABLE])
user image Michael Müller Author
19 Aug. 17

... and remove this check ;-)

+ {
+ if (IS_DUAL_SOURCE_BLEND(state->render_states[WINED3D_RS_SRCBLENDALPHA])) return TRUE;
+ if (IS_DUAL_SOURCE_BLEND(state->render_states[WINED3D_RS_DESTBLENDALPHA])) return TRUE;
+ }
+#undef IS_DUAL_SOURCE_BLEND
+
+ return FALSE;
+}
+
#if defined(STAGING_CSMT)
struct wined3d_gl_bo
{
--
2.13.2