Signed-off-by: Zebediah Figura z.figura12@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);