[PATCH 2/2] wined3d: Store and use stream offset in state block.

Paul Gofman gofmanp at gmail.com
Wed Apr 3 12:26:07 CDT 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=21161
Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
 dlls/d3d9/tests/stateblock.c   | 48 ++++++++++++++++++++++++++++------
 dlls/wined3d/device.c          |  1 +
 dlls/wined3d/stateblock.c      | 29 +++++++++++++++-----
 dlls/wined3d/wined3d_private.h |  1 +
 4 files changed, 65 insertions(+), 14 deletions(-)

diff --git a/dlls/d3d9/tests/stateblock.c b/dlls/d3d9/tests/stateblock.c
index 0983cf7b4f..59e5260e1c 100644
--- a/dlls/d3d9/tests/stateblock.c
+++ b/dlls/d3d9/tests/stateblock.c
@@ -67,6 +67,7 @@ struct state_test
 /* Apparently recorded stateblocks record and apply vertex declarations,
  * but don't capture them */
 #define SB_QUIRK_RECORDED_VDECL_CAPTURE  0x00000001
+#define SB_QUIRK_STREAM_OFFSET_NOT_UPDATED 0x00000002
 
 struct event_data
 {
@@ -135,6 +136,8 @@ static void execute_test_chain(IDirect3DDevice9 *device, struct state_test *test
     {
         const void *data;
 
+        trace("event %u.\n", j);
+
         /* Execute the next event handler (if available). */
         if (event[j].event_fn)
         {
@@ -349,16 +352,17 @@ static void execute_test_chain_all(IDirect3DDevice9 *device, struct state_test *
     struct event capture_reapply_stateblock_events[] =
     {
         {begin_stateblock,          SB_DATA_NONE,           SB_DATA_TEST_IN},
-        {end_stateblock,            SB_DATA_NONE,           SB_DATA_NONE},
+        {end_stateblock,            SB_DATA_NONE,           SB_DATA_DEFAULT},
         {capture_stateblock,        SB_DATA_DEFAULT,        SB_DATA_TEST_IN},
-        {apply_stateblock,          SB_DATA_DEFAULT,        SB_DATA_NONE,       SB_QUIRK_RECORDED_VDECL_CAPTURE},
+        {capture_stateblock,        SB_DATA_TEST_IN,        SB_DATA_DEFAULT},
+        {apply_stateblock,          SB_DATA_TEST_IN,        SB_DATA_DEFAULT, SB_QUIRK_RECORDED_VDECL_CAPTURE},
     };
 
     struct event create_stateblock_capture_apply_all_events[] =
     {
         {create_stateblock_all,     SB_DATA_DEFAULT,        SB_DATA_TEST_IN},
         {capture_stateblock,        SB_DATA_TEST_ALL,       SB_DATA_DEFAULT},
-        {apply_stateblock,          SB_DATA_TEST_ALL,       SB_DATA_NONE},
+        {apply_stateblock,          SB_DATA_TEST_ALL,       SB_DATA_NONE, SB_QUIRK_STREAM_OFFSET_NOT_UPDATED},
     };
 
     struct event create_stateblock_apply_all_events[] =
@@ -433,7 +437,7 @@ static void execute_test_chain_all(IDirect3DDevice9 *device, struct state_test *
     execute_test_chain(device, test, ntests, apply_stateblock_events, 3, &arg);
 
     trace("Running stateblock capture/reapply state tests\n");
-    execute_test_chain(device, test, ntests, capture_reapply_stateblock_events, 4, &arg);
+    execute_test_chain(device, test, ntests, capture_reapply_stateblock_events, 5, &arg);
 
     trace("Running create stateblock capture/apply all state tests\n");
     execute_test_chain(device, test, ntests, create_stateblock_capture_apply_all_events, 3, &arg);
@@ -749,7 +753,7 @@ static void light_check_data(IDirect3DDevice9 *device, const struct state_test *
             "Chain stage %u: expected get_light_result %#x, got %#x.\n",
             chain_stage, ldata->get_light_result, value.get_light_result);
 
-    ok(value.enabled == ldata->enabled,
+    ok(!value.enabled == !ldata->enabled,
             "Chain stage %u: expected enabled %#x, got %#x.\n",
             chain_stage, ldata->enabled, value.enabled);
     ok(value.light.Type == ldata->light.Type,
@@ -1666,6 +1670,7 @@ struct resource_test_data
     IDirect3DPixelShader9 *ps;
     IDirect3DIndexBuffer9 *ib;
     IDirect3DVertexBuffer9 **vb;
+    unsigned int stream_offset, stream_stride;
     IDirect3DTexture9 **tex;
 };
 
@@ -1682,6 +1687,7 @@ static void resource_apply_data(IDirect3DDevice9 *device, const struct state_tes
 {
     const struct resource_test_arg *arg = test->test_arg;
     const struct resource_test_data *d = data;
+    IDirect3DVertexBuffer9 *temp_vb = NULL;
     unsigned int i;
     HRESULT hr;
 
@@ -1699,10 +1705,26 @@ static void resource_apply_data(IDirect3DDevice9 *device, const struct state_tes
 
     for (i = 0; i < arg->stream_count; ++i)
     {
-        hr = IDirect3DDevice9_SetStreamSource(device, i, d->vb[i], 0, 64);
-        ok(SUCCEEDED(hr), "SetStreamSource (%u, %p, 0, 64) returned %#x.\n",
-                i, d->vb[i], hr);
+        if (!d->vb[i])
+        {
+            /* Use a non NULL vertex buffer to really set offset and stride and avoid leftover values. */
+            if (!temp_vb)
+            {
+                hr = IDirect3DDevice9_CreateVertexBuffer(device, 64, D3DUSAGE_DYNAMIC,
+                        0, D3DPOOL_DEFAULT, &temp_vb, NULL);
+                ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+            }
+            hr = IDirect3DDevice9_SetStreamSource(device, i, temp_vb, d->stream_offset, d->stream_stride);
+            ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+        }
+
+        hr = IDirect3DDevice9_SetStreamSource(device, i, d->vb[i], d->stream_offset, d->stream_stride);
+        ok(hr == D3D_OK, "Unexpected SetStreamSource result, i %u, vb %p, "
+                "stream_offset %u, stream_stride %u), hr %#x.\n",
+                i, d->vb[i], d->stream_offset, d->stream_stride, hr);
     }
+    if (temp_vb)
+        IDirect3DVertexBuffer9_Release(temp_vb);
 
     for (i = 0; i < arg->tex_count; ++i)
     {
@@ -1718,6 +1740,7 @@ static void resource_check_data(IDirect3DDevice9 *device, const struct state_tes
     const struct resource_test_data *poison = &ctx->poison_data;
     const struct resource_test_arg *arg = test->test_arg;
     const struct resource_test_data *d = expected_data;
+    unsigned int expected_offset;
     unsigned int i;
     HRESULT hr;
     void *ptr;
@@ -1771,6 +1794,7 @@ static void resource_check_data(IDirect3DDevice9 *device, const struct state_tes
         IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9 *)ptr);
     }
 
+    expected_offset = quirk & SB_QUIRK_STREAM_OFFSET_NOT_UPDATED ? 0 : d->stream_offset;
     for (i = 0; i < arg->stream_count; ++i)
     {
         ptr = poison->vb[i];
@@ -1778,6 +1802,8 @@ static void resource_check_data(IDirect3DDevice9 *device, const struct state_tes
         ok(SUCCEEDED(hr), "GetStreamSource (%u) returned %#x.\n", i, hr);
         ok(ptr == d->vb[i], "Chain stage %u, stream %u, expected vertex buffer %p, received %p.\n",
                 chain_stage, i, d->vb[i], ptr);
+        ok(v == expected_offset, "Stream source offset %u, expected %u, stride %u.\n", v, expected_offset, w);
+        ok(w == d->stream_stride, "Stream source stride %u, expected %u.\n", w, d->stream_stride);
         if (SUCCEEDED(hr) && ptr)
         {
             IDirect3DIndexBuffer9_Release((IDirect3DVertexBuffer9 *)ptr);
@@ -1811,6 +1837,8 @@ static void resource_default_data_init(struct resource_test_data *data, const st
     {
         data->vb[i] = NULL;
     }
+    data->stream_offset = 0;
+    data->stream_stride = 0;
     data->tex = HeapAlloc(GetProcessHeap(), 0, arg->tex_count * sizeof(*data->tex));
     for (i = 0; i < arg->tex_count; ++i)
     {
@@ -1885,6 +1913,8 @@ static void resource_test_data_init(IDirect3DDevice9 *device,
                 0, D3DPOOL_DEFAULT, &data->vb[i], NULL);
         ok(SUCCEEDED(hr), "CreateVertexBuffer (%u) returned %#x.\n", i, hr);
     }
+    data->stream_offset = 4;
+    data->stream_stride = 64;
     data->tex = HeapAlloc(GetProcessHeap(), 0, arg->tex_count * sizeof(*data->tex));
     for (i = 0; i < arg->tex_count; ++i)
     {
@@ -1908,6 +1938,8 @@ static void resource_poison_data_init(struct resource_test_data *data, const str
     {
         data->vb[i] = (IDirect3DVertexBuffer9 *)poison++;
     }
+    data->stream_offset = 16;
+    data->stream_stride = 128;
     data->tex = HeapAlloc(GetProcessHeap(), 0, arg->tex_count * sizeof(*data->tex));
     for (i = 0; i < arg->tex_count; ++i)
     {
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 9556aeef83..517fd55c8c 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1388,6 +1388,7 @@ HRESULT CDECL wined3d_device_set_stream_source(struct wined3d_device *device, UI
         wined3d_buffer_decref(device->update_stateblock_state->streams[stream_idx].buffer);
     device->update_stateblock_state->streams[stream_idx].buffer = buffer;
     device->update_stateblock_state->streams[stream_idx].stride = stride;
+    device->update_stateblock_state->streams[stream_idx].offset = offset;
 
     if (device->recording)
     {
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index 36239207ae..70a2f1ebc0 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -212,6 +212,7 @@ static void stateblock_savedstates_set_all(struct wined3d_saved_states *states,
 
     /* Fixed size arrays */
     states->streamSource = 0xffff;
+    states->stream_offset_ignore = FALSE;
     states->streamFreq = 0xffff;
     states->textures = 0xfffff;
     stateblock_set_bits(states->transform, WINED3D_HIGHEST_TRANSFORM_STATE + 1);
@@ -916,13 +917,17 @@ void CDECL wined3d_stateblock_capture(struct wined3d_stateblock *stateblock)
         if (!(map & 1)) continue;
 
         if (stateblock->stateblock_state.streams[i].stride != state->streams[i].stride
+                || stateblock->stateblock_state.streams[i].offset != state->streams[i].offset
                 || stateblock->stateblock_state.streams[i].buffer != state->streams[i].buffer)
         {
-            TRACE("Updating stream source %u to %p, stride to %u.\n",
-                    i, state->streams[i].buffer,
-                    state->streams[i].stride);
+            TRACE("stateblock %p, stream source %u, buffer %p, stride %u, offset %u.\n",
+                    stateblock, i, state->streams[i].buffer, state->streams[i].stride,
+                    state->streams[i].offset);
 
             stateblock->stateblock_state.streams[i].stride = state->streams[i].stride;
+            if (!stateblock->changed.stream_offset_ignore)
+                stateblock->stateblock_state.streams[i].offset = state->streams[i].offset;
+
             if (state->streams[i].buffer)
                     wined3d_buffer_incref(state->streams[i].buffer);
             if (stateblock->stateblock_state.streams[i].buffer)
@@ -1211,18 +1216,24 @@ void CDECL wined3d_stateblock_apply(const struct wined3d_stateblock *stateblock)
     map = stateblock->changed.streamSource;
     for (i = 0; map; map >>= 1, ++i)
     {
+        struct wined3d_buffer *buffer;
+        unsigned int offset, stride;
+
         if (!(map & 1)) continue;
 
-        state->streams[i].stride = stateblock->stateblock_state.streams[i].stride;
         if (stateblock->stateblock_state.streams[i].buffer)
                 wined3d_buffer_incref(stateblock->stateblock_state.streams[i].buffer);
         if (state->streams[i].buffer)
                 wined3d_buffer_decref(state->streams[i].buffer);
         state->streams[i].buffer = stateblock->stateblock_state.streams[i].buffer;
 
+        offset = stateblock->stateblock_state.streams[i].offset;
+        stride = stateblock->stateblock_state.streams[i].stride;
+
+        state->streams[i].stride = stride;
+        state->streams[i].offset = offset;
         wined3d_device_set_stream_source(device, i,
-                stateblock->stateblock_state.streams[i].buffer,
-                0, stateblock->stateblock_state.streams[i].stride);
+                stateblock->stateblock_state.streams[i].buffer, offset, stride);
     }
 
     map = stateblock->changed.streamFreq;
@@ -1599,6 +1610,12 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock,
     stateblock_init_contained_states(stateblock);
     wined3d_stateblock_capture(stateblock);
 
+    /* According to the tests, stream offset is not updated in the captured state if
+     * the state was captured on state block creation. This is not the case for
+     * state blocks initialized with BeginStateBlock / EndStateBlock, multiple
+     * captures get stream offsets updated. */
+    stateblock->changed.stream_offset_ignore = TRUE;
+
     return WINED3D_OK;
 }
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index d8df79026a..60a69023c5 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3641,6 +3641,7 @@ struct wined3d_saved_states
 {
     DWORD transform[(WINED3D_HIGHEST_TRANSFORM_STATE >> 5) + 1];
     WORD streamSource;                          /* WINED3D_MAX_STREAMS, 16 */
+    BOOL stream_offset_ignore;
     WORD streamFreq;                            /* WINED3D_MAX_STREAMS, 16 */
     DWORD renderState[(WINEHIGHEST_RENDER_STATE >> 5) + 1];
     DWORD textureState[WINED3D_MAX_TEXTURES];   /* WINED3D_HIGHEST_TEXTURE_STATE + 1, 18 */
-- 
2.20.1




More information about the wine-devel mailing list