Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/quartz/vmr9.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index e7a588e28a0..d1110572303 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -262,10 +262,10 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi { struct quartz_vmr *This = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); const HANDLE events[2] = {This->run_event, This->renderer.flush_event}; + VMR9PresentationInfo info = {}; LPBYTE pbSrcStream = NULL; long cbSrcStream = 0; REFERENCE_TIME tStart, tStop; - VMR9PresentationInfo info; HRESULT hr;
TRACE("%p %p\n", iface, pSample);
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- v3: Retain the old code path for the VMR7. It's obviously wrong in some ways, but without tests it's not clear how the VMR7 does format type negotiation—it doesn't seem to be solely based on the subtype—and it's better to change the algorithm for one filter at a time.
dlls/quartz/tests/vmr9.c | 16 ++--- dlls/quartz/vmr9.c | 127 ++++++++++++++++++++++++++++----------- 2 files changed, 99 insertions(+), 44 deletions(-)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index 387f4f0a93e..352268dae5e 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -1388,17 +1388,13 @@ static void test_connect_pin(void) skip("Got E_FAIL when connecting.\n"); goto out; } - todo_wine_if (bpp_tests[j] == 24) - ok(hr == S_OK, "Got hr %#x for subtype %s and bpp %u.\n", hr, - wine_dbgstr_guid(subtype_tests[i]), bpp_tests[j]); + ok(hr == S_OK, "Got hr %#x for subtype %s and bpp %u.\n", hr, + wine_dbgstr_guid(subtype_tests[i]), bpp_tests[j]);
- if (hr == S_OK) - { - hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); - ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IFilterGraph2_Disconnect(graph, pin); - ok(hr == S_OK, "Got hr %#x.\n", hr); - } + hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_Disconnect(graph, pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); } }
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index d1110572303..35d625ddd7e 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -349,58 +349,117 @@ static HRESULT WINAPI VMR9_CheckMediaType(struct strmbase_renderer *iface, const return S_OK; }
-static HRESULT VMR9_maybe_init(struct quartz_vmr *This, BOOL force) +static HRESULT initialize_device(struct quartz_vmr *filter, VMR9AllocationInfo *info) { - VMR9AllocationInfo info; - DWORD buffers; + DWORD buffer_count = 2; HRESULT hr;
- TRACE("my mode: %u, my window: %p, my last window: %p\n", This->mode, This->baseControlWindow.baseWindow.hWnd, This->hWndClippingWindow); - if (This->num_surfaces) + if (FAILED(hr = IVMRSurfaceAllocatorEx9_InitializeDevice(filter->allocator, + filter->cookie, info, &buffer_count))) + { + WARN("Failed to initialize device (flags %#x), hr %#x.\n", info->dwFlags, hr); + return hr; + } + + SetRect(&filter->source_rect, 0, 0, filter->bmiheader.biWidth, filter->bmiheader.biHeight); + filter->num_surfaces = buffer_count; + + return hr; +} + +static HRESULT VMR9_maybe_init(struct quartz_vmr *filter, BOOL force, const AM_MEDIA_TYPE *mt) +{ + VMR9AllocationInfo info = {}; + HRESULT hr = E_FAIL; + unsigned int i; + + static const struct + { + const GUID *subtype; + D3DFORMAT format; + DWORD flags; + } + formats[] = + { + {&MEDIASUBTYPE_ARGB1555, D3DFMT_A1R5G5B5, VMR9AllocFlag_TextureSurface}, + {&MEDIASUBTYPE_ARGB32, D3DFMT_A8R8G8B8, VMR9AllocFlag_TextureSurface}, + {&MEDIASUBTYPE_ARGB4444, D3DFMT_A4R4G4B4, VMR9AllocFlag_TextureSurface}, + + {&MEDIASUBTYPE_RGB24, D3DFMT_R8G8B8, VMR9AllocFlag_TextureSurface | VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_RGB32, D3DFMT_X8R8G8B8, VMR9AllocFlag_TextureSurface | VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_RGB555, D3DFMT_X1R5G5B5, VMR9AllocFlag_TextureSurface | VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_RGB565, D3DFMT_R5G6B5, VMR9AllocFlag_TextureSurface | VMR9AllocFlag_OffscreenSurface}, + + {&MEDIASUBTYPE_NV12, MAKEFOURCC('N','V','1','2'), VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_UYVY, D3DFMT_UYVY, VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_YUY2, D3DFMT_YUY2, VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_YV12, MAKEFOURCC('Y','V','1','2'), VMR9AllocFlag_OffscreenSurface}, + }; + + TRACE("Initializing in mode %u, our window %p, clipping window %p.\n", + filter->mode, filter->baseControlWindow.baseWindow.hWnd, filter->hWndClippingWindow); + if (filter->num_surfaces) return S_OK;
- if (This->mode == VMR9Mode_Windowless && !This->hWndClippingWindow) + if (filter->mode == VMR9Mode_Windowless && !filter->hWndClippingWindow) return (force ? VFW_E_RUNTIME_ERROR : S_OK);
- TRACE("Initializing\n"); - info.dwFlags = VMR9AllocFlag_TextureSurface; - info.dwHeight = This->source_rect.bottom; - info.dwWidth = This->source_rect.right; + info.dwWidth = filter->source_rect.right; + info.dwHeight = filter->source_rect.bottom; info.Pool = D3DPOOL_DEFAULT; info.MinBuffers = 2; - FIXME("Reduce ratio to least common denominator\n"); info.szAspectRatio.cx = info.dwWidth; info.szAspectRatio.cy = info.dwHeight; - info.szNativeSize.cx = This->bmiheader.biWidth; - info.szNativeSize.cy = This->bmiheader.biHeight; - buffers = 2; + info.szNativeSize.cx = filter->bmiheader.biWidth; + info.szNativeSize.cy = filter->bmiheader.biHeight;
- switch (This->bmiheader.biBitCount) + filter->cur_surface = 0; + if (filter->num_surfaces) { - case 8: info.Format = D3DFMT_R3G3B2; break; - case 15: info.Format = D3DFMT_X1R5G5B5; break; - case 16: info.Format = D3DFMT_R5G6B5; break; - case 24: info.Format = D3DFMT_R8G8B8; break; - case 32: info.Format = D3DFMT_X8R8G8B8; break; - default: - FIXME("Unknown bpp %u\n", This->bmiheader.biBitCount); - hr = E_INVALIDARG; + ERR("num_surfaces or d3d9_surfaces not 0\n"); + return E_FAIL; }
- This->cur_surface = 0; - if (This->num_surfaces) + if (IsEqualGUID(&filter->renderer.filter.clsid, &CLSID_VideoMixingRenderer)) { - ERR("num_surfaces or d3d9_surfaces not 0\n"); - return E_FAIL; + switch (filter->bmiheader.biBitCount) + { + case 8: info.Format = D3DFMT_R3G3B2; break; + case 15: info.Format = D3DFMT_X1R5G5B5; break; + case 16: info.Format = D3DFMT_R5G6B5; break; + case 24: info.Format = D3DFMT_R8G8B8; break; + case 32: info.Format = D3DFMT_X8R8G8B8; break; + default: + FIXME("Unhandled bit depth %u.\n", filter->bmiheader.biBitCount); + return E_INVALIDARG; + } + + info.dwFlags = VMR9AllocFlag_TextureSurface; + return initialize_device(filter, &info); }
- hr = IVMRSurfaceAllocatorEx9_InitializeDevice(This->allocator, This->cookie, &info, &buffers); - if (SUCCEEDED(hr)) + for (i = 0; i < ARRAY_SIZE(formats); ++i) { - SetRect(&This->source_rect, 0, 0, This->bmiheader.biWidth, This->bmiheader.biHeight); + if (IsEqualGUID(&mt->subtype, formats[i].subtype)) + { + info.Format = formats[i].format; + + if (formats[i].flags & VMR9AllocFlag_TextureSurface) + { + info.dwFlags = VMR9AllocFlag_TextureSurface; + if (SUCCEEDED(hr = initialize_device(filter, &info))) + return hr; + }
- This->num_surfaces = buffers; + if (formats[i].flags & VMR9AllocFlag_OffscreenSurface) + { + info.dwFlags = VMR9AllocFlag_OffscreenSurface; + if (SUCCEEDED(hr = initialize_device(filter, &info))) + return hr; + } + } } + return hr; }
@@ -411,7 +470,7 @@ static void vmr_start_stream(struct strmbase_renderer *iface) TRACE("(%p)\n", This);
if (This->renderer.sink.pin.peer) - VMR9_maybe_init(This, TRUE); + VMR9_maybe_init(This, TRUE, &This->renderer.sink.pin.mt); IVMRImagePresenter9_StartPresenting(This->presenter, This->cookie); SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL, This->source_rect.left, @@ -470,7 +529,7 @@ static HRESULT vmr_connect(struct strmbase_renderer *iface, const AM_MEDIA_TYPE
if (filter->mode || SUCCEEDED(hr = IVMRFilterConfig9_SetRenderingMode(&filter->IVMRFilterConfig9_iface, VMR9Mode_Windowed))) - hr = VMR9_maybe_init(filter, FALSE); + hr = VMR9_maybe_init(filter, FALSE, mt);
return hr; } @@ -1772,7 +1831,7 @@ static HRESULT WINAPI VMR9WindowlessControl_SetVideoClippingWindow(IVMRWindowles EnterCriticalSection(&This->renderer.filter.csFilter); This->hWndClippingWindow = hwnd; if (This->renderer.sink.pin.peer) - VMR9_maybe_init(This, FALSE); + VMR9_maybe_init(This, FALSE, &This->renderer.sink.pin.mt); if (!hwnd) IVMRSurfaceAllocatorEx9_TerminateDevice(This->allocator, This->cookie); LeaveCriticalSection(&This->renderer.filter.csFilter);
How to Survive gets confused when we ask for more than one surface.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/quartz/vmr9.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 35d625ddd7e..ab471b90421 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -351,7 +351,7 @@ static HRESULT WINAPI VMR9_CheckMediaType(struct strmbase_renderer *iface, const
static HRESULT initialize_device(struct quartz_vmr *filter, VMR9AllocationInfo *info) { - DWORD buffer_count = 2; + DWORD buffer_count = 1; HRESULT hr;
if (FAILED(hr = IVMRSurfaceAllocatorEx9_InitializeDevice(filter->allocator, @@ -407,7 +407,7 @@ static HRESULT VMR9_maybe_init(struct quartz_vmr *filter, BOOL force, const AM_M info.dwWidth = filter->source_rect.right; info.dwHeight = filter->source_rect.bottom; info.Pool = D3DPOOL_DEFAULT; - info.MinBuffers = 2; + info.MinBuffers = 1; info.szAspectRatio.cx = info.dwWidth; info.szAspectRatio.cy = info.dwHeight; info.szNativeSize.cx = filter->bmiheader.biWidth;
How to Survive does not reference the IDirect3DSurface9 in IVMRSurfaceAllocator9::GetSurface(), nor does it dereference it in IVMRSurfaceAllocator9::TerminateDevice(). Native quartz only asks for each surface once, when connecting, and releases those surfaces when disconnecting, which lets these two application bugs cancel each other out.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/quartz/vmr9.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index ab471b90421..0aa861c3a69 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -75,6 +75,7 @@ struct quartz_vmr /* Presentation related members */ IDirect3DDevice9 *allocator_d3d9_dev; HMONITOR allocator_mon; + IDirect3DSurface9 **surfaces; DWORD num_surfaces; DWORD cur_surface; DWORD_PTR cookie; @@ -312,14 +313,9 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi info.rtEnd = tStop; info.szAspectRatio.cx = This->bmiheader.biWidth; info.szAspectRatio.cy = This->bmiheader.biHeight; - - hr = IVMRSurfaceAllocatorEx9_GetSurface(This->allocator, This->cookie, (++This->cur_surface)%This->num_surfaces, 0, &info.lpSurf); - - if (FAILED(hr)) - return hr; + info.lpSurf = This->surfaces[(++This->cur_surface) % This->num_surfaces];
VMR9_SendSampleData(This, &info, pbSrcStream, cbSrcStream); - IDirect3DSurface9_Release(info.lpSurf);
if (This->renderer.filter.state == State_Paused) { @@ -351,7 +347,7 @@ static HRESULT WINAPI VMR9_CheckMediaType(struct strmbase_renderer *iface, const
static HRESULT initialize_device(struct quartz_vmr *filter, VMR9AllocationInfo *info) { - DWORD buffer_count = 1; + DWORD buffer_count = 1, i; HRESULT hr;
if (FAILED(hr = IVMRSurfaceAllocatorEx9_InitializeDevice(filter->allocator, @@ -361,6 +357,25 @@ static HRESULT initialize_device(struct quartz_vmr *filter, VMR9AllocationInfo * return hr; }
+ if (!(filter->surfaces = calloc(buffer_count, sizeof(IDirect3DSurface9 *)))) + { + IVMRSurfaceAllocatorEx9_TerminateDevice(filter->allocator, filter->cookie); + return E_OUTOFMEMORY; + } + + for (i = 0; i < buffer_count; ++i) + { + if (FAILED(hr = IVMRSurfaceAllocatorEx9_GetSurface(filter->allocator, + filter->cookie, i, 0, &filter->surfaces[i]))) + { + ERR("Failed to get surface %u, hr %#x.\n", i, hr); + while (i--) + IDirect3DSurface9_Release(filter->surfaces[i]); + IVMRSurfaceAllocatorEx9_TerminateDevice(filter->allocator, filter->cookie); + return hr; + } + } + SetRect(&filter->source_rect, 0, 0, filter->bmiheader.biWidth, filter->bmiheader.biHeight); filter->num_surfaces = buffer_count;
@@ -538,6 +553,7 @@ static HRESULT WINAPI VMR9_BreakConnect(struct strmbase_renderer *This) { struct quartz_vmr *pVMR9 = impl_from_IBaseFilter(&This->filter.IBaseFilter_iface); HRESULT hr = S_OK; + DWORD i;
if (!pVMR9->mode) return S_FALSE; @@ -549,6 +565,10 @@ static HRESULT WINAPI VMR9_BreakConnect(struct strmbase_renderer *This) } if (pVMR9->renderer.filter.state == State_Running) hr = IVMRImagePresenter9_StopPresenting(pVMR9->presenter, pVMR9->cookie); + + for (i = 0; i < pVMR9->num_surfaces; ++i) + IDirect3DSurface9_Release(pVMR9->surfaces[i]); + free(pVMR9->surfaces); IVMRSurfaceAllocatorEx9_TerminateDevice(pVMR9->allocator, pVMR9->cookie); pVMR9->num_surfaces = 0; }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/quartz/tests/Makefile.in | 2 +- dlls/quartz/tests/avisplit.c | 1 - dlls/quartz/tests/vmr9.c | 561 +++++++++++++++++++++++++++++++++- 3 files changed, 560 insertions(+), 4 deletions(-)
diff --git a/dlls/quartz/tests/Makefile.in b/dlls/quartz/tests/Makefile.in index 46b3728ab82..7609f4db6c8 100644 --- a/dlls/quartz/tests/Makefile.in +++ b/dlls/quartz/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = quartz.dll -IMPORTS = strmbase advapi32 msvfw32 ole32 oleaut32 strmiids user32 uuid +IMPORTS = strmbase advapi32 d3d9 msvfw32 ole32 oleaut32 user32 uuid
C_SRCS = \ acmwrapper.c \ diff --git a/dlls/quartz/tests/avisplit.c b/dlls/quartz/tests/avisplit.c index 90c91822e59..7f54172618a 100644 --- a/dlls/quartz/tests/avisplit.c +++ b/dlls/quartz/tests/avisplit.c @@ -21,7 +21,6 @@
#define COBJMACROS #include "dshow.h" -#include "initguid.h" #include "wmcodecdsp.h" #include "wine/strmbase.h" #include "wine/test.h" diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index 352268dae5e..45898db1117 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -19,9 +19,14 @@ */
#define COBJMACROS +#include "ocidl.h" +#include "olectl.h" +#include "initguid.h" #include "dshow.h" +#include "qedit.h" #include "d3d9.h" #include "vmr9.h" +#include "wmcodecdsp.h" #include "wine/heap.h" #include "wine/strmbase.h" #include "wine/test.h" @@ -984,9 +989,9 @@ static HANDLE send_frame(IMemInputPin *sink)
hr = IMediaSample_GetPointer(sample, &data); ok(hr == S_OK, "Got hr %#x.\n", hr); - memset(data, 0x55, 32 * 16 * 4); + memset(data, 0x55, IMediaSample_GetSize(sample));
- hr = IMediaSample_SetActualDataLength(sample, 32 * 16 * 4); + hr = IMediaSample_SetActualDataLength(sample, IMediaSample_GetSize(sample)); ok(hr == S_OK, "Got hr %#x.\n", hr);
start_time = 0; @@ -1508,6 +1513,38 @@ static void test_overlay(void) IPin_Release(pin); ref = IBaseFilter_Release(filter); ok(!ref, "Got outstanding refcount %d.\n", ref); + + filter = create_vmr9(VMR9Mode_Windowless); + IBaseFilter_FindPin(filter, L"VMR Input0", &pin); + + hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hwnd = (HWND)0xdeadbeef; + hr = IOverlay_GetWindowHandle(overlay, &hwnd); + todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr); + todo_wine ok(hwnd == (HWND)0xdeadbeef, "Got invalid window %p.\n", hwnd); + + IOverlay_Release(overlay); + IPin_Release(pin); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + filter = create_vmr9(VMR9Mode_Renderless); + IBaseFilter_FindPin(filter, L"VMR Input0", &pin); + + hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hwnd = (HWND)0xdeadbeef; + hr = IOverlay_GetWindowHandle(overlay, &hwnd); + todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr); + todo_wine ok(hwnd == (HWND)0xdeadbeef, "Got invalid window %p.\n", hwnd); + + IOverlay_Release(overlay); + IPin_Release(pin); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); }
/* try to make sure pending X events have been processed before continuing */ @@ -2321,6 +2358,524 @@ out: DestroyWindow(our_hwnd); }
+static IDirect3DDevice9 *create_device(HWND window) +{ + D3DPRESENT_PARAMETERS present_parameters = + { + .Windowed = TRUE, + .hDeviceWindow = window, + .SwapEffect = D3DSWAPEFFECT_DISCARD, + .BackBufferWidth = 640, + .BackBufferHeight = 480, + .BackBufferFormat = D3DFMT_A8R8G8B8, + }; + IDirect3DDevice9 *device; + IDirect3D9 *d3d; + HRESULT hr; + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + ok(!!d3d, "Failed to create a D3D object.\n"); + + /* We can expect this to succeed, or we couldn't have created the VMR. */ + hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, + D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_parameters, &device); + ok(hr == D3D_OK, "Failed to create a 3D device, hr %#x.\n", hr); + IDirect3D9_Release(d3d); + return device; +} + +static void test_allocate_surface_helper(void) +{ + VMR9AllocationInfo info = + { + .dwFlags = VMR9AllocFlag_OffscreenSurface, + .dwWidth = 32, + .dwHeight = 16, + .Format = D3DFMT_X8R8G8B8, + .Pool = D3DPOOL_DEFAULT, + .MinBuffers = 2, + .szAspectRatio = {32, 16}, + .szNativeSize = {32, 16}, + }; + IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless); + IVMRSurfaceAllocatorNotify9 *notify; + IDirect3DSurface9 *surfaces[2] = {}; + IDirect3DDevice9 *device, *device2; + RECT rect = {0, 0, 640, 480}; + IDirect3DTexture9 *container; + D3DSURFACE_DESC desc; + DWORD count; + HWND window; + HRESULT hr; + ULONG ref; + + IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)¬ify); + + count = 2; + hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces); + todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); + window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, + rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL); + device = create_device(window); + + hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY)); + if (hr == E_NOINTERFACE) + { + win_skip("Direct3D does not support video rendering.\n"); + goto out; + } + ok(hr == S_OK, "Got hr %#x.\n", hr); + + if (0) /* crashes on Windows */ + { + hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, NULL, &count, surfaces); + ok(hr == E_POINTER, "Got hr %#x.\n", hr); + + hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, NULL, surfaces); + ok(hr == E_POINTER, "Got hr %#x.\n", hr); + } + + hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, NULL); + ok(hr == E_POINTER, "Got hr %#x.\n", hr); + + hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(count == 2, "Got count %u.\n", count); + ok(!!surfaces[0], "Surface 0 was not allocated.\n"); + ok(!!surfaces[1], "Surface 1 was not allocated.\n"); + + hr = IDirect3DSurface9_GetDevice(surfaces[0], &device2); + ok(hr == D3D_OK, "Got hr %#x.\n", hr); + ok(device2 == device, "Devices did not match.\n"); + IDirect3DDevice9_Release(device2); + + hr = IDirect3DSurface9_GetContainer(surfaces[0], &IID_IDirect3DTexture9, (void **)&container); + ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr); + + hr = IDirect3DSurface9_GetDesc(surfaces[0], &desc); + ok(hr == D3D_OK, "Got hr %#x.\n", hr); + ok(desc.Format == info.Format, "Got format %#x.\n", desc.Format); + ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type); + ok(!desc.Usage, "Got usage %#x.\n", desc.Usage); + ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool); + ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType); + ok(!desc.MultiSampleQuality, "Got multisample quality %u.\n", desc.MultiSampleQuality); + ok(desc.Width == 32, "Got width %u.\n", desc.Width); + ok(desc.Height == 16, "Got height %u.\n", desc.Height); + + IDirect3DSurface9_Release(surfaces[0]); + IDirect3DSurface9_Release(surfaces[1]); + + surfaces[0] = surfaces[1] = NULL; + count = 1; + hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!count, "Got count %u.\n", count); + ok(!surfaces[0], "Surface 0 was allocated.\n"); + ok(!surfaces[1], "Surface 1 was allocated.\n"); + + count = 2; + info.MinBuffers = 1; + hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(count == 2, "Got count %u.\n", count); + ok(!!surfaces[0], "Surface 0 was not allocated.\n"); + ok(!!surfaces[1], "Surface 1 was not allocated.\n"); + IDirect3DSurface9_Release(surfaces[0]); + IDirect3DSurface9_Release(surfaces[1]); + + count = 2; + info.dwFlags = VMR9AllocFlag_TextureSurface; + surfaces[0] = surfaces[1] = NULL; + hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(count == 2, "Got count %u.\n", count); + ok(!!surfaces[0], "Surface 0 was not allocated.\n"); + ok(!!surfaces[1], "Surface 1 was not allocated.\n"); + + hr = IDirect3DSurface9_GetDevice(surfaces[0], &device2); + ok(hr == D3D_OK, "Got hr %#x.\n", hr); + ok(device2 == device, "Devices did not match.\n"); + IDirect3DDevice9_Release(device2); + + hr = IDirect3DSurface9_GetContainer(surfaces[0], &IID_IDirect3DTexture9, (void **)&container); + ok(hr == D3D_OK, "Got hr %#x.\n", hr); + IDirect3DTexture9_Release(container); + + hr = IDirect3DSurface9_GetDesc(surfaces[1], &desc); + ok(hr == D3D_OK, "Got hr %#x.\n", hr); + ok(desc.Format == info.Format, "Got format %#x.\n", desc.Format); + ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type); + todo_wine ok(desc.Usage == D3DUSAGE_DYNAMIC, "Got usage %#x.\n", desc.Usage); + ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool); + ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType); + ok(!desc.MultiSampleQuality, "Got multisample quality %u.\n", desc.MultiSampleQuality); + ok(desc.Width == 32, "Got width %u.\n", desc.Width); + ok(desc.Height == 16, "Got height %u.\n", desc.Height); + + IDirect3DSurface9_Release(surfaces[0]); + IDirect3DSurface9_Release(surfaces[1]); + + info.Format = D3DFMT_R8G8B8; + surfaces[0] = surfaces[1] = NULL; + hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces); + ok(hr == D3DERR_INVALIDCALL, "Got hr %#x.\n", hr); + ok(!count, "Got count %u.\n", count); + ok(!surfaces[0], "Surface 0 was allocated.\n"); + ok(!surfaces[1], "Surface 1 was allocated.\n"); + +out: + IVMRSurfaceAllocatorNotify9_Release(notify); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IDirect3DDevice9_Release(device); + ok(!ref, "Got outstanding refcount %d.\n", ref); + DestroyWindow(window); +} + +static IVMRSurfaceAllocator9 allocator_iface; +static IVMRImagePresenter9 presenter_iface; +static LONG allocator_refcount = 1; +static D3DFORMAT allocator_format; +static DWORD allocator_accept_flags; +static IDirect3DSurface9 *allocator_surfaces[5]; +static IVMRSurfaceAllocatorNotify9 *allocator_notify; +static unsigned int allocator_got_PresentImage; + +static HRESULT WINAPI presenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID iid, void **out) +{ + return IVMRSurfaceAllocator9_QueryInterface(&allocator_iface, iid, out); +} + +static ULONG WINAPI presenter_AddRef(IVMRImagePresenter9 *iface) +{ + return IVMRSurfaceAllocator9_AddRef(&allocator_iface); +} + +static ULONG WINAPI presenter_Release(IVMRImagePresenter9 *iface) +{ + return IVMRSurfaceAllocator9_Release(&allocator_iface); +} + +static HRESULT WINAPI presenter_StartPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie) +{ + if (winetest_debug > 1) trace("StartPresenting()\n"); + ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie); + return E_NOTIMPL; +} + +static HRESULT WINAPI presenter_StopPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie) +{ + if (winetest_debug > 1) trace("StopPresenting()\n"); + ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie); + return E_NOTIMPL; +} + +static HRESULT WINAPI presenter_PresentImage(IVMRImagePresenter9 *iface, DWORD_PTR cookie, VMR9PresentationInfo *info) +{ + static const RECT rect; + if (winetest_debug > 1) trace("PresentImage()\n"); + ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie); + todo_wine ok(info->dwFlags == VMR9Sample_TimeValid, "Got flags %#x.\n", info->dwFlags); + ok(!info->rtStart, "Got start time %s.\n", wine_dbgstr_longlong(info->rtStart)); + ok(info->rtEnd == 10000000, "Got end time %s.\n", wine_dbgstr_longlong(info->rtEnd)); + todo_wine ok(info->szAspectRatio.cx == 120, "Got aspect ratio width %d.\n", info->szAspectRatio.cx); + todo_wine ok(info->szAspectRatio.cy == 60, "Got aspect ratio height %d.\n", info->szAspectRatio.cy); + ok(EqualRect(&info->rcSrc, &rect), "Got source rect %s.\n", wine_dbgstr_rect(&info->rcSrc)); + ok(EqualRect(&info->rcDst, &rect), "Got dest rect %s.\n", wine_dbgstr_rect(&info->rcDst)); + ok(!info->dwReserved1, "Got dwReserved1 %#x.\n", info->dwReserved1); + ok(!info->dwReserved2, "Got dwReserved2 %#x.\n", info->dwReserved2); + + ++allocator_got_PresentImage; + return S_OK; +} + +static const IVMRImagePresenter9Vtbl presenter_vtbl = +{ + presenter_QueryInterface, + presenter_AddRef, + presenter_Release, + presenter_StartPresenting, + presenter_StopPresenting, + presenter_PresentImage, +}; + +static HRESULT WINAPI allocator_QueryInterface(IVMRSurfaceAllocator9 *iface, REFIID iid, void **out) +{ + if (winetest_debug > 1) trace("QueryInterface(%s)\n", wine_dbgstr_guid(iid)); + + if (IsEqualGUID(iid, &IID_IVMRImagePresenter9)) + { + *out = &presenter_iface; + IVMRImagePresenter9_AddRef(&presenter_iface); + return S_OK; + } + *out = NULL; + return E_NOTIMPL; +} + +static ULONG WINAPI allocator_AddRef(IVMRSurfaceAllocator9 *iface) +{ + return InterlockedIncrement(&allocator_refcount); +} + +static ULONG WINAPI allocator_Release(IVMRSurfaceAllocator9 *iface) +{ + return InterlockedDecrement(&allocator_refcount); +} + +static HRESULT WINAPI allocator_InitializeDevice(IVMRSurfaceAllocator9 *iface, + DWORD_PTR cookie, VMR9AllocationInfo *info, DWORD *buffer_count) +{ + if (winetest_debug > 1) trace("InitializeDevice(flags %#x, format %u)\n", + info->dwFlags, info->Format); + ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie); + ok(info->dwWidth == 32, "Got width %u.\n", info->dwWidth); + ok(info->dwHeight == 16, "Got height %u.\n", info->dwHeight); + todo_wine ok(info->MinBuffers == 5, "Got buffer count %u.\n", info->MinBuffers); + ok(info->Pool == D3DPOOL_DEFAULT, "Got pool %u\n", info->Pool); + todo_wine ok(info->szAspectRatio.cx == 120, "Got aspect ratio width %d.\n", info->szAspectRatio.cx); + todo_wine ok(info->szAspectRatio.cy == 60, "Got aspect ratio height %d.\n", info->szAspectRatio.cy); + ok(info->szNativeSize.cx == 32, "Got native width %d.\n", info->szNativeSize.cx); + ok(info->szNativeSize.cy == 16, "Got native height %d.\n", info->szNativeSize.cy); + todo_wine ok(*buffer_count == 5, "Got buffer count %u.\n", *buffer_count); + + allocator_format = info->Format; + + if (info->dwFlags != allocator_accept_flags) + return 0xdeadbeef; + return IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(allocator_notify, + info, buffer_count, allocator_surfaces); +} + +static HRESULT WINAPI allocator_TerminateDevice(IVMRSurfaceAllocator9 *iface, DWORD_PTR cookie) +{ + if (winetest_debug > 1) trace("TerminateDevice()\n"); + ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie); + /* Don't dereference the surfaces here, to mimic How to Survive. */ + return E_NOTIMPL; +} + +static HRESULT WINAPI allocator_GetSurface(IVMRSurfaceAllocator9 *iface, + DWORD_PTR cookie, DWORD index, DWORD flags, IDirect3DSurface9 **surface) +{ + if (winetest_debug > 1) trace("GetSurface(index %u)\n", index); + ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie); + ok(!flags, "Got flags %#x.\n", flags); + ok(index < 5, "Got index %u.\n", index); + + /* Don't reference the surface here, to mimic How to Survive. */ + *surface = allocator_surfaces[index]; + return S_OK; +} + +static HRESULT WINAPI allocator_AdviseNotify(IVMRSurfaceAllocator9 *iface, IVMRSurfaceAllocatorNotify9 *notify) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IVMRSurfaceAllocator9Vtbl allocator_vtbl = +{ + allocator_QueryInterface, + allocator_AddRef, + allocator_Release, + allocator_InitializeDevice, + allocator_TerminateDevice, + allocator_GetSurface, + allocator_AdviseNotify, +}; + +static IVMRSurfaceAllocator9 allocator_iface = {&allocator_vtbl}; +static IVMRImagePresenter9 presenter_iface = {&presenter_vtbl}; + +static void test_renderless_present(IFilterGraph2 *graph, IMemInputPin *input) +{ + IMediaControl *control; + OAFilterState state; + HANDLE thread; + HRESULT hr; + + IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); + + allocator_got_PresentImage = 0; + + hr = IMediaControl_Pause(control); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + thread = send_frame(input); + hr = IMediaControl_GetState(control, 1000, &state); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(allocator_got_PresentImage == 1, "Got %u calls to PresentImage().\n", allocator_got_PresentImage); + + hr = IMediaControl_Run(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = join_thread(thread); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + IMediaControl_Release(control); +} + +static void test_renderless_formats(void) +{ + VIDEOINFOHEADER vih = + { + .rcSource = {4, 6, 16, 12}, + .rcTarget = {40, 60, 160, 120}, + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biWidth = 32, + .bmiHeader.biHeight = 16, + }; + AM_MEDIA_TYPE req_mt = + { + .majortype = MEDIATYPE_Video, + .formattype = FORMAT_VideoInfo, + .cbFormat = sizeof(vih), + .pbFormat = (BYTE *)&vih, + }; + ALLOCATOR_PROPERTIES req_props = {5, 32 * 16 * 4, 1, 0}, ret_props; + IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless); + IFilterGraph2 *graph = create_graph(); + IVMRSurfaceAllocatorNotify9 *notify; + RECT rect = {0, 0, 640, 480}; + struct testfilter source; + IDirect3DDevice9 *device; + IMemAllocator *allocator; + IMemInputPin *input; + unsigned int i; + HWND window; + HRESULT hr; + ULONG ref; + IPin *pin; + + static const struct + { + const GUID *subtype; + D3DFORMAT format; + DWORD flags; + } + tests[] = + { + {&MEDIASUBTYPE_ARGB1555, D3DFMT_A1R5G5B5, VMR9AllocFlag_TextureSurface}, + {&MEDIASUBTYPE_ARGB32, D3DFMT_A8R8G8B8, VMR9AllocFlag_TextureSurface}, + {&MEDIASUBTYPE_ARGB4444, D3DFMT_A4R4G4B4, VMR9AllocFlag_TextureSurface}, + + {&MEDIASUBTYPE_RGB555, D3DFMT_X1R5G5B5, VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_RGB555, D3DFMT_X1R5G5B5, VMR9AllocFlag_TextureSurface}, + {&MEDIASUBTYPE_RGB565, D3DFMT_R5G6B5, VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_RGB565, D3DFMT_R5G6B5, VMR9AllocFlag_TextureSurface}, + {&MEDIASUBTYPE_RGB24, D3DFMT_R8G8B8, VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_RGB24, D3DFMT_R8G8B8, VMR9AllocFlag_TextureSurface}, + {&MEDIASUBTYPE_RGB32, D3DFMT_X8R8G8B8, VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_RGB32, D3DFMT_X8R8G8B8, VMR9AllocFlag_TextureSurface}, + + {&MEDIASUBTYPE_NV12, MAKEFOURCC('N','V','1','2'), VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_UYVY, D3DFMT_UYVY, VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_YUY2, D3DFMT_YUY2, VMR9AllocFlag_OffscreenSurface}, + {&MEDIASUBTYPE_YV12, MAKEFOURCC('Y','V','1','2'), VMR9AllocFlag_OffscreenSurface}, + }; + + IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)¬ify); + + AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); + window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, + rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL); + device = create_device(window); + + hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY)); + if (hr == E_NOINTERFACE) + { + win_skip("Direct3D does not support video rendering.\n"); + goto out; + } + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab, &allocator_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + allocator_notify = notify; + + testfilter_init(&source); + IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, filter, NULL); + IBaseFilter_FindPin(filter, L"VMR Input0", &pin); + IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + req_mt.subtype = *tests[i].subtype; + allocator_accept_flags = tests[i].flags; + + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + /* Connection never fails on Native, but Wine currently creates D3D + * surfaces during IPin::ReceiveConnection() instead of + * IMemAllocator::SetProperties(), so let that fail here for now. */ + if (hr != S_OK) + { + skip("Format %u (%#x), flags %#x are not supported, hr %#x.\n", + tests[i].format, tests[i].format, tests[i].flags, hr); + continue; + } + ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr); + + hr = IMemInputPin_GetAllocator(input, &allocator); + todo_wine_if (i == 0) ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr); + if (hr != S_OK) + { + test_allocator(input); + hr = IMemInputPin_GetAllocator(input, &allocator); + } + + hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props); + if (hr != S_OK) + { + skip("Format %u (%#x), flags %#x are not supported, hr %#x.\n", + tests[i].format, tests[i].format, tests[i].flags, hr); + IMemAllocator_Release(allocator); + hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr); + hr = IFilterGraph2_Disconnect(graph, pin); + ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr); + continue; + } + ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n"); + hr = IMemAllocator_Commit(allocator); + ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr); + + ok(allocator_format == tests[i].format, "Test %u: Got format %u (%#x).\n", + i, allocator_format, allocator_format); + + test_renderless_present(graph, input); + + hr = IMemAllocator_Decommit(allocator); + ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr); + IMemAllocator_Release(allocator); + + hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr); + hr = IFilterGraph2_Disconnect(graph, pin); + ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr); + } + + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + IMemInputPin_Release(input); + IPin_Release(pin); + +out: + IVMRSurfaceAllocatorNotify9_Release(notify); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ok(allocator_refcount == 1, "Got outstanding refcount %d.\n", allocator_refcount); + ref = IDirect3DDevice9_Release(device); + ok(!ref, "Got outstanding refcount %d.\n", ref); + DestroyWindow(window); +} + START_TEST(vmr9) { IBaseFilter *filter; @@ -2348,6 +2903,8 @@ START_TEST(vmr9) test_connect_pin(); test_overlay(); test_video_window(); + test_allocate_surface_helper(); + test_renderless_formats();
CoUninitialize(); }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/quartz/tests/vmr9.c | 2 +- dlls/quartz/vmr9.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index 45898db1117..1194fd8d17e 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -2508,7 +2508,7 @@ static void test_allocate_surface_helper(void) ok(hr == D3D_OK, "Got hr %#x.\n", hr); ok(desc.Format == info.Format, "Got format %#x.\n", desc.Format); ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type); - todo_wine ok(desc.Usage == D3DUSAGE_DYNAMIC, "Got usage %#x.\n", desc.Usage); + ok(desc.Usage == D3DUSAGE_DYNAMIC, "Got usage %#x.\n", desc.Usage); ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool); ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType); ok(!desc.MultiSampleQuality, "Got multisample quality %u.\n", desc.MultiSampleQuality); diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 0aa861c3a69..b2217547cdc 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -2138,7 +2138,7 @@ static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper(IVMRSurfa { IDirect3DTexture9 *texture;
- hr = IDirect3DDevice9_CreateTexture(This->allocator_d3d9_dev, allocinfo->dwWidth, allocinfo->dwHeight, 1, 0, + hr = IDirect3DDevice9_CreateTexture(This->allocator_d3d9_dev, allocinfo->dwWidth, allocinfo->dwHeight, 1, D3DUSAGE_DYNAMIC, allocinfo->Format, allocinfo->Pool, &texture, NULL); if (FAILED(hr)) break;