From a95b88ac21b040a62d5b17bc916b63d4f3e5e30b Mon Sep 17 00:00:00 2001
From: Paul Gofman <gofmanp@gmail.com>
Date: Mon, 25 Feb 2019 15:05:12 +0300
Subject: [PATCH] wined3d: Support SWVP vertex shader constants limit in state
 tracking.

---
 dlls/d3d9/tests/device.c       |  5 -----
 dlls/d3d9/tests/visual.c       |  1 -
 dlls/wined3d/device.c          |  6 ++++--
 dlls/wined3d/glsl_shader.c     |  2 +-
 dlls/wined3d/stateblock.c      | 23 ++++++++++++++---------
 dlls/wined3d/wined3d_private.h | 13 +++++++++++--
 include/wine/wined3d.h         |  2 +-
 7 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index 41cfc1519c1..21247319853 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -6544,13 +6544,10 @@ static void test_vertex_shader_constant(void)
     ok(consts_swvp == 8192, "Unexpected consts_swvp %u.\n", consts_swvp);
 
     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, consts + 0, c, 1);
-    todo_wine
     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, consts + 1, c, 1);
-    todo_wine
     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, consts - 1, d, 4);
-    todo_wine
     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, consts_swvp - 1, c, 1);
     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
@@ -6575,7 +6572,6 @@ static void test_vertex_shader_constant(void)
 
     IDirect3DDevice9_SetSoftwareVertexProcessing(device, 0);
     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, consts + 0, c, 1);
-    todo_wine
     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, consts_swvp - 1, c, 1);
     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
@@ -6583,7 +6579,6 @@ static void test_vertex_shader_constant(void)
     IDirect3DDevice9_SetSoftwareVertexProcessing(device, 1);
 
     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, consts + 0, c, 1);
-    todo_wine
     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, consts_swvp - 1, c, 1);
     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index f873f3ae9b3..0b3fd91328d 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -24880,7 +24880,6 @@ static void test_mvp_software_vertex_shaders(void)
     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, 0, c_index, 1);
     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
     hr = IDirect3DDevice9_SetVertexShaderConstantF(device, (unsigned int)c_index[0], c_color, 1);
-    todo_wine
     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
 
     hr = IDirect3DDevice9_BeginScene(device);
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 541d091816b..b83a8f49d72 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -3255,7 +3255,7 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
     const struct wined3d_saved_states *changed = &stateblock->changed;
     const unsigned int word_bit_count = sizeof(DWORD) * CHAR_BIT;
     BOOL set_blend_state = FALSE, set_rasterizer_state = FALSE;
-    unsigned int i, j, start, idx;
+    unsigned int i, j, start, idx, vs_uniform_count;
     struct wined3d_range range;
     uint32_t map;
 
@@ -3266,9 +3266,11 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
     if (changed->pixelShader)
         wined3d_device_set_pixel_shader(device, state->ps);
 
+    vs_uniform_count = wined3d_device_get_vs_uniform_count(device);
+
     for (start = 0; ; start = range.offset + range.size)
     {
-        if (!wined3d_bitmap_get_range(changed->vs_consts_f, WINED3D_MAX_VS_CONSTS_F, start, &range))
+        if (!wined3d_bitmap_get_range(changed->vs_consts_f, vs_uniform_count, start, &range))
             break;
 
         wined3d_device_set_vs_consts_f(device, range.offset, range.size, &state->vs_consts_f[range.offset]);
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index bb632ecca7b..1ac4ae92953 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -1913,7 +1913,7 @@ static void shader_glsl_update_float_vertex_constants(struct wined3d_device *dev
     if (priv->consts_ubo)
         return;
 
-    for (i = start; i < count + start; ++i)
+    for (i = start; i < min(WINED3D_MAX_VS_CONSTS_F, count + start); ++i)
     {
         update_heap_entry(heap, i, priv->next_constant_version);
     }
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index 7e97c84c19e..b439e70b4f4 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -714,8 +714,8 @@ void CDECL wined3d_stateblock_capture(struct wined3d_stateblock *stateblock,
         const struct wined3d_stateblock *device_state)
 {
     const struct wined3d_stateblock_state *state = &device_state->stateblock_state;
+    unsigned int i, start, vs_uniform_count;
     struct wined3d_range range;
-    unsigned int i, start;
     DWORD map;
 
     TRACE("stateblock %p, device_state %p.\n", stateblock, device_state);
@@ -731,9 +731,11 @@ void CDECL wined3d_stateblock_capture(struct wined3d_stateblock *stateblock,
         stateblock->stateblock_state.vs = state->vs;
     }
 
+    vs_uniform_count = wined3d_device_get_vs_uniform_count(stateblock->device);
+
     for (start = 0; ; start = range.offset + range.size)
     {
-        if (!wined3d_bitmap_get_range(stateblock->changed.vs_consts_f, WINED3D_MAX_VS_CONSTS_F, start, &range))
+        if (!wined3d_bitmap_get_range(stateblock->changed.vs_consts_f, vs_uniform_count, start, &range))
             break;
 
         memcpy(&stateblock->stateblock_state.vs_consts_f[range.offset], &state->vs_consts_f[range.offset],
@@ -977,8 +979,8 @@ void CDECL wined3d_stateblock_apply(const struct wined3d_stateblock *stateblock,
         struct wined3d_stateblock *device_state)
 {
     const struct wined3d_stateblock_state *state = &stateblock->stateblock_state;
+    unsigned int i, start, vs_uniform_count;
     struct wined3d_range range;
-    unsigned int i, start;
     DWORD map;
 
     TRACE("stateblock %p, device_state %p.\n", stateblock, device_state);
@@ -988,9 +990,11 @@ void CDECL wined3d_stateblock_apply(const struct wined3d_stateblock *stateblock,
     if (stateblock->changed.pixelShader)
         wined3d_stateblock_set_pixel_shader(device_state, state->ps);
 
+    vs_uniform_count = wined3d_device_get_vs_uniform_count(stateblock->device);
+
     for (start = 0; ; start = range.offset + range.size)
     {
-        if (!wined3d_bitmap_get_range(stateblock->changed.vs_consts_f, WINED3D_MAX_VS_CONSTS_F, start, &range))
+        if (!wined3d_bitmap_get_range(stateblock->changed.vs_consts_f, vs_uniform_count, start, &range))
             break;
         wined3d_stateblock_set_vs_consts_f(device_state, range.offset, range.size, &state->vs_consts_f[range.offset]);
     }
@@ -1182,13 +1186,14 @@ static void wined3d_bitmap_set_bits(uint32_t *bitmap, unsigned int start, unsign
 HRESULT CDECL wined3d_stateblock_set_vs_consts_f(struct wined3d_stateblock *stateblock,
         unsigned int start_idx, unsigned int count, const struct wined3d_vec4 *constants)
 {
-    const struct wined3d_d3d_info *d3d_info = &stateblock->device->adapter->d3d_info;
+    unsigned int constants_count;
 
     TRACE("stateblock %p, start_idx %u, count %u, constants %p.\n",
             stateblock, start_idx, count, constants);
 
-    if (!constants || start_idx >= d3d_info->limits.vs_uniform_count
-            || count > d3d_info->limits.vs_uniform_count - start_idx)
+    constants_count = wined3d_device_get_vs_uniform_count(stateblock->device);
+
+    if (!constants || start_idx >= constants_count || count > constants_count - start_idx)
         return WINED3DERR_INVALIDCALL;
 
     memcpy(&stateblock->stateblock_state.vs_consts_f[start_idx], constants, count * sizeof(*constants));
@@ -1933,7 +1938,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru
             stateblock_init_lights(stateblock->stateblock_state.light_state->light_map,
                     device_state->stateblock_state.light_state->light_map);
             stateblock_savedstates_set_all(&stateblock->changed,
-                    d3d_info->limits.vs_uniform_count, d3d_info->limits.ps_uniform_count);
+                    d3d_info->limits.vs_uniform_count_swvp, d3d_info->limits.ps_uniform_count);
             break;
 
         case WINED3D_SBT_PIXEL_STATE:
@@ -1945,7 +1950,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru
             stateblock_init_lights(stateblock->stateblock_state.light_state->light_map,
                     device_state->stateblock_state.light_state->light_map);
             stateblock_savedstates_set_vertex(&stateblock->changed,
-                    d3d_info->limits.vs_uniform_count);
+                    d3d_info->limits.vs_uniform_count_swvp);
             break;
 
         default:
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 49120a2dda2..f2040eec334 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3441,7 +3441,7 @@ struct wined3d_state
     struct wined3d_shader_resource_view *shader_resource_view[WINED3D_SHADER_TYPE_COUNT][MAX_SHADER_RESOURCE_VIEWS];
     struct wined3d_unordered_access_view *unordered_access_view[WINED3D_PIPELINE_COUNT][MAX_UNORDERED_ACCESS_VIEWS];
 
-    struct wined3d_vec4 vs_consts_f[WINED3D_MAX_VS_CONSTS_F];
+    struct wined3d_vec4 vs_consts_f[WINED3D_MAX_VS_CONSTS_F_SWVP];
     struct wined3d_ivec4 vs_consts_i[WINED3D_MAX_CONSTS_I];
     BOOL vs_consts_b[WINED3D_MAX_CONSTS_B];
 
@@ -3585,6 +3585,15 @@ HRESULT wined3d_device_set_implicit_swapchain(struct wined3d_device *device,
         struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
 void wined3d_device_uninit_3d(struct wined3d_device *device) DECLSPEC_HIDDEN;
 
+static inline unsigned int wined3d_device_get_vs_uniform_count(const struct wined3d_device *device)
+{
+    const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
+
+    return device->create_parms.flags
+            & (WINED3DCREATE_SOFTWARE_VERTEXPROCESSING | WINED3DCREATE_MIXED_VERTEXPROCESSING)
+            ? d3d_info->limits.vs_uniform_count_swvp : d3d_info->limits.vs_uniform_count;
+}
+
 struct wined3d_device_no3d
 {
     struct wined3d_device d;
@@ -4242,7 +4251,7 @@ struct wined3d_vertex_declaration
 
 struct wined3d_saved_states
 {
-    uint32_t vs_consts_f[WINED3D_BITMAP_SIZE(WINED3D_MAX_VS_CONSTS_F)];
+    uint32_t vs_consts_f[WINED3D_BITMAP_SIZE(WINED3D_MAX_VS_CONSTS_F_SWVP)];
     WORD vertexShaderConstantsI;                /* WINED3D_MAX_CONSTS_I, 16 */
     WORD vertexShaderConstantsB;                /* WINED3D_MAX_CONSTS_B, 16 */
     uint32_t ps_consts_f[WINED3D_BITMAP_SIZE(WINED3D_MAX_PS_CONSTS_F)];
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 0ffeecfb297..9b1e64385e0 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2158,7 +2158,7 @@ struct wined3d_stateblock_state
     int base_vertex_index;
 
     struct wined3d_shader *vs;
-    struct wined3d_vec4 vs_consts_f[WINED3D_MAX_VS_CONSTS_F];
+    struct wined3d_vec4 vs_consts_f[WINED3D_MAX_VS_CONSTS_F_SWVP];
     struct wined3d_ivec4 vs_consts_i[WINED3D_MAX_CONSTS_I];
     BOOL vs_consts_b[WINED3D_MAX_CONSTS_B];
 
-- 
2.26.2

