From 9932a1943b2091d7b1f9df35aabde5901665c71a Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 25 Mar 2021 12:40:31 +0300 Subject: [PATCH] mfplat: Implement Lock2D()/Unlock2D() for d3d11 buffer. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/mfplat/buffer.c | 127 ++++++++++++++++++++++++++++++++++--- dlls/mfplat/tests/mfplat.c | 72 +++++++++++++++++++++ 2 files changed, 190 insertions(+), 9 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index cf9ead7d809..fbd3b7786b6 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -64,7 +64,9 @@ struct memory_buffer struct { ID3D11Texture2D *texture; - unsigned int subresource; + unsigned int sub_resource_idx; + ID3D11Texture2D *rb_texture; + D3D11_MAPPED_SUBRESOURCE map_desc; struct attributes attributes; } dxgi_surface; @@ -134,6 +136,8 @@ static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface) if (buffer->dxgi_surface.texture) { ID3D11Texture2D_Release(buffer->dxgi_surface.texture); + if (buffer->dxgi_surface.rb_texture) + ID3D11Texture2D_Release(buffer->dxgi_surface.rb_texture); clear_attributes_object(&buffer->dxgi_surface.attributes); } DeleteCriticalSection(&buffer->cs); @@ -834,6 +838,75 @@ static HRESULT WINAPI dxgi_1d_2d_buffer_QueryInterface(IMFMediaBuffer *iface, RE return S_OK; } +static HRESULT dxgi_surface_buffer_create_readback_texture(struct memory_buffer *buffer) +{ + D3D11_TEXTURE2D_DESC texture_desc; + ID3D11Device *device; + HRESULT hr; + + if (buffer->dxgi_surface.rb_texture) + return S_OK; + + ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device); + + ID3D11Texture2D_GetDesc(buffer->dxgi_surface.texture, &texture_desc); + texture_desc.Usage = D3D11_USAGE_STAGING; + texture_desc.BindFlags = 0; + texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + texture_desc.MiscFlags = 0; + texture_desc.MipLevels = 1; + if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &buffer->dxgi_surface.rb_texture))) + WARN("Failed to create readback texture, hr %#x.\n", hr); + + ID3D11Device_Release(device); + + return hr; +} + +static HRESULT dxgi_surface_buffer_map(struct memory_buffer *buffer) +{ + ID3D11DeviceContext *immediate_context; + ID3D11Device *device; + HRESULT hr; + + if (FAILED(hr = dxgi_surface_buffer_create_readback_texture(buffer))) + return hr; + + ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device); + ID3D11Device_GetImmediateContext(device, &immediate_context); + ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, + 0, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, NULL); + + memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); + if (FAILED(hr = ID3D11DeviceContext_Map(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, + 0, D3D11_MAP_READ_WRITE, 0, &buffer->dxgi_surface.map_desc))) + { + WARN("Failed to map readback texture, hr %#x.\n", hr); + } + + ID3D11DeviceContext_Release(immediate_context); + ID3D11Device_Release(device); + + return hr; +} + +static void dxgi_surface_buffer_unmap(struct memory_buffer *buffer) +{ + ID3D11DeviceContext *immediate_context; + ID3D11Device *device; + + ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device); + ID3D11Device_GetImmediateContext(device, &immediate_context); + ID3D11DeviceContext_Unmap(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0); + memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); + + ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, + buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); + + ID3D11DeviceContext_Release(immediate_context); + ID3D11Device_Release(device); +} + static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length) { @@ -862,16 +935,52 @@ static HRESULT WINAPI dxgi_surface_buffer_SetCurrentLength(IMFMediaBuffer *iface static HRESULT WINAPI dxgi_surface_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch) { - FIXME("%p, %p, %p.\n", iface, scanline0, pitch); + struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p, %p, %p.\n", iface, scanline0, pitch); + + if (!scanline0 || !pitch) + return E_POINTER; + + EnterCriticalSection(&buffer->cs); + + if (buffer->_2d.linear_buffer) + hr = MF_E_UNEXPECTED; + else if (!buffer->_2d.locks++) + hr = dxgi_surface_buffer_map(buffer); + + if (SUCCEEDED(hr)) + { + *scanline0 = buffer->dxgi_surface.map_desc.pData; + *pitch = buffer->dxgi_surface.map_desc.RowPitch; + } + + LeaveCriticalSection(&buffer->cs); + + return hr; } static HRESULT WINAPI dxgi_surface_buffer_Unlock2D(IMF2DBuffer2 *iface) { - FIXME("%p.\n", iface); + struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p.\n", iface); + + EnterCriticalSection(&buffer->cs); + + if (buffer->_2d.locks) + { + if (!--buffer->_2d.locks) + dxgi_surface_buffer_unmap(buffer); + } + else + hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED); + + LeaveCriticalSection(&buffer->cs); + + return hr; } static HRESULT WINAPI dxgi_surface_buffer_GetScanline0AndPitch(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch) @@ -925,7 +1034,7 @@ static HRESULT WINAPI dxgi_buffer_GetSubresourceIndex(IMFDXGIBuffer *iface, UINT if (!index) return E_POINTER; - *index = buffer->dxgi_surface.subresource; + *index = buffer->dxgi_surface.sub_resource_idx; return S_OK; } @@ -1165,8 +1274,8 @@ static HRESULT create_d3d9_surface_buffer(IUnknown *surface, BOOL bottom_up, IMF return S_OK; } -static HRESULT create_dxgi_surface_buffer(IUnknown *surface, UINT subresource, BOOL bottom_up, - IMFMediaBuffer **buffer) +static HRESULT create_dxgi_surface_buffer(IUnknown *surface, unsigned int sub_resource_idx, + BOOL bottom_up, IMFMediaBuffer **buffer) { struct memory_buffer *object; D3D11_TEXTURE2D_DESC desc; @@ -1208,7 +1317,7 @@ static HRESULT create_dxgi_surface_buffer(IUnknown *surface, UINT subresource, B object->refcount = 1; InitializeCriticalSection(&object->cs); object->dxgi_surface.texture = texture; - object->dxgi_surface.subresource = subresource; + object->dxgi_surface.sub_resource_idx = sub_resource_idx; MFGetPlaneSize(format, desc.Width, desc.Height, &object->_2d.plane_size); object->_2d.width = stride; diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index b2b595b8fe7..dacad924ae9 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6320,6 +6320,22 @@ static ID3D11Device *create_d3d11_device(void) return NULL; } +static void update_d3d11_texture(ID3D11Texture2D *texture, unsigned int sub_resource_idx, + const BYTE *data, unsigned int src_pitch) +{ + ID3D11DeviceContext *immediate_context; + ID3D11Device *device; + + ID3D11Texture2D_GetDevice(texture, &device); + ID3D11Device_GetImmediateContext(device, &immediate_context); + + ID3D11DeviceContext_UpdateSubresource(immediate_context, (ID3D11Resource *)texture, + sub_resource_idx, NULL, data, src_pitch, 0); + + ID3D11DeviceContext_Release(immediate_context); + ID3D11Device_Release(device); +} + static void test_dxgi_surface_buffer(void) { DWORD max_length, cur_length, length, color; @@ -6329,10 +6345,12 @@ static void test_dxgi_surface_buffer(void) IMF2DBuffer *_2d_buffer; IMFMediaBuffer *buffer; ID3D11Device *device; + BYTE buff[64 * 64 * 4]; UINT index, size; IUnknown *obj; HRESULT hr; BYTE *data; + LONG pitch; if (!pMFCreateDXGISurfaceBuffer) { @@ -6463,6 +6481,60 @@ todo_wine todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + /* Lock2D()/Unlock2D() */ + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!!data && pitch == desc.Width * 4, "Unexpected pitch %d.\n", pitch); + + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!!data && pitch == desc.Width * 4, "Unexpected pitch %d.\n", pitch); + + hr = IMFMediaBuffer_Lock(buffer, &data, &max_length, &cur_length); +todo_wine + ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#x.\n", hr); + + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED), "Unexpected hr %#x.\n", hr); + + IMF2DBuffer_Release(_2d_buffer); + IMFMediaBuffer_Release(buffer); + + ID3D11Texture2D_Release(texture); + + /* Subresource index 1. */ + hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture); + ok(hr == S_OK, "Failed to create a texture, hr %#x.\n", hr); + + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 1, FALSE, &buffer); + ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + /* Pitch reflects top level. */ + memset(buff, 0, sizeof(buff)); + *(DWORD *)buff = 0xff00ff00; + update_d3d11_texture(texture, 1, buff, 64 * 4); + + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(pitch == desc.Width * 4, "Unexpected pitch %d.\n", pitch); + ok(*(DWORD *)data == 0xff00ff00, "Unexpected color %#x.\n", *(DWORD *)data); + + hr = IMF2DBuffer_Unlock2D(_2d_buffer); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + IMF2DBuffer_Release(_2d_buffer); IMFMediaBuffer_Release(buffer); ID3D11Texture2D_Release(texture);