diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h index 1a8cdc6d77c..2b5a51afbd1 100644 --- a/dlls/d3d11/d3d11_private.h +++ b/dlls/d3d11/d3d11_private.h @@ -547,6 +547,7 @@ struct d3d11_device_context ID3D11Multithread ID3D11Multithread_iface; LONG refcount; + D3D11_DEVICE_CONTEXT_TYPE type; struct wined3d_device_context *wined3d_context; struct d3d_device *device; diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index 6b3ff22055f..1a02b95772c 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -330,6 +330,11 @@ static void d3d_device_context_state_init(struct d3d_device_context_state *state d3d_device_context_state_AddRef(&state->ID3DDeviceContextState_iface); } +static void d3d11_device_context_cleanup(struct d3d11_device_context *context) +{ + wined3d_private_store_cleanup(&context->private_store); +} + /* ID3D11DeviceContext - immediate context methods */ static inline struct d3d11_device_context *impl_from_ID3D11DeviceContext1(ID3D11DeviceContext1 *iface) @@ -351,7 +356,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_context_QueryInterface(ID3D11Devic { *out = &context->ID3D11DeviceContext1_iface; } - else if (IsEqualGUID(iid, &IID_ID3D11Multithread)) + else if (context->type == D3D11_DEVICE_CONTEXT_IMMEDIATE && IsEqualGUID(iid, &IID_ID3D11Multithread)) { *out = &context->ID3D11Multithread_iface; } @@ -390,6 +395,12 @@ static ULONG STDMETHODCALLTYPE d3d11_device_context_Release(ID3D11DeviceContext1 if (!refcount) { + if (context->type != D3D11_DEVICE_CONTEXT_IMMEDIATE) + { + wined3d_deferred_context_destroy(context->wined3d_context); + d3d11_device_context_cleanup(context); + heap_free(context); + } ID3D11Device2_Release(&context->device->ID3D11Device2_iface); } @@ -2645,9 +2656,11 @@ static void STDMETHODCALLTYPE d3d11_device_context_Flush(ID3D11DeviceContext1 *i static D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE d3d11_device_context_GetType(ID3D11DeviceContext1 *iface) { + struct d3d11_device_context *context = impl_from_ID3D11DeviceContext1(iface); + TRACE("iface %p.\n", iface); - return D3D11_DEVICE_CONTEXT_IMMEDIATE; + return context->type; } static UINT STDMETHODCALLTYPE d3d11_device_context_GetContextFlags(ID3D11DeviceContext1 *iface) @@ -2826,13 +2839,18 @@ static void STDMETHODCALLTYPE d3d11_device_context_SwapDeviceContextState(ID3D11 TRACE("iface %p, state %p, prev %p.\n", iface, state, prev); - if (!state) + if (prev) + *prev = NULL; + + if (context->type != D3D11_DEVICE_CONTEXT_IMMEDIATE) { - if (prev) - *prev = NULL; + WARN("SwapDeviceContextState is not allowed on a deferred context.\n"); return; } + if (!state) + return; + wined3d_mutex_lock(); prev_impl = device->state; @@ -3082,11 +3100,13 @@ static const struct ID3D11MultithreadVtbl d3d11_multithread_vtbl = d3d11_multithread_GetMultithreadProtected, }; -static void d3d11_device_context_init(struct d3d11_device_context *context, struct d3d_device *device) +static void d3d11_device_context_init(struct d3d11_device_context *context, struct d3d_device *device, + D3D11_DEVICE_CONTEXT_TYPE type) { context->ID3D11DeviceContext1_iface.lpVtbl = &d3d11_device_context_vtbl; context->ID3D11Multithread_iface.lpVtbl = &d3d11_multithread_vtbl; context->refcount = 1; + context->type = type; context->device = device; ID3D11Device2_AddRef(&device->ID3D11Device2_iface); @@ -3094,11 +3114,6 @@ static void d3d11_device_context_init(struct d3d11_device_context *context, stru wined3d_private_store_init(&context->private_store); } -static void d3d11_device_context_destroy(struct d3d11_device_context *context) -{ - wined3d_private_store_cleanup(&context->private_store); -} - /* ID3D11Device methods */ static HRESULT STDMETHODCALLTYPE d3d11_device_QueryInterface(ID3D11Device2 *iface, REFIID iid, void **out) @@ -3575,13 +3590,49 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateCounter(ID3D11Device2 *iface return E_NOTIMPL; } +static HRESULT d3d11_deferred_context_create(struct d3d_device *device, + UINT flags, struct d3d11_device_context **context) +{ + struct d3d11_device_context *object; + HRESULT hr; + + if (flags) + FIXME("Ignoring flags %#x.\n", flags); + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + d3d11_device_context_init(object, device, D3D11_DEVICE_CONTEXT_DEFERRED); + + wined3d_mutex_lock(); + if (FAILED(hr = wined3d_deferred_context_create(device->wined3d_device, &object->wined3d_context))) + { + WARN("Failed to create wined3d deferred context, hr %#x.\n", hr); + heap_free(object); + wined3d_mutex_unlock(); + return hr; + } + wined3d_mutex_unlock(); + + TRACE("Created deferred context %p.\n", object); + *context = object; + + return S_OK; +} + static HRESULT STDMETHODCALLTYPE d3d11_device_CreateDeferredContext(ID3D11Device2 *iface, UINT flags, ID3D11DeviceContext **context) { - FIXME("iface %p, flags %#x, context %p stub!\n", iface, flags, context); + struct d3d_device *device = impl_from_ID3D11Device2(iface); + struct d3d11_device_context *object; + HRESULT hr; - *context = NULL; - return E_NOTIMPL; + TRACE("iface %p, flags %#x, context %p.\n", iface, flags, context); + + if (FAILED(hr = d3d11_deferred_context_create(device, flags, &object))) + return hr; + + *context = (ID3D11DeviceContext *)&object->ID3D11DeviceContext1_iface; + return S_OK; } static HRESULT STDMETHODCALLTYPE d3d11_device_OpenSharedResource(ID3D11Device2 *iface, HANDLE resource, REFIID iid, @@ -4302,7 +4353,7 @@ static ULONG STDMETHODCALLTYPE d3d_device_inner_Release(IUnknown *iface) d3d_device_context_state_remove_entry(device->context_states[i], device); } heap_free(device->context_states); - d3d11_device_context_destroy(&device->immediate_context); + d3d11_device_context_cleanup(&device->immediate_context); if (device->wined3d_device) { wined3d_mutex_lock(); @@ -6655,7 +6706,7 @@ void d3d_device_init(struct d3d_device *device, void *outer_unknown) device->d3d11_only = FALSE; device->state = NULL; - d3d11_device_context_init(&device->immediate_context, device); + d3d11_device_context_init(&device->immediate_context, device, D3D11_DEVICE_CONTEXT_IMMEDIATE); ID3D11DeviceContext1_Release(&device->immediate_context.ID3D11DeviceContext1_iface); wine_rb_init(&device->blend_states, d3d_blend_state_compare); diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index a88b2511d3d..77ea747d981 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -2266,6 +2266,8 @@ static void test_create_deferred_context(void) hr = ID3D11Device_CreateDeferredContext(device, 0, &context); todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Failed to create deferred context, hr %#x.\n", hr); + if (hr == S_OK) + ID3D11DeviceContext_Release(context); refcount = ID3D11Device_Release(device); ok(!refcount, "Device has %u references left.\n", refcount); @@ -2278,9 +2280,7 @@ static void test_create_deferred_context(void) expected_refcount = get_refcount(device) + 1; hr = ID3D11Device_CreateDeferredContext(device, 0, &context); - todo_wine ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr); - if (FAILED(hr)) - goto done; + ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr); refcount = get_refcount(device); ok(refcount == expected_refcount, "Got refcount %u, expected %u.\n", refcount, expected_refcount); refcount = get_refcount(context); @@ -2294,7 +2294,6 @@ static void test_create_deferred_context(void) refcount = ID3D11DeviceContext_Release(context); ok(!refcount, "Got unexpected refcount %u.\n", refcount); -done: refcount = ID3D11Device_Release(device); ok(!refcount, "Device has %u references left.\n", refcount); } @@ -32257,14 +32256,7 @@ static void test_deferred_context_state(void) ID3D11DeviceContext_PSSetConstantBuffers(immediate, 0, 1, &green_buffer); hr = ID3D11Device_CreateDeferredContext(device, 0, &deferred); - todo_wine ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr); - if (hr != S_OK) - { - ID3D11Buffer_Release(blue_buffer); - ID3D11Buffer_Release(green_buffer); - release_test_context(&test_context); - return; - } + ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr); ID3D11DeviceContext_PSGetConstantBuffers(deferred, 0, 1, &ret_buffer); ok(!ret_buffer, "Got unexpected buffer %p.\n", ret_buffer); @@ -32276,7 +32268,15 @@ static void test_deferred_context_state(void) ID3D11Buffer_Release(ret_buffer); hr = ID3D11DeviceContext_FinishCommandList(deferred, TRUE, &list1); - ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr); + todo_wine ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr); + if (hr != S_OK) + { + ID3D11DeviceContext_Release(deferred); + ID3D11Buffer_Release(blue_buffer); + ID3D11Buffer_Release(green_buffer); + release_test_context(&test_context); + return; + } ID3D11DeviceContext_PSGetConstantBuffers(deferred, 0, 1, &ret_buffer); ok(ret_buffer == blue_buffer, "Got unexpected buffer %p.\n", ret_buffer); @@ -32455,12 +32455,7 @@ static void test_deferred_context_rendering(void) immediate = test_context.immediate_context; hr = ID3D11Device_CreateDeferredContext(device, 0, &deferred); - todo_wine ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr); - if (hr != S_OK) - { - release_test_context(&test_context); - return; - } + ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr); memset(&blend_desc, 0, sizeof(blend_desc)); @@ -32479,7 +32474,16 @@ static void test_deferred_context_rendering(void) ID3D11DeviceContext_ClearRenderTargetView(deferred, test_context.backbuffer_rtv, green); hr = ID3D11DeviceContext_FinishCommandList(deferred, TRUE, &list1); - ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr); + todo_wine ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr); + if (hr != S_OK) + { + ID3D11BlendState_Release(red_blend); + ID3D11BlendState_Release(green_blend); + ID3D11BlendState_Release(blue_blend); + ID3D11DeviceContext_Release(deferred); + release_test_context(&test_context); + return; + } hr = ID3D11DeviceContext_FinishCommandList(deferred, TRUE, &list2); ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr); @@ -32716,12 +32720,7 @@ static void test_deferred_context_map(void) immediate = test_context.immediate_context; hr = ID3D11Device_CreateDeferredContext(device, 0, &deferred); - todo_wine ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr); - if (hr != S_OK) - { - release_test_context(&test_context); - return; - } + ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr); for (i = 0; i < ARRAY_SIZE(data); ++i) data[i] = i; @@ -32745,13 +32744,21 @@ static void test_deferred_context_map(void) ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); hr = ID3D11DeviceContext_Map(deferred, (ID3D11Resource *)buffer, 0, D3D11_MAP_WRITE, 0, &map_desc); - ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); hr = ID3D11DeviceContext_Map(deferred, (ID3D11Resource *)buffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map_desc); - ok(hr == D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD, "Got unexpected hr %#x.\n", hr); + todo_wine ok(hr == D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD, "Got unexpected hr %#x.\n", hr); hr = ID3D11DeviceContext_Map(deferred, (ID3D11Resource *)buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map_desc); - ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + if (hr != S_OK) + { + ID3D11Buffer_Release(buffer2); + ID3D11Buffer_Release(buffer); + ID3D11DeviceContext_Release(deferred); + release_test_context(&test_context); + return; + } map_data = map_desc.pData; /* The previous contents of map_data are undefined and may in practice be * uninitialized garbage. */ diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 8702ac08631..3f05d593b7c 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -3162,3 +3162,149 @@ void wined3d_cs_destroy(struct wined3d_cs *cs) heap_free(cs->data); heap_free(cs); } + +struct wined3d_deferred_context +{ + struct wined3d_device_context c; + + SIZE_T data_size, data_capacity; + void *data; +}; + +static struct wined3d_deferred_context *wined3d_deferred_context_from_context(struct wined3d_device_context *context) +{ + return CONTAINING_RECORD(context, struct wined3d_deferred_context, c); +} + +static void *wined3d_deferred_context_require_space(struct wined3d_device_context *context, + size_t size, enum wined3d_cs_queue_id queue_id) +{ + struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context); + struct wined3d_cs_packet *packet; + size_t header_size, packet_size; + + assert(queue_id == WINED3D_CS_QUEUE_DEFAULT); + + header_size = offsetof(struct wined3d_cs_packet, data[0]); + packet_size = offsetof(struct wined3d_cs_packet, data[size]); + packet_size = (packet_size + header_size - 1) & ~(header_size - 1); + + if (!wined3d_array_reserve(&deferred->data, &deferred->data_capacity, deferred->data_size + packet_size, 1)) + return NULL; + + packet = (struct wined3d_cs_packet *)((BYTE *)deferred->data + deferred->data_size); + TRACE("size was %zu, adding %zu\n", (size_t)deferred->data_size, packet_size); + deferred->data_size += packet_size; + packet->size = packet_size - header_size; + return &packet->data; +} + +static void wined3d_deferred_context_submit(struct wined3d_device_context *context, enum wined3d_cs_queue_id queue_id) +{ + assert(queue_id == WINED3D_CS_QUEUE_DEFAULT); + + /* Nothing to do. */ +} + +static void wined3d_deferred_context_finish(struct wined3d_device_context *context, enum wined3d_cs_queue_id queue_id) +{ + /* This should not happen; we cannot meaningfully finish a deferred context. */ + ERR("Ignoring finish() on a deferred context.\n"); +} + +static void wined3d_deferred_context_push_constants(struct wined3d_device_context *context, + enum wined3d_push_constants p, unsigned int start_idx, unsigned int count, const void *constants) +{ + FIXME("context %p, p %#x, start_idx %u, count %u, constants %p, stub!\n", context, p, start_idx, count, constants); +} + +static HRESULT wined3d_deferred_context_map(struct wined3d_device_context *context, + struct wined3d_resource *resource, unsigned int sub_resource_idx, + struct wined3d_map_desc *map_desc, const struct wined3d_box *box, unsigned int flags) +{ + FIXME("context %p, resource %p, sub_resource_idx %u, map_desc %p, box %p, flags %#x, stub!\n", + context, resource, sub_resource_idx, map_desc, box, flags); + return E_NOTIMPL; +} + +static HRESULT wined3d_deferred_context_unmap(struct wined3d_device_context *context, + struct wined3d_resource *resource, unsigned int sub_resource_idx) +{ + FIXME("context %p, resource %p, sub_resource_idx %u, stub!\n", context, resource, sub_resource_idx); + return E_NOTIMPL; +} + +static void wined3d_deferred_context_update_sub_resource(struct wined3d_device_context *context, + struct wined3d_resource *resource, unsigned int sub_resource_idx, const struct wined3d_box *box, + const void *data, unsigned int row_pitch, unsigned int slice_pitch) +{ + FIXME("context %p, resource %p, sub_resource_idx %u, box %s, data %p, row_pitch %u, slice_pitch %u, stub!\n", + context, resource, sub_resource_idx, debug_box(box), data, row_pitch, slice_pitch); +} + +static void wined3d_deferred_context_issue_query(struct wined3d_device_context *context, + struct wined3d_query *query, unsigned int flags) +{ + FIXME("context %p, query %p, flags %#x, stub!\n", context, query, flags); +} + +static void wined3d_deferred_context_flush(struct wined3d_device_context *context) +{ + FIXME("context %p, stub!\n", context); +} + +static void wined3d_deferred_context_acquire_resource(struct wined3d_device_context *context, + struct wined3d_resource *resource) +{ + FIXME("context %p, resource %p, stub!\n", context, resource); +} + +static const struct wined3d_device_context_ops wined3d_deferred_context_ops = +{ + wined3d_deferred_context_require_space, + wined3d_deferred_context_submit, + wined3d_deferred_context_finish, + wined3d_deferred_context_push_constants, + wined3d_deferred_context_map, + wined3d_deferred_context_unmap, + wined3d_deferred_context_update_sub_resource, + wined3d_deferred_context_issue_query, + wined3d_deferred_context_flush, + wined3d_deferred_context_acquire_resource, +}; + +HRESULT CDECL wined3d_deferred_context_create(struct wined3d_device *device, struct wined3d_device_context **context) +{ + struct wined3d_deferred_context *object; + HRESULT hr; + + TRACE("device %p, context %p.\n", device, context); + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = wined3d_state_create(device, &device->cs->c.state->feature_level, 1, &object->c.state))) + { + heap_free(object); + return hr; + } + + object->c.ops = &wined3d_deferred_context_ops; + object->c.device = device; + + TRACE("Created deferred context %p.\n", object); + *context = &object->c; + + return S_OK; +} + +void CDECL wined3d_deferred_context_destroy(struct wined3d_device_context *context) +{ + struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context); + + TRACE("context %p.\n", context); + + wined3d_state_destroy(deferred->c.state); + heap_free(deferred->data); + heap_free(deferred); +} diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index ece69929c65..be88f8a60db 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -33,6 +33,9 @@ @ cdecl wined3d_buffer_get_resource(ptr) @ cdecl wined3d_buffer_incref(ptr) +@ cdecl wined3d_deferred_context_create(ptr ptr) +@ cdecl wined3d_deferred_context_destroy(ptr) + @ cdecl wined3d_depth_stencil_state_create(ptr ptr ptr ptr ptr) @ cdecl wined3d_depth_stencil_state_decref(ptr) @ cdecl wined3d_depth_stencil_state_get_parent(ptr) diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index db567784de6..f75047be873 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2340,6 +2340,9 @@ void * __cdecl wined3d_buffer_get_parent(const struct wined3d_buffer *buffer); struct wined3d_resource * __cdecl wined3d_buffer_get_resource(struct wined3d_buffer *buffer); ULONG __cdecl wined3d_buffer_incref(struct wined3d_buffer *buffer); +HRESULT __cdecl wined3d_deferred_context_create(struct wined3d_device *device, struct wined3d_device_context **context); +void __cdecl wined3d_deferred_context_destroy(struct wined3d_device_context *context); + HRESULT __cdecl wined3d_depth_stencil_state_create(struct wined3d_device *device, const struct wined3d_depth_stencil_state_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_depth_stencil_state **state);