From: Brendan McGrath bmcgrath@codeweavers.com
If both buffers are DXGI buffers, they can be copied on the GPU. They are currently transferred to the CPU, copied by the CPU and then transferred back to the GPU.
Performing a GPU copy produces ~25% faster playback on 4K video. --- dlls/mfreadwrite/reader.c | 84 +++++++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 8 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 0e0ba10b076..17ead32a50a 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -38,6 +38,9 @@ #include "wine/list.h"
#include "mf_private.h" +#undef EXTERN_GUID +#define EXTERN_GUID DEFINE_GUID +#include "d3d11.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
@@ -429,9 +432,70 @@ static void source_reader_response_ready(struct source_reader *reader, struct st stream->requests--; }
-static void source_reader_copy_sample_buffer(IMFSample *src, IMFSample *dst) +static HRESULT dxgi_copy(IMFMediaBuffer *src, IMFMediaBuffer *dst, IUnknown *device_manager) { - IMFMediaBuffer *buffer; + HRESULT hr; + IMFDXGIBuffer *dxgi_src, *dxgi_dst; + IMFDXGIDeviceManager *dxgi_manager; + HANDLE device_handle; + ID3D11Device *device; + ID3D11DeviceContext *device_context; + ID3D11Texture2D *texture_src, *texture_dst; + + if (!device_manager) + return E_INVALIDARG; + + if (FAILED(hr = IUnknown_QueryInterface(device_manager, &IID_IMFDXGIDeviceManager, (void**)&dxgi_manager))) + return hr; + + if (FAILED(hr = IMFMediaBuffer_QueryInterface(src, &IID_IMFDXGIBuffer, (void**)&dxgi_src))) + goto release_dxgi; + + if (FAILED(hr = IMFMediaBuffer_QueryInterface(dst, &IID_IMFDXGIBuffer, (void**)&dxgi_dst))) + goto release_src; + + if (FAILED(hr = IMFDXGIBuffer_GetResource(dxgi_src, &IID_ID3D11Texture2D, (void**)&texture_src))) + goto release_dst; + + if (FAILED(hr = IMFDXGIBuffer_GetResource(dxgi_dst, &IID_ID3D11Texture2D, (void**)&texture_dst))) + goto release_texture_src; + + if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(dxgi_manager, &device_handle))) + goto release_texture_dest; + + if (FAILED(IMFDXGIDeviceManager_LockDevice(dxgi_manager, device_handle, &IID_ID3D11Device, (void **)&device, TRUE))) + goto close_device_handle; + + ID3D11Device_GetImmediateContext(device, &device_context); + ID3D11DeviceContext_CopyResource(device_context, (ID3D11Resource *)texture_dst, (ID3D11Resource *)texture_src); + ID3D11DeviceContext_Release(device_context); + ID3D11Device_Release(device); + IMFDXGIDeviceManager_UnlockDevice(dxgi_manager, device_handle, FALSE); + +close_device_handle: + IMFDXGIDeviceManager_CloseDeviceHandle(dxgi_manager, device_handle); + +release_texture_dest: + ID3D11Texture2D_Release(texture_dst); + +release_texture_src: + ID3D11Texture2D_Release(texture_src); + +release_dst: + IMFDXGIBuffer_Release(dxgi_dst); + +release_src: + IMFDXGIBuffer_Release(dxgi_src); + +release_dxgi: + IMFDXGIDeviceManager_Release(dxgi_manager); + + return hr; +} + +static void source_reader_copy_sample_buffer(IMFSample *src, IMFSample *dst, IUnknown *device_manager) +{ + IMFMediaBuffer *buffer_dst, *buffer_src; LONGLONG time; DWORD flags; HRESULT hr; @@ -451,14 +515,18 @@ static void source_reader_copy_sample_buffer(IMFSample *src, IMFSample *dst) if (SUCCEEDED(IMFSample_GetSampleFlags(src, &flags))) IMFSample_SetSampleFlags(dst, flags);
- if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src, NULL))) + if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src, &buffer_src))) { - if (SUCCEEDED(IMFSample_GetBufferByIndex(dst, 0, &buffer))) + if (SUCCEEDED(IMFSample_GetBufferByIndex(dst, 0, &buffer_dst))) { - if (FAILED(hr = IMFSample_CopyToBuffer(src, buffer))) - WARN("Failed to copy a buffer, hr %#lx.\n", hr); - IMFMediaBuffer_Release(buffer); + if(FAILED(dxgi_copy(buffer_src, buffer_dst, device_manager))) + { + if (FAILED(hr = IMFSample_CopyToBuffer(src, buffer_dst))) + WARN("Failed to copy a buffer, hr %#lx.\n", hr); + } + IMFMediaBuffer_Release(buffer_dst); } + IMFMediaBuffer_Release(buffer_src); } }
@@ -1204,7 +1272,7 @@ static struct stream_response *media_stream_pop_response(struct source_reader *r /* Return allocation error to the caller, while keeping original response sample in for later. */ if (SUCCEEDED(hr = IMFVideoSampleAllocatorEx_AllocateSample(stream->allocator, &sample))) { - source_reader_copy_sample_buffer(response->sample, sample); + source_reader_copy_sample_buffer(response->sample, sample, reader->device_manager); IMFSample_Release(response->sample); response->sample = sample; }