[PATCH v2 8/8] d3d11: Implement ID3D11DeviceContext::ExecuteCommandList().

Zebediah Figura z.figura12 at gmail.com
Wed May 26 21:14:52 CDT 2021


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/d3d11/device.c            |  17 ++++-
 dlls/d3d11/tests/d3d11.c       |  30 ++++-----
 dlls/wined3d/cs.c              | 109 +++++++++++++++++++++++++++++++++
 dlls/wined3d/device.c          |   8 +++
 dlls/wined3d/wined3d.spec      |   1 +
 dlls/wined3d/wined3d_private.h |   2 +
 include/wine/wined3d.h         |   2 +
 7 files changed, 150 insertions(+), 19 deletions(-)

diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c
index e832d8e68d3..b6e60050f4f 100644
--- a/dlls/d3d11/device.c
+++ b/dlls/d3d11/device.c
@@ -447,6 +447,14 @@ static const struct ID3D11CommandListVtbl d3d11_command_list_vtbl =
     d3d11_command_list_GetContextFlags,
 };
 
+static struct d3d11_command_list *unsafe_impl_from_ID3D11CommandList(ID3D11CommandList *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3d11_command_list_vtbl);
+    return impl_from_ID3D11CommandList(iface);
+}
+
 /* ID3D11DeviceContext - immediate context methods */
 
 static inline struct d3d11_device_context *impl_from_ID3D11DeviceContext1(ID3D11DeviceContext1 *iface)
@@ -1513,7 +1521,14 @@ static void STDMETHODCALLTYPE d3d11_device_context_ResolveSubresource(ID3D11Devi
 static void STDMETHODCALLTYPE d3d11_device_context_ExecuteCommandList(ID3D11DeviceContext1 *iface,
         ID3D11CommandList *command_list, BOOL restore_state)
 {
-    FIXME("iface %p, command_list %p, restore_state %#x stub!\n", iface, command_list, restore_state);
+    struct d3d11_device_context *context = impl_from_ID3D11DeviceContext1(iface);
+    struct d3d11_command_list *list_impl = unsafe_impl_from_ID3D11CommandList(command_list);
+
+    TRACE("iface %p, command_list %p, restore_state %#x.\n", iface, command_list, restore_state);
+
+    wined3d_mutex_lock();
+    wined3d_device_context_execute_command_list(context->wined3d_context, list_impl->wined3d_list, !!restore_state);
+    wined3d_mutex_unlock();
 }
 
 static void STDMETHODCALLTYPE d3d11_device_context_HSSetShaderResources(ID3D11DeviceContext1 *iface,
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index 8da0cfaa8bf..408c0492cd2 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -32302,9 +32302,7 @@ static void test_deferred_context_state(void)
     ID3D11DeviceContext_PSSetConstantBuffers(immediate, 0, 1, &green_buffer);
     ID3D11DeviceContext_ExecuteCommandList(immediate, list1, FALSE);
     ID3D11DeviceContext_PSGetConstantBuffers(immediate, 0, 1, &ret_buffer);
-    todo_wine ok(!ret_buffer, "Got unexpected buffer %p.\n", ret_buffer);
-    if (ret_buffer)
-        ID3D11Buffer_Release(ret_buffer);
+    ok(!ret_buffer, "Got unexpected buffer %p.\n", ret_buffer);
 
     ID3D11CommandList_Release(list2);
     ID3D11CommandList_Release(list1);
@@ -32328,9 +32326,7 @@ static void test_deferred_context_state(void)
     ID3D11DeviceContext_PSSetConstantBuffers(deferred, 0, 1, &blue_buffer);
     ID3D11DeviceContext_ExecuteCommandList(deferred, list1, FALSE);
     ID3D11DeviceContext_PSGetConstantBuffers(deferred, 0, 1, &ret_buffer);
-    todo_wine ok(!ret_buffer, "Got unexpected buffer %p.\n", ret_buffer);
-    if (ret_buffer)
-        ID3D11Buffer_Release(ret_buffer);
+    ok(!ret_buffer, "Got unexpected buffer %p.\n", ret_buffer);
 
     ID3D11CommandList_Release(list1);
     ID3D11DeviceContext_Release(deferred2);
@@ -32488,12 +32484,12 @@ static void test_deferred_context_rendering(void)
 
     ID3D11DeviceContext_ExecuteCommandList(immediate, list1, TRUE);
     color = get_texture_color(test_context.backbuffer, 320, 240);
-    todo_wine ok(color == 0xff00ff00, "Got unexpected color %#08x.\n", color);
+    ok(color == 0xff00ff00, "Got unexpected color %#08x.\n", color);
 
     ID3D11DeviceContext_ClearRenderTargetView(immediate, test_context.backbuffer_rtv, &white.x);
     ID3D11DeviceContext_ExecuteCommandList(immediate, list1, TRUE);
     color = get_texture_color(test_context.backbuffer, 320, 240);
-    todo_wine ok(color == 0xff00ff00, "Got unexpected color %#08x.\n", color);
+    ok(color == 0xff00ff00, "Got unexpected color %#08x.\n", color);
 
     ID3D11DeviceContext_ClearRenderTargetView(immediate, test_context.backbuffer_rtv, &white.x);
     ID3D11DeviceContext_ExecuteCommandList(immediate, list2, TRUE);
@@ -32509,7 +32505,7 @@ static void test_deferred_context_rendering(void)
     ID3D11DeviceContext_ClearRenderTargetView(immediate, test_context.backbuffer_rtv, &white.x);
     ID3D11DeviceContext_ExecuteCommandList(immediate, list2, TRUE);
     color = get_texture_color(test_context.backbuffer, 320, 240);
-    todo_wine ok(color == 0xff00ff00, "Got unexpected color %#08x.\n", color);
+    ok(color == 0xff00ff00, "Got unexpected color %#08x.\n", color);
 
     ID3D11CommandList_Release(list2);
     ID3D11CommandList_Release(list1);
@@ -32535,7 +32531,7 @@ static void test_deferred_context_rendering(void)
     ID3D11DeviceContext_ClearRenderTargetView(immediate, rtv, blue);
     ID3D11DeviceContext_ExecuteCommandList(immediate, list1, TRUE);
     color = get_texture_color(test_context.backbuffer, 320, 240);
-    todo_wine ok(color == 0xffff0000, "Got unexpected color %#08x.\n", color);
+    ok(color == 0xffff0000, "Got unexpected color %#08x.\n", color);
 
     ID3D11CommandList_Release(list1);
     ID3D11DeviceContext_Release(deferred);
@@ -32569,12 +32565,10 @@ static void test_deferred_context_rendering(void)
     set_viewport(immediate, 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 1.0f);
     draw_color_quad(&test_context, &white);
     color = get_texture_color(test_context.backbuffer, 320, 240);
-    todo_wine ok(color == 0xffffffff, "Got unexpected color %#08x.\n", color);
+    ok(color == 0xffffffff, "Got unexpected color %#08x.\n", color);
 
     ID3D11DeviceContext_OMGetBlendState(immediate, &ret_blend, blend_factor, &sample_mask);
-    todo_wine ok(!ret_blend, "Got unexpected blend state %p.\n", ret_blend);
-    if (ret_blend)
-        ID3D11BlendState_Release(ret_blend);
+    ok(!ret_blend, "Got unexpected blend state %p.\n", ret_blend);
 
     ID3D11CommandList_Release(list1);
     ID3D11DeviceContext_Release(deferred);
@@ -32602,7 +32596,7 @@ static void test_deferred_context_rendering(void)
     ID3D11DeviceContext_OMSetBlendState(immediate, red_blend, NULL, D3D11_DEFAULT_SAMPLE_MASK);
     ID3D11DeviceContext_ExecuteCommandList(immediate, list1, FALSE);
     color = get_texture_color(test_context.backbuffer, 320, 240);
-    todo_wine ok(color == 0xffffffff, "Got unexpected color %#08x.\n", color);
+    ok(color == 0xffffffff, "Got unexpected color %#08x.\n", color);
 
     ID3D11CommandList_Release(list1);
 
@@ -32625,7 +32619,7 @@ static void test_deferred_context_rendering(void)
     ID3D11DeviceContext_OMSetBlendState(immediate, red_blend, NULL, D3D11_DEFAULT_SAMPLE_MASK);
     ID3D11DeviceContext_ExecuteCommandList(immediate, list1, FALSE);
     color = get_texture_color(test_context.backbuffer, 320, 240);
-    todo_wine ok(color == 0xff00ff00, "Got unexpected color %#08x.\n", color);
+    ok(color == 0xff00ff00, "Got unexpected color %#08x.\n", color);
 
     ID3D11CommandList_Release(list1);
 
@@ -32658,7 +32652,7 @@ static void test_deferred_context_rendering(void)
     ID3D11DeviceContext_OMSetBlendState(immediate, red_blend, NULL, D3D11_DEFAULT_SAMPLE_MASK);
     ID3D11DeviceContext_ExecuteCommandList(immediate, list2, FALSE);
     color = get_texture_color(test_context.backbuffer, 320, 240);
-    todo_wine ok(color == 0xffffffff, "Got unexpected color %#08x.\n", color);
+    ok(color == 0xffffffff, "Got unexpected color %#08x.\n", color);
 
     ID3D11CommandList_Release(list2);
 
@@ -32678,7 +32672,7 @@ static void test_deferred_context_rendering(void)
     ID3D11DeviceContext_OMSetBlendState(immediate, red_blend, NULL, D3D11_DEFAULT_SAMPLE_MASK);
     ID3D11DeviceContext_ExecuteCommandList(immediate, list2, FALSE);
     color = get_texture_color(test_context.backbuffer, 320, 240);
-    todo_wine ok(color == 0xff00ff00, "Got unexpected color %#08x.\n", color);
+    ok(color == 0xff00ff00, "Got unexpected color %#08x.\n", color);
 
     ID3D11CommandList_Release(list2);
 
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 1e082ce724d..50a08334dab 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -37,6 +37,12 @@ struct wined3d_command_list
 
     SIZE_T resource_count;
     struct wined3d_resource **resources;
+
+    /* List of command lists queued for execution on this command list. We might
+     * be the only thing holding a pointer to another command list, so we need
+     * to hold a reference here (and in wined3d_deferred_context) as well. */
+    SIZE_T command_list_count;
+    struct wined3d_command_list **command_lists;
 };
 
 static void wined3d_command_list_destroy_object(void *object)
@@ -70,6 +76,8 @@ ULONG CDECL wined3d_command_list_decref(struct wined3d_command_list *list)
     {
         SIZE_T i;
 
+        for (i = 0; i < list->command_list_count; ++i)
+            wined3d_command_list_decref(list->command_lists[i]);
         for (i = 0; i < list->resource_count; ++i)
             wined3d_resource_decref(list->resources[i]);
 
@@ -130,6 +138,7 @@ enum wined3d_cs_op
     WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW,
     WINED3D_CS_OP_COPY_UAV_COUNTER,
     WINED3D_CS_OP_GENERATE_MIPMAPS,
+    WINED3D_CS_OP_EXECUTE_COMMAND_LIST,
     WINED3D_CS_OP_STOP,
 };
 
@@ -511,6 +520,12 @@ struct wined3d_cs_generate_mipmaps
     struct wined3d_shader_resource_view *view;
 };
 
+struct wined3d_cs_execute_command_list
+{
+    enum wined3d_cs_op opcode;
+    struct wined3d_command_list *list;
+};
+
 struct wined3d_cs_stop
 {
     enum wined3d_cs_op opcode;
@@ -599,6 +614,7 @@ static const char *debug_cs_op(enum wined3d_cs_op op)
         WINED3D_TO_STR(WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW);
         WINED3D_TO_STR(WINED3D_CS_OP_COPY_UAV_COUNTER);
         WINED3D_TO_STR(WINED3D_CS_OP_GENERATE_MIPMAPS);
+        WINED3D_TO_STR(WINED3D_CS_OP_EXECUTE_COMMAND_LIST);
         WINED3D_TO_STR(WINED3D_CS_OP_STOP);
 #undef WINED3D_TO_STR
     }
@@ -2314,6 +2330,27 @@ static void wined3d_cs_issue_query(struct wined3d_device_context *context,
         query->state = QUERY_SIGNALLED;
 }
 
+static void wined3d_cs_execute_command_list(struct wined3d_device_context *context,
+        struct wined3d_command_list *list, bool restore_state)
+{
+    struct wined3d_cs_execute_command_list *op;
+    SIZE_T i;
+
+    op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
+    op->opcode = WINED3D_CS_OP_EXECUTE_COMMAND_LIST;
+    op->list = list;
+
+    for (i = 0; i < list->resource_count; ++i)
+        wined3d_resource_acquire(list->resources[i]);
+
+    wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
+
+    if (restore_state)
+        wined3d_device_context_set_state(context, context->state);
+    else
+        wined3d_device_context_reset_state(context);
+}
+
 static void wined3d_cs_exec_preload_resource(struct wined3d_cs *cs, const void *data)
 {
     const struct wined3d_cs_preload_resource *op = data;
@@ -2777,6 +2814,8 @@ static void wined3d_cs_acquire_resource(struct wined3d_device_context *context,
     wined3d_resource_acquire(resource);
 }
 
+static void wined3d_cs_exec_execute_command_list(struct wined3d_cs *cs, const void *data);
+
 static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
 {
     /* WINED3D_CS_OP_NOP                         */ wined3d_cs_exec_nop,
@@ -2828,8 +2867,32 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view,
     /* WINED3D_CS_OP_COPY_UAV_COUNTER            */ wined3d_cs_exec_copy_uav_counter,
     /* WINED3D_CS_OP_GENERATE_MIPMAPS            */ wined3d_cs_exec_generate_mipmaps,
+    /* WINED3D_CS_OP_EXECUTE_COMMAND_LIST        */ wined3d_cs_exec_execute_command_list,
 };
 
+static void wined3d_cs_exec_execute_command_list(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_execute_command_list *op = data;
+    size_t start = 0, end = op->list->data_size;
+    const BYTE *cs_data = op->list->data;
+
+    TRACE("Executing command list %p.\n", op->list);
+
+    while (start < end)
+    {
+        const struct wined3d_cs_packet *packet = (const struct wined3d_cs_packet *)&cs_data[start];
+        enum wined3d_cs_op opcode = *(const enum wined3d_cs_op *)packet->data;
+
+        if (opcode >= WINED3D_CS_OP_STOP)
+            ERR("Invalid opcode %#x.\n", opcode);
+        else
+            wined3d_cs_op_handlers[opcode](cs, packet->data);
+        TRACE("%s executed.\n", debug_cs_op(opcode));
+
+        start += offsetof(struct wined3d_cs_packet, data[packet->size]);
+    }
+}
+
 static void *wined3d_cs_st_require_space(struct wined3d_device_context *context,
         size_t size, enum wined3d_cs_queue_id queue_id)
 {
@@ -2897,6 +2960,7 @@ static const struct wined3d_device_context_ops wined3d_cs_st_ops =
     wined3d_cs_issue_query,
     wined3d_cs_flush,
     wined3d_cs_acquire_resource,
+    wined3d_cs_execute_command_list,
 };
 
 static BOOL wined3d_cs_queue_is_empty(const struct wined3d_cs *cs, const struct wined3d_cs_queue *queue)
@@ -3024,6 +3088,7 @@ static const struct wined3d_device_context_ops wined3d_cs_mt_ops =
     wined3d_cs_issue_query,
     wined3d_cs_flush,
     wined3d_cs_acquire_resource,
+    wined3d_cs_execute_command_list,
 };
 
 static void poll_queries(struct wined3d_cs *cs)
@@ -3235,6 +3300,12 @@ struct wined3d_deferred_context
 
     SIZE_T resource_count, resources_capacity;
     struct wined3d_resource **resources;
+
+    /* List of command lists queued for execution on this context. A command
+     * list can be the only thing holding a pointer to another command list, so
+     * we need to hold a reference here and in wined3d_command_list as well. */
+    SIZE_T command_list_count, command_lists_capacity;
+    struct wined3d_command_list **command_lists;
 };
 
 static struct wined3d_deferred_context *wined3d_deferred_context_from_context(struct wined3d_device_context *context)
@@ -3332,6 +3403,30 @@ static void wined3d_deferred_context_acquire_resource(struct wined3d_device_cont
     wined3d_resource_incref(resource);
 }
 
+static void wined3d_deferred_context_execute_command_list(struct wined3d_device_context *context,
+        struct wined3d_command_list *list, bool restore_state)
+{
+    struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
+    struct wined3d_cs_execute_command_list *op;
+
+    op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
+    op->opcode = WINED3D_CS_OP_EXECUTE_COMMAND_LIST;
+    op->list = list;
+
+    if (restore_state)
+        wined3d_device_context_set_state(context, context->state);
+    else
+        wined3d_device_context_reset_state(context);
+
+    /* Grab a reference to the command list. Note that this implicitly prevents
+     * any dependent command lists or resources from being freed as well. */
+    if (!wined3d_array_reserve((void **)&deferred->command_lists, &deferred->command_lists_capacity,
+            deferred->command_list_count + 1, sizeof(*deferred->command_lists)))
+        return;
+
+    wined3d_command_list_incref(deferred->command_lists[deferred->command_list_count++] = list);
+}
+
 static const struct wined3d_device_context_ops wined3d_deferred_context_ops =
 {
     wined3d_deferred_context_require_space,
@@ -3344,6 +3439,7 @@ static const struct wined3d_device_context_ops wined3d_deferred_context_ops =
     wined3d_deferred_context_issue_query,
     wined3d_deferred_context_flush,
     wined3d_deferred_context_acquire_resource,
+    wined3d_deferred_context_execute_command_list,
 };
 
 HRESULT CDECL wined3d_deferred_context_create(struct wined3d_device *device, struct wined3d_device_context **context)
@@ -3419,8 +3515,21 @@ HRESULT CDECL wined3d_deferred_context_record_command_list(struct wined3d_device
     memcpy(object->resources, deferred->resources, deferred->resource_count * sizeof(*object->resources));
     /* Transfer our references to the resources to the command list. */
 
+    if (!(object->command_lists = heap_alloc(deferred->command_list_count * sizeof(*object->command_lists))))
+    {
+        heap_free(object->resources);
+        heap_free(object->data);
+        heap_free(object);
+        return E_OUTOFMEMORY;
+    }
+    object->command_list_count = deferred->command_list_count;
+    memcpy(object->command_lists, deferred->command_lists,
+            deferred->command_list_count * sizeof(*object->command_lists));
+    /* Transfer our references to the command lists to the command list. */
+
     deferred->data_size = 0;
     deferred->resource_count = 0;
+    deferred->command_list_count = 0;
 
     /* This is in fact recorded into a subsequent command list. */
     if (restore)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 08f986dd5e2..c6b0c9f831e 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -4888,6 +4888,14 @@ void CDECL wined3d_device_context_issue_query(struct wined3d_device_context *con
     context->ops->issue_query(context, query, flags);
 }
 
+void CDECL wined3d_device_context_execute_command_list(struct wined3d_device_context *context,
+        struct wined3d_command_list *list, bool restore_state)
+{
+    TRACE("context %p, list %p, restore_state %d.\n", context, list, restore_state);
+
+    context->ops->execute_command_list(context, list, restore_state);
+}
+
 struct wined3d_rendertarget_view * CDECL wined3d_device_context_get_rendertarget_view(
         const struct wined3d_device_context *context, unsigned int view_idx)
 {
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index 6683b3bc30f..1369fd4cf90 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -95,6 +95,7 @@
 @ cdecl wined3d_device_context_draw_indirect(ptr ptr long long)
 @ cdecl wined3d_device_context_dispatch(ptr long long long)
 @ cdecl wined3d_device_context_dispatch_indirect(ptr ptr long)
+@ cdecl wined3d_device_context_execute_command_list(ptr ptr long)
 @ cdecl wined3d_device_context_flush(ptr)
 @ cdecl wined3d_device_context_generate_mipmaps(ptr ptr)
 @ cdecl wined3d_device_context_get_blend_state(ptr ptr ptr)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index af9beffc142..8e3efccffc2 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -4693,6 +4693,8 @@ struct wined3d_device_context_ops
     void (*issue_query)(struct wined3d_device_context *context, struct wined3d_query *query, unsigned int flags);
     void (*flush)(struct wined3d_device_context *context);
     void (*acquire_resource)(struct wined3d_device_context *context, struct wined3d_resource *resource);
+    void (*execute_command_list)(struct wined3d_device_context *context,
+            struct wined3d_command_list *list, bool restore_state);
 };
 
 struct wined3d_device_context
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index bb6bf58a822..7777e45ad21 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2441,6 +2441,8 @@ void __cdecl wined3d_device_context_draw_indexed(struct wined3d_device_context *
         unsigned int start_index, unsigned int index_count, unsigned int start_instance, unsigned int instance_count);
 void __cdecl wined3d_device_context_draw_indirect(struct wined3d_device_context *context,
         struct wined3d_buffer *buffer, unsigned int offset, bool indexed);
+void __cdecl wined3d_device_context_execute_command_list(struct wined3d_device_context *context,
+        struct wined3d_command_list *list, bool restore_state);
 void __cdecl wined3d_device_context_flush(struct wined3d_device_context *context);
 void __cdecl wined3d_device_context_generate_mipmaps(struct wined3d_device_context *context,
         struct wined3d_shader_resource_view *view);
-- 
2.30.2




More information about the wine-devel mailing list