d3d11: Implement ID3D11Device::CreateDeferredContext().

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=42191
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-05-27 11:14:29 -05:00 committed by Alexandre Julliard
parent a17c0a7213
commit 60027fcc23
6 changed files with 256 additions and 45 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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. */

View file

@ -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);
}

View file

@ -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)

View file

@ -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);