From: Charlotte Pabst <cpabst@codeweavers.com> --- dlls/mfplat/tests/mfplat.c | 854 ++++++++++++++++++++++++++++++++++++- 1 file changed, 850 insertions(+), 4 deletions(-) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 1e6fa0639c3..c81f8738d01 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -516,6 +516,214 @@ static void put_d3d11_texture_color(ID3D11Texture2D *texture, unsigned int x, un release_d3d11_resource_readback(&rb, TRUE); } +struct d3d12_resource_readback +{ + BOOL upload; + ID3D12Resource *resource; + ID3D12Resource *parent_resource; + IMFD3D12SynchronizationObjectCommands *sync; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint; + unsigned int sub_resource_idx; + void *data; +}; + +static HRESULT copy_d3d12_resource_readback(struct d3d12_resource_readback *rb) +{ + D3D12_COMMAND_QUEUE_DESC queue_desc = { .Type = D3D12_COMMAND_LIST_TYPE_COPY }; + D3D12_RESOURCE_BARRIER pre_barrier, post_barrier; + D3D12_TEXTURE_COPY_LOCATION res_loc, rb_loc; + ID3D12Device *device = NULL; + ID3D12CommandAllocator *allocator = NULL; + ID3D12GraphicsCommandList *list = NULL; + ID3D12CommandQueue *queue = NULL; + ID3D12Fence *fence = NULL; + HRESULT hr; + + hr = ID3D12Resource_GetDevice(rb->resource, &IID_ID3D12Device, (void **) &device); + if (FAILED(hr)) goto end; + + hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_COPY, + &IID_ID3D12CommandAllocator, (void **) &allocator); + if (FAILED(hr)) goto end; + + hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_COPY, allocator, NULL, + &IID_ID3D12GraphicsCommandList, (void **) &list); + if (FAILED(hr)) goto end; + + hr = ID3D12Device_CreateCommandQueue(device, &queue_desc, &IID_ID3D12CommandQueue, (void **) &queue); + if (FAILED(hr)) goto end; + + hr = ID3D12Device_CreateFence(device, 0, 0, &IID_ID3D12Fence, (void **) &fence); + if (FAILED(hr)) goto end; + + res_loc.pResource = rb->parent_resource; + res_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + res_loc.SubresourceIndex = rb->sub_resource_idx; + rb_loc.pResource = rb->resource; + rb_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + rb_loc.PlacedFootprint = rb->footprint; + + pre_barrier.Type = post_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + pre_barrier.Flags = post_barrier.Flags = 0; + pre_barrier.Transition.pResource = post_barrier.Transition.pResource = rb->parent_resource; + pre_barrier.Transition.Subresource = post_barrier.Transition.Subresource = rb->sub_resource_idx; + pre_barrier.Transition.StateBefore = post_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON; + pre_barrier.Transition.StateAfter = post_barrier.Transition.StateBefore = rb->upload ? D3D12_RESOURCE_STATE_COPY_DEST : D3D12_RESOURCE_STATE_COPY_SOURCE; + + ID3D12GraphicsCommandList_ResourceBarrier(list, 1, &pre_barrier); + ID3D12GraphicsCommandList_CopyTextureRegion(list, rb->upload ? &res_loc : &rb_loc, 0, 0, 0, rb->upload ? &rb_loc : &res_loc, NULL); + ID3D12GraphicsCommandList_ResourceBarrier(list, 1, &post_barrier); + ID3D12GraphicsCommandList_Close(list); + + if (!rb->upload) + IMFD3D12SynchronizationObjectCommands_EnqueueResourceReadyWait(rb->sync, queue); + + ID3D12CommandQueue_ExecuteCommandLists(queue, 1, (ID3D12CommandList **) &list); + + if (rb->upload) + IMFD3D12SynchronizationObjectCommands_EnqueueResourceReady(rb->sync, queue); + + ID3D12CommandQueue_Signal(queue, fence, 1); + ID3D12Fence_SetEventOnCompletion(fence, 1, NULL); + + hr = S_OK; + +end: + if (device) ID3D12Device_Release(device); + if (allocator) ID3D12CommandAllocator_Release(allocator); + if (list) ID3D12GraphicsCommandList_Release(list); + if (queue) ID3D12CommandQueue_Release(queue); + if (fence) ID3D12Fence_Release(fence); + + return hr; +} + +static HRESULT get_d3d12_resource_readback(ID3D12Resource *resource, IMFD3D12SynchronizationObjectCommands *sync, + unsigned int sub_resource_idx, struct d3d12_resource_readback *rb, BOOL upload) +{ + D3D12_HEAP_PROPERTIES heap_prop = { .Type = upload ? D3D12_HEAP_TYPE_UPLOAD : D3D12_HEAP_TYPE_READBACK }; + D3D12_RESOURCE_DESC desc; + D3D12_RANGE empty_range = { 0, 0 }; + UINT64 bytes; + ID3D12Device *device = NULL; + HRESULT hr; + + memset(rb, 0, sizeof(*rb)); + + rb->upload = upload; + rb->parent_resource = resource; + rb->sub_resource_idx = sub_resource_idx; + rb->sync = sync; + + hr = ID3D12Resource_GetDevice(rb->parent_resource, &IID_ID3D12Device, (void **) &device); + if (FAILED(hr)) goto end; + + desc = ID3D12Resource_GetDesc(rb->parent_resource); + ID3D12Device_GetCopyableFootprints(device, &desc, rb->sub_resource_idx, 1, 0, &rb->footprint, NULL, NULL, &bytes); + rb->footprint.Offset = 0; + + memset(&desc, 0, sizeof(desc)); + desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + desc.Alignment = 0; + desc.Width = bytes; + desc.Height = 1; + desc.DepthOrArraySize = 1; + desc.MipLevels = 1; + desc.Format = DXGI_FORMAT_UNKNOWN; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + desc.Flags = 0; + + hr = ID3D12Device_CreateCommittedResource(device, &heap_prop, D3D12_HEAP_FLAG_NONE, &desc, + rb->upload ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST, NULL, + &IID_ID3D12Resource, (void **) &rb->resource); + if (FAILED(hr)) goto end; + + if (!rb->upload) + { + hr = copy_d3d12_resource_readback(rb); + if (FAILED(hr)) goto end; + } + + hr = ID3D12Resource_Map(rb->resource, 0, rb->upload ? &empty_range : NULL, &rb->data); + +end: + if (FAILED(hr) && rb->resource) + { + ID3D12Resource_Release(rb->resource); + rb->resource = NULL; + } + if (device) ID3D12Device_Release(device); + return hr; +} + +static void release_d3d12_resource_readback(struct d3d12_resource_readback *rb) +{ + D3D12_RANGE empty_range = { 0, 0 }; + + if (rb->resource) + { + ID3D12Resource_Unmap(rb->resource, 0, rb->upload ? NULL : &empty_range); + if (rb->upload) + copy_d3d12_resource_readback(rb); + ID3D12Resource_Release(rb->resource); + } +} + +static void *get_d3d12_readback_data(struct d3d12_resource_readback *rb, + unsigned int x, unsigned int y, unsigned int z, unsigned byte_width) +{ + return (BYTE *)rb->data + rb->footprint.Offset + (z * rb->footprint.Footprint.Height + y) * rb->footprint.Footprint.RowPitch + x * byte_width; +} + +static DWORD get_d3d12_readback_u32(struct d3d12_resource_readback *rb, unsigned int x, unsigned int y, unsigned int z) +{ + return *(DWORD *)get_d3d12_readback_data(rb, x, y, z, sizeof(DWORD)); +} + +static DWORD get_d3d12_readback_color(struct d3d12_resource_readback *rb, unsigned int x, unsigned int y, unsigned int z) +{ + return get_d3d12_readback_u32(rb, x, y, z); +} + +static DWORD get_d3d12_texture_color(ID3D12Resource *resource, IMFD3D12SynchronizationObjectCommands *sync, unsigned int sub_resource_idx, unsigned int x, unsigned int y) +{ + struct d3d12_resource_readback rb; + DWORD color; + HRESULT hr; + + hr = get_d3d12_resource_readback(resource, sync, sub_resource_idx, &rb, FALSE); + ok(SUCCEEDED(hr), "unexpected hr: %#08lx\n", hr); + color = get_d3d12_readback_color(&rb, x, y, 0); + release_d3d12_resource_readback(&rb); + + return color; +} + +static void put_d3d12_readback_u32(struct d3d12_resource_readback *rb, + unsigned int x, unsigned int y, unsigned int z, DWORD color) +{ + *(DWORD *)get_d3d12_readback_data(rb, x, y, z, sizeof(DWORD)) = color; +} + +static void put_d3d12_readback_color(struct d3d12_resource_readback *rb, + unsigned int x, unsigned int y, unsigned int z, DWORD color) +{ + put_d3d12_readback_u32(rb, x, y, z, color); +} + +static void put_d3d12_texture_color(ID3D12Resource *resource, IMFD3D12SynchronizationObjectCommands *sync, unsigned int sub_resource_idx, unsigned int x, unsigned int y, DWORD color) +{ + struct d3d12_resource_readback rb; + HRESULT hr; + + hr = get_d3d12_resource_readback(resource, sync, sub_resource_idx, &rb, TRUE); + ok(SUCCEEDED(hr), "unexpected hr: %#08lx\n", hr); + put_d3d12_readback_color(&rb, x, y, 0, color); + release_d3d12_resource_readback(&rb); +} + static HRESULT (WINAPI *pD3D11CreateDevice)(IDXGIAdapter *adapter, D3D_DRIVER_TYPE driver_type, HMODULE swrast, UINT flags, const D3D_FEATURE_LEVEL *feature_levels, UINT levels, UINT sdk_version, ID3D11Device **device_out, D3D_FEATURE_LEVEL *obtained_feature_level, ID3D11DeviceContext **immediate_context); @@ -11462,6 +11670,51 @@ static void test_d3d11_surface_buffer(void) ID3D11Device_Release(device); } +enum test_d3d12_buffer_lock_kind +{ + TEST_D3D12_BUFFER_LOCK = 0, + TEST_D3D12_BUFFER_LOCK2D, + TEST_D3D12_BUFFER_LOCK2DSIZE_READ, + TEST_D3D12_BUFFER_LOCK2DSIZE_READWRITE, + TEST_D3D12_BUFFER_LOCK_COUNT, +}; + +struct test_d3d12_buffer_lock_param +{ + IMFMediaBuffer *buffer; + IMF2DBuffer2 *_2dbuffer2; + enum test_d3d12_buffer_lock_kind kind; +}; + +static DWORD CALLBACK test_d3d12_buffer_lock_thread(void *arg) +{ + struct test_d3d12_buffer_lock_param *param = arg; + BYTE *scanline0, *start; + LONG pitch; + DWORD max_length, cur_length; + HRESULT hr = S_OK; + + switch (param->kind) + { + case TEST_D3D12_BUFFER_LOCK: + hr = IMFMediaBuffer_Lock(param->buffer, &scanline0, &max_length, &cur_length); + break; + case TEST_D3D12_BUFFER_LOCK2D: + hr = IMF2DBuffer2_Lock2D(param->_2dbuffer2, &scanline0, &pitch); + break; + case TEST_D3D12_BUFFER_LOCK2DSIZE_READ: + hr = IMF2DBuffer2_Lock2DSize(param->_2dbuffer2, MF2DBuffer_LockFlags_Read, &scanline0, &pitch, &start, &max_length); + break; + case TEST_D3D12_BUFFER_LOCK2DSIZE_READWRITE: + hr = IMF2DBuffer2_Lock2DSize(param->_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &scanline0, &pitch, &start, &max_length); + break; + default: break; + } + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + return 0; +} + static void test_d3d12_surface_buffer(void) { IMFDXGIBuffer *dxgi_buffer; @@ -11469,9 +11722,24 @@ static void test_d3d12_surface_buffer(void) D3D12_RESOURCE_DESC desc; ID3D12Resource *resource; IMFMediaBuffer *buffer; + IMF2DBuffer *_2d_buffer; + IMF2DBuffer2 *_2dbuffer2; unsigned int refcount; ID3D12Device *device; IUnknown *obj; + IMFD3D12SynchronizationObject *sync_obj; + IMFD3D12SynchronizationObjectCommands *sync_cmd; + ID3D12CommandQueue *queue; + D3D12_COMMAND_QUEUE_DESC queue_desc = { .Type = D3D12_COMMAND_LIST_TYPE_COPY }; + struct test_d3d12_buffer_lock_param buffer_lock_param; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout; + DWORD max_length, cur_length, length, color; + BYTE *data, *data2, *buffer_start; + LONG pitch, pitch2; + UINT index; + UINT64 total_bytes; + HANDLE event, thread; + DWORD status; HRESULT hr; /* d3d12 */ @@ -11481,6 +11749,9 @@ static void test_d3d12_surface_buffer(void) return; } + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + memset(&heap_props, 0, sizeof(heap_props)); heap_props.Type = D3D12_HEAP_TYPE_DEFAULT; @@ -11497,6 +11768,8 @@ static void test_d3d12_surface_buffer(void) desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + ID3D12Device_GetCopyableFootprints(device, &desc, 0, 1, 0, &layout, NULL, NULL, &total_bytes); + hr = ID3D12Device_CreateCommittedResource(device, &heap_props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&resource); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -11506,6 +11779,7 @@ static void test_d3d12_surface_buffer(void) { todo_wine win_skip("D3D12 resource buffers are not supported.\n"); + ID3D12Resource_Release(resource); goto notsupported; } ok(hr == S_OK, "Failed to create a buffer, hr %#lx.\n", hr); @@ -11517,20 +11791,592 @@ if (SUCCEEDED(hr)) check_interface(buffer, &IID_IMFDXGIBuffer, TRUE); check_interface(buffer, &IID_IMFGetService, FALSE); + max_length = 0; + hr = IMFMediaBuffer_GetMaxLength(buffer, &max_length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(max_length == total_bytes, "Unexpected length %lu.\n", max_length); + + hr = IMFMediaBuffer_GetCurrentLength(buffer, &cur_length); + ok(hr == S_OK, "Failed to get length, hr %#lx.\n", hr); + ok(!cur_length, "Unexpected length %lu.\n", cur_length); + + hr = IMFMediaBuffer_SetCurrentLength(buffer, 4096); + ok(hr == S_OK, "Failed to set length, hr %#lx.\n", hr); + + hr = IMFMediaBuffer_GetCurrentLength(buffer, &cur_length); + ok(hr == S_OK, "Failed to get length, hr %#lx.\n", hr); + ok(!cur_length, "Unexpected length %lu.\n", cur_length); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer_GetContiguousLength(_2d_buffer, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_GetContiguousLength(_2d_buffer, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(length == desc.Height * desc.Width * 4, "Unexpected length %lu.\n", length); + IMF2DBuffer_Release(_2d_buffer); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer); ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr); + EXPECT_REF(resource, 2); hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D12Resource, (void **)&obj); ok(hr == S_OK, "Failed to get resource, hr %#lx.\n", hr); + EXPECT_REF(resource, 3); ok(obj == (IUnknown *)resource, "Unexpected resource pointer.\n"); IUnknown_Release(obj); + hr = IMFDXGIBuffer_GetSubresourceIndex(dxgi_buffer, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IMFDXGIBuffer_GetSubresourceIndex(dxgi_buffer, &index); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(index == 0, "Unexpected subresource index.\n"); + + hr = IMFDXGIBuffer_SetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFDXGIBuffer_SetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, (void *)device); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFDXGIBuffer_SetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, (void *)device); + ok(hr == HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS), "Unexpected hr %#lx.\n", hr); + + hr = IMFDXGIBuffer_GetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, &IID_ID3D12Device, (void **)&obj); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(obj == (IUnknown *)device, "Unexpected pointer.\n"); + IUnknown_Release(obj); + + hr = IMFDXGIBuffer_SetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFDXGIBuffer_GetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, &IID_IUnknown, (void **)&obj); + ok(hr == MF_E_NOT_FOUND, "Unexpected hr %#lx.\n", hr); + + hr = IMFDXGIBuffer_GetUnknown(dxgi_buffer, &MF_D3D12_SYNCHRONIZATION_OBJECT, &IID_IMFD3D12SynchronizationObject, (void **) &sync_obj); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFD3D12SynchronizationObject_Release(sync_obj); + + hr = IMFDXGIBuffer_GetUnknown(dxgi_buffer, &MF_D3D12_SYNCHRONIZATION_OBJECT, &IID_IMFD3D12SynchronizationObjectCommands, (void **) &sync_cmd); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFDXGIBuffer_Release(dxgi_buffer); - IMFMediaBuffer_Release(buffer); -} -notsupported: - ID3D12Resource_Release(resource); + hr = ID3D12Device_CreateCommandQueue(device, &queue_desc, &IID_ID3D12CommandQueue, (void **) &queue); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFD3D12SynchronizationObjectCommands_EnqueueResourceReady(sync_cmd, queue); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Lock() is readonly */ + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(!color, "Unexpected texture color %#lx.\n", color); + + max_length = cur_length = 0; + data = NULL; + hr = IMFMediaBuffer_Lock(buffer, &data, &max_length, &cur_length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(max_length && max_length == cur_length, "Unexpected length %lu.\n", max_length); + if (data) *(DWORD *)data = ~0u; + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(!color, "Unexpected texture color %#lx.\n", color); + + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(!color, "Unexpected texture color %#lx.\n", color); + + hr = IMFMediaBuffer_Lock(buffer, &data, &max_length, &cur_length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!*(DWORD *)data, "Unexpected buffer %#lx.\n", *(DWORD *)data); + + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Lock2DSize(Write) -> Unlock2D() success */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Lock2DSize(ReadWrite) -> Unlock2D() failure */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + /* Lock2DSize(Write) -> Unlock2D() now fails */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + put_d3d12_texture_color(resource, sync_cmd, 0, 1, 0, 0xcdcdcdcd); + + /* Lock2DSize(Read) -> Unlock2D() success */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Recent write was not picked up */ + ok(!((DWORD *)data)[1], "Unexpected dword %#lx.\n", ((DWORD *)data)[1]); + + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Lock2DSize(Write) -> Unlock2D() succeeds again after read */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Lock2D() is readonly, Unlock2D() fails */ + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + if (data) *(DWORD *)data = ~0u; + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(!color, "Unexpected texture color %#lx.\n", color); + + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(!color, "Unexpected texture color %#lx.\n", color); + + /* Lock2DSize() with ReadWrite is readonly, Unlock2D() fails */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + if (data) *(DWORD *)data = ~0u; + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(!color, "Unexpected texture color %#lx.\n", color); + + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(!color, "Unexpected texture color %#lx.\n", color); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Texture updates. */ + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(!color, "Unexpected texture color %#lx.\n", color); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(length == layout.Footprint.Height * layout.Footprint.RowPitch, "Unexpected length %lu.\n", length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (data) *(DWORD *)data = ~0u; + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(!color, "Unexpected texture color %#lx.\n", color); + + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(color == ~0u, "Unexpected texture color %#lx.\n", color); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(*(DWORD *)data == ~0u, "Unexpected buffer %#lx.\n", *(DWORD *)data); + + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Lock2D()/Unlock2D() */ + hr = IMF2DBuffer_GetScanline0AndPitch(_2d_buffer, &data2, &pitch2); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED), "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!data && pitch == layout.Footprint.RowPitch, "Unexpected pitch %ld.\n", pitch); + + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!data && pitch == layout.Footprint.RowPitch, "Unexpected pitch %ld.\n", pitch); + + hr = IMF2DBuffer_GetScanline0AndPitch(_2d_buffer, &data2, &pitch2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(data2 == data && pitch2 == pitch, "Unexpected data/pitch.\n"); + + hr = IMFMediaBuffer_Lock(buffer, &data, &max_length, &cur_length); + ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED), "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == MF_E_UNEXPECTED, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMF2DBuffer_Release(_2d_buffer); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Lock flags are honored, so reads and writes are discarded if + * the flags are not correct. Also, previous content is discarded + * when locking for writing and not for reading. */ + put_d3d12_texture_color(resource, sync_cmd, 0, 0, 0, 0xcdcdcdcd); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(data == data2, "Unexpected scanline pointer.\n"); + ok(*(DWORD *)data == 0xcdcdcdcd, "Unexpected leading dword %#lx.\n", *(DWORD *)data); + memset(data, 0xab, 4); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(color == 0xcdcdcdcd, "Unexpected leading dword %#lx.\n", color); + put_d3d12_texture_color(resource, sync_cmd, 0, 0, 0, 0xefefefef); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(*(DWORD *)data != 0xefefefef, "Unexpected leading dword.\n"); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(color != 0xefefefef, "Unexpected leading dword.\n"); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(*(DWORD *)data != 0xefefefef, "Unexpected leading dword.\n"); + memset(data, 0x89, 4); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(color == 0x89898989, "Unexpected leading dword %#lx.\n", color); + + /* When relocking for writing, stores are not committed if they + * were issued before relocking. */ + put_d3d12_texture_color(resource, sync_cmd, 0, 0, 0, 0xcdcdcdcd); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + memset(data, 0xab, 4); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(color == 0xcdcdcdcd, "Unexpected leading dword %#lx.\n", color); + + /* When relocking for writing, stores are not committed if they + * were issued after relocking. */ + put_d3d12_texture_color(resource, sync_cmd, 0, 0, 0, 0xcdcdcdcd); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + memset(data, 0xab, 4); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + + color = get_d3d12_texture_color(resource, sync_cmd, 0, 0, 0); + ok(color == 0xcdcdcdcd, "Unexpected leading dword %#lx.\n", color); + + /* Flags incompatibilities. */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Except when originally locking for writing. */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_LOCKED), "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_LOCKED), "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_LOCKED), "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED), "Unexpected hr %#lx.\n", hr); + + IMF2DBuffer2_Release(_2dbuffer2); + IMFD3D12SynchronizationObjectCommands_Release(sync_cmd); + IMFMediaBuffer_Release(buffer); + + /* Read blocks on ResourceReady, issues ResourceRelease */ + event = CreateEventA(NULL, FALSE, FALSE, NULL); + for (enum test_d3d12_buffer_lock_kind kind = 0; kind < TEST_D3D12_BUFFER_LOCK_COUNT; kind++) + { + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D12Resource, (IUnknown *)resource, 0, FALSE, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **) &dxgi_buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **) &_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFDXGIBuffer_GetUnknown(dxgi_buffer, &MF_D3D12_SYNCHRONIZATION_OBJECT, + &IID_IMFD3D12SynchronizationObject, (void **)&sync_obj); + hr = IMFDXGIBuffer_GetUnknown(dxgi_buffer, &MF_D3D12_SYNCHRONIZATION_OBJECT, + &IID_IMFD3D12SynchronizationObjectCommands, (void **)&sync_cmd); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + buffer_lock_param.buffer = buffer; + buffer_lock_param._2dbuffer2 = _2dbuffer2; + buffer_lock_param.kind = kind; + + thread = CreateThread(NULL, 0, test_d3d12_buffer_lock_thread, &buffer_lock_param, 0, NULL); + + status = WaitForSingleObject(thread, 100); + ok(status == WAIT_TIMEOUT, "got %#lx.\n", status); + hr = IMFD3D12SynchronizationObject_SignalEventOnFinalResourceRelease(sync_obj, event); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + status = WaitForSingleObject(event, 100); + ok(status == WAIT_TIMEOUT, "got %#lx.\n", status); + + hr = IMFD3D12SynchronizationObjectCommands_EnqueueResourceReady(sync_cmd, queue); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + status = WaitForSingleObject(thread, 100); + ok(status == WAIT_OBJECT_0, "got %#lx.\n", status); + status = WaitForSingleObject(event, 100); + ok(status == WAIT_OBJECT_0, "got %#lx.\n", status); + + CloseHandle(thread); + + if (kind == TEST_D3D12_BUFFER_LOCK) + hr = IMFMediaBuffer_Unlock(buffer); + else + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + + if (kind == TEST_D3D12_BUFFER_LOCK2D || kind == TEST_D3D12_BUFFER_LOCK2DSIZE_READWRITE) + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + else + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFD3D12SynchronizationObject_Release(sync_obj); + IMFD3D12SynchronizationObjectCommands_Release(sync_cmd); + IMFDXGIBuffer_Release(dxgi_buffer); + IMF2DBuffer2_Release(_2dbuffer2); + IMFMediaBuffer_Release(buffer); + } + + /* Write signals ResourceReady */ + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D12Resource, (IUnknown *)resource, 0, FALSE, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **) &_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **) &dxgi_buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFDXGIBuffer_GetUnknown(dxgi_buffer, &MF_D3D12_SYNCHRONIZATION_OBJECT, + &IID_IMFD3D12SynchronizationObjectCommands, (void **)&sync_cmd); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFD3D12SynchronizationObjectCommands_SignalEventOnResourceReady(sync_cmd, event); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + status = WaitForSingleObject(event, 100); + ok(status == WAIT_TIMEOUT, "got %#lx.\n", status); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &buffer_start, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + status = WaitForSingleObject(event, 100); + ok(status == WAIT_TIMEOUT, "got %#lx.\n", status); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + status = WaitForSingleObject(event, 100); + ok(status == WAIT_OBJECT_0, "got %#lx.\n", status); + IMFD3D12SynchronizationObjectCommands_Release(sync_cmd); + IMFDXGIBuffer_Release(dxgi_buffer); + IMF2DBuffer2_Release(_2dbuffer2); + IMFMediaBuffer_Release(buffer); + + /* Bottom up. */ + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D12Resource, (IUnknown *)resource, 0, TRUE, &buffer); + ok(hr == S_OK, "Failed to create a buffer, hr %#lx.\n", hr); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!data && pitch == layout.Footprint.RowPitch, "Unexpected pitch %ld.\n", pitch); + + hr = IMF2DBuffer2_GetScanline0AndPitch(_2dbuffer2, &data2, &pitch2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(data2 == data && pitch2 == pitch, "Unexpected data/pitch.\n"); + + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMF2DBuffer2_Release(_2dbuffer2); + IMFMediaBuffer_Release(buffer); + + ID3D12Resource_Release(resource); + + /* creation tests */ + + desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + hr = ID3D12Device_CreateCommittedResource(device, &heap_props, D3D12_HEAP_FLAG_NONE, + &desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&resource); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D12Resource, (IUnknown *)resource, 0, FALSE, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaBuffer_Release(buffer); + ID3D12Resource_Release(resource); + + desc.Flags = 0; + hr = ID3D12Device_CreateCommittedResource(device, &heap_props, D3D12_HEAP_FLAG_NONE, + &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&resource); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D12Resource, (IUnknown *)resource, 0, FALSE, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaBuffer_Release(buffer); + ID3D12Resource_Release(resource); + + /* Subresource index 1. */ + desc.MipLevels = 0; + desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + hr = ID3D12Device_CreateCommittedResource(device, &heap_props, D3D12_HEAP_FLAG_NONE, + &desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&resource); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D12Resource, (IUnknown *)resource, 1, FALSE, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Pitch reflects top level. */ + put_d3d12_texture_color(resource, sync_cmd, 1, 0, 0, 0xff00ff00); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(*(DWORD *)data == 0xff00ff00, "Unexpected color %#lx.\n", *(DWORD *)data); + + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMF2DBuffer2_Release(_2dbuffer2); + IMFMediaBuffer_Release(buffer); + ID3D12Resource_Release(resource); + + desc.MipLevels = 1; + desc.Format = DXGI_FORMAT_NV12; + hr = ID3D12Device_CreateCommittedResource(device, &heap_props, D3D12_HEAP_FLAG_NONE, + &desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&resource); + if (SUCCEEDED(hr)) + { + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D12Resource, (IUnknown *)resource, 0, FALSE, &buffer); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&_2dbuffer2); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &buffer_start, &length); + ok(hr == S_OK, "got %#lx.\n", hr); + + ok(pitch >= desc.Width, "got %ld.\n", pitch); + ok(length == pitch * desc.Height * 3 / 2, "got %lu.\n", length); + + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMF2DBuffer2_Release(_2dbuffer2); + IMFMediaBuffer_Release(buffer); + ID3D12Resource_Release(resource); + } + else + { + skip("Failed to create NV12 texture, hr %#lx, skipping test.\n", hr); + } + + heap_props.Type = D3D12_HEAP_TYPE_READBACK; + desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + desc.Width = 32*32; + desc.Height = 1; + desc.Format = DXGI_FORMAT_UNKNOWN; + desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + desc.Flags = 0; + hr = ID3D12Device_CreateCommittedResource(device, &heap_props, D3D12_HEAP_FLAG_NONE, + &desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, &IID_ID3D12Resource, (void **)&resource); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D12Resource, (IUnknown *)resource, 0, FALSE, &buffer); + ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#lx.\n", hr); + ID3D12Resource_Release(resource); + + heap_props.Type = D3D12_HEAP_TYPE_UPLOAD; + hr = ID3D12Device_CreateCommittedResource(device, &heap_props, D3D12_HEAP_FLAG_NONE, + &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, (void **)&resource); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D12Resource, (IUnknown *)resource, 0, FALSE, &buffer); + ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#lx.\n", hr); + ID3D12Resource_Release(resource); + + CloseHandle(event); + ID3D12CommandQueue_Release(queue); +} + +notsupported: + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + refcount = ID3D12Device_Release(device); ok(!refcount, "Unexpected device refcount %u.\n", refcount); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11420