From: Henri Verbeet Subject: [PATCH 4/5] wined3d: Implement support for per-stage texture stage constants. Message-Id: <1398256522-19049-4-git-send-email-hverbeet@codeweavers.com> Date: Wed, 23 Apr 2014 14:35:21 +0200 This patch is loosely based on an earlier patch by Christian Costa. --- dlls/d3d9/tests/visual.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ dlls/wined3d/glsl_shader.c | 49 +++++++++++---- 2 files changed, 179 insertions(+), 11 deletions(-) diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index a055f59..71f6835 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -16407,6 +16407,146 @@ static void add_dirty_rect_test(void) DestroyWindow(window); } +static void test_per_stage_constant(void) +{ + IDirect3DDevice9 *device; + IDirect3D9 *d3d; + D3DCOLOR color; + ULONG refcount; + D3DCAPS9 caps; + HWND window; + HRESULT hr; + + static const struct + { + struct vec3 position; + D3DCOLOR diffuse; + } + quad[] = + { + {{-1.0f, -1.0f, 0.1f}, 0xffff0000}, + {{-1.0f, 1.0f, 0.1f}, 0xffff0000}, + {{ 1.0f, -1.0f, 0.1f}, 0xffff0000}, + {{ 1.0f, 1.0f, 0.1f}, 0xffff0000}, + }; + + window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 0, 0, 640, 480, NULL, NULL, NULL, NULL); + d3d = Direct3DCreate9(D3D_SDK_VERSION); + ok(!!d3d, "Failed to create a D3D object.\n"); + if (!(device = create_device(d3d, window, window, TRUE))) + { + skip("Failed to create a D3D device, skipping tests.\n"); + goto done; + } + + hr = IDirect3DDevice9_GetDeviceCaps(device, &caps); + ok(SUCCEEDED(hr), "Failed to get device caps, hr %#x.\n", hr); + if (!(caps.PrimitiveMiscCaps & D3DPMISCCAPS_PERSTAGECONSTANT)) + { + skip("Per-stage constants not supported, skipping tests.\n"); + IDirect3DDevice9_Release(device); + goto done; + } + + hr = IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE); + ok(SUCCEEDED(hr), "Failed to set FVF, hr %#x.\n", hr); + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHABLENDENABLE, TRUE); + ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE); + ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); + + hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_CONSTANT, 0x80a1b2c3); + ok(SUCCEEDED(hr), "Failed to set texture stage state, hr %#x.\n", hr); + hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1, D3DTA_CONSTANT); + ok(SUCCEEDED(hr), "Failed to set texture stage state, hr %#x.\n", hr); + hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + ok(SUCCEEDED(hr), "Failed to set texture stage state, hr %#x.\n", hr); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x000000ff, 1.0f, 0); + ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr); + + hr = IDirect3DDevice9_BeginScene(device); + ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr); + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(*quad)); + ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr); + hr = IDirect3DDevice9_EndScene(device); + ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr); + + color = getPixelColor(device, 320, 240); + ok(color_match(color, 0x00a1b2c3, 1), "Got unexpected color 0x%08x.\n", color); + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr); + + hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1, D3DTA_CONSTANT | D3DTA_COMPLEMENT); + ok(SUCCEEDED(hr), "Failed to set texture stage state, hr %#x.\n", hr); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x000000ff, 1.0f, 0); + ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr); + + hr = IDirect3DDevice9_BeginScene(device); + ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr); + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(*quad)); + ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr); + hr = IDirect3DDevice9_EndScene(device); + ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr); + + color = getPixelColor(device, 320, 240); + ok(color_match(color, 0x005e4d3c, 1), "Got unexpected color 0x%08x.\n", color); + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr); + + hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1, D3DTA_CONSTANT | D3DTA_ALPHAREPLICATE); + ok(SUCCEEDED(hr), "Failed to set texture stage state, hr %#x.\n", hr); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x000000ff, 1.0f, 0); + ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr); + + hr = IDirect3DDevice9_BeginScene(device); + ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr); + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(*quad)); + ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr); + hr = IDirect3DDevice9_EndScene(device); + ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr); + + color = getPixelColor(device, 320, 240); + ok(color_match(color, 0x00808080, 1), "Got unexpected color 0x%08x.\n", color); + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr); + + hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1, D3DTA_CONSTANT); + ok(SUCCEEDED(hr), "Failed to set texture stage state, hr %#x.\n", hr); + hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + ok(SUCCEEDED(hr), "Failed to set texture stage state, hr %#x.\n", hr); + hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1, D3DTA_CURRENT); + ok(SUCCEEDED(hr), "Failed to set texture stage state, hr %#x.\n", hr); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x000000ff, 1.0f, 0); + ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr); + + hr = IDirect3DDevice9_BeginScene(device); + ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr); + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(*quad)); + ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr); + hr = IDirect3DDevice9_EndScene(device); + ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr); + + color = getPixelColor(device, 320, 240); + ok(color_match(color, 0x0080007f, 1), "Got unexpected color 0x%08x.\n", color); + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr); + + refcount = IDirect3DDevice9_Release(device); + ok(!refcount, "Device has %u references left.\n", refcount); +done: + IDirect3D9_Release(d3d); + DestroyWindow(window); +} + START_TEST(visual) { D3DADAPTER_IDENTIFIER9 identifier; @@ -16513,4 +16653,5 @@ START_TEST(visual) multisampled_depth_buffer_test(); resz_test(); stencil_cull_test(); + test_per_stage_constant(); } diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 32ad9e7..c86d400 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -129,6 +129,7 @@ struct glsl_ps_program GLint bumpenv_mat_location[MAX_TEXTURES]; GLint bumpenv_lum_scale_location[MAX_TEXTURES]; GLint bumpenv_lum_offset_location[MAX_TEXTURES]; + GLint tss_constant_location[MAX_TEXTURES]; GLint tex_factor_location; GLint specular_enable_location; GLint ycorrection_location; @@ -868,6 +869,15 @@ static void shader_glsl_load_constants(void *shader_priv, struct wined3d_context else GL_EXTCALL(glUniform4fARB(prog->ps.specular_enable_location, 0.0f, 0.0f, 0.0f, 0.0f)); + for (i = 0; i < MAX_TEXTURES; ++i) + { + if (prog->ps.tss_constant_location[i] == -1) + continue; + + D3DCOLORTOGLFLOAT4(state->texture_states[i][WINED3D_TSS_CONSTANT], col); + GL_EXTCALL(glUniform4fvARB(prog->ps.tss_constant_location[i], 1, col)); + } + checkGLcall("fixed function uniforms"); } @@ -5083,17 +5093,16 @@ static const char *shader_glsl_get_ffp_fragment_op_arg(struct wined3d_shader_buf break; case WINED3DTA_CONSTANT: - FIXME("Per-stage constants not implemented.\n"); switch (stage) { - case 0: ret = "const0"; break; - case 1: ret = "const1"; break; - case 2: ret = "const2"; break; - case 3: ret = "const3"; break; - case 4: ret = "const4"; break; - case 5: ret = "const5"; break; - case 6: ret = "const6"; break; - case 7: ret = "const7"; break; + case 0: ret = "tss_const0"; break; + case 1: ret = "tss_const1"; break; + case 2: ret = "tss_const2"; break; + case 3: ret = "tss_const3"; break; + case 4: ret = "tss_const4"; break; + case 5: ret = "tss_const5"; break; + case 6: ret = "tss_const6"; break; + case 7: ret = "tss_const7"; break; default: ret = ""; break; @@ -5284,8 +5293,8 @@ static void shader_glsl_ffp_fragment_op(struct wined3d_shader_buffer *buffer, un static GLuint shader_glsl_generate_ffp_fragment_shader(struct wined3d_shader_buffer *buffer, const struct ffp_frag_settings *settings, const struct wined3d_gl_info *gl_info) { + BYTE lum_map = 0, bump_map = 0, tex_map = 0, tss_const_map = 0; BOOL tempreg_used = FALSE, tfactor_used = FALSE; - BYTE lum_map = 0, bump_map = 0, tex_map = 0; const char *final_combiner_src = "ret"; UINT lowest_disabled_stage; GLhandleARB shader_obj; @@ -5312,6 +5321,8 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct wined3d_shader_buf tempreg_used = TRUE; if (settings->op[stage].dst == tempreg) tempreg_used = TRUE; + if (arg0 == WINED3DTA_CONSTANT || arg1 == WINED3DTA_CONSTANT || arg2 == WINED3DTA_CONSTANT) + tss_const_map |= 1 << stage; switch (settings->op[stage].cop) { @@ -5347,6 +5358,8 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct wined3d_shader_buf tfactor_used = TRUE; if (arg0 == WINED3DTA_TEMP || arg1 == WINED3DTA_TEMP || arg2 == WINED3DTA_TEMP) tempreg_used = TRUE; + if (arg0 == WINED3DTA_CONSTANT || arg1 == WINED3DTA_CONSTANT || arg2 == WINED3DTA_CONSTANT) + tss_const_map |= 1 << stage; } lowest_disabled_stage = stage; @@ -5363,6 +5376,9 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct wined3d_shader_buf for (stage = 0; stage < MAX_TEXTURES; ++stage) { + if (tss_const_map & (1 << stage)) + shader_addline(buffer, "uniform vec4 tss_const%u;\n", stage); + if (!(tex_map & (1 << stage))) continue; @@ -5723,6 +5739,8 @@ static void shader_glsl_init_ps_uniform_locations(const struct wined3d_gl_info * ps->bumpenv_lum_scale_location[i] = GL_EXTCALL(glGetUniformLocationARB(program_id, name)); snprintf(name, sizeof(name), "bumpenv_lum_offset%u", i); ps->bumpenv_lum_offset_location[i] = GL_EXTCALL(glGetUniformLocationARB(program_id, name)); + snprintf(name, sizeof(name), "tss_const%u", i); + ps->tss_constant_location[i] = GL_EXTCALL(glGetUniformLocationARB(program_id, name)); } ps->tex_factor_location = GL_EXTCALL(glGetUniformLocationARB(program_id, "tex_factor")); @@ -7027,7 +7045,8 @@ static void glsl_fragment_pipe_get_caps(const struct wined3d_gl_info *gl_info, s { caps->wined3d_caps = WINED3D_FRAGMENT_CAP_PROJ_CONTROL | WINED3D_FRAGMENT_CAP_SRGB_WRITE; - caps->PrimitiveMiscCaps = WINED3DPMISCCAPS_TSSARGTEMP; + caps->PrimitiveMiscCaps = WINED3DPMISCCAPS_TSSARGTEMP + | WINED3DPMISCCAPS_PERSTAGECONSTANT; caps->TextureOpCaps = WINED3DTEXOPCAPS_DISABLE | WINED3DTEXOPCAPS_SELECTARG1 | WINED3DTEXOPCAPS_SELECTARG2 @@ -7253,6 +7272,14 @@ static const struct StateEntryTemplate glsl_fragment_pipe_state_template[] = {STATE_TEXTURESTAGE(5,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(5, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE }, {STATE_TEXTURESTAGE(6,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(6, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE }, {STATE_TEXTURESTAGE(7,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(7, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(0, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(0, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(1, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(1, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(2, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(2, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(3, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(3, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(4, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(4, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(5, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(5, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(6, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(6, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(7, WINED3D_TSS_CONSTANT), {STATE_TEXTURESTAGE(7, WINED3D_TSS_CONSTANT), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE }, {STATE_RENDER(WINED3D_RS_SPECULARENABLE), {STATE_RENDER(WINED3D_RS_SPECULARENABLE), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE }, {0 /* Terminate */, {0, 0 }, WINED3D_GL_EXT_NONE }, }; -- 1.7.10.4