mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 22:14:06 +00:00
dxva2: Introduce progressive processor device.
The point is to provide a device, with similar caps and NV12 support, while keeping software device on its own, the way it should be. This is based on research by Derek Lesho. Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
996126b2de
commit
12a1b4b360
|
@ -34,6 +34,8 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dxva2);
|
||||
|
||||
#define D3DFMT_NV12 MAKEFOURCC('N','V','1','2')
|
||||
|
||||
enum device_handle_flags
|
||||
{
|
||||
HANDLE_FLAG_OPEN = 0x1,
|
||||
|
@ -125,6 +127,22 @@ static struct video_processor *impl_from_IDirectXVideoProcessor(IDirectXVideoPro
|
|||
return CONTAINING_RECORD(iface, struct video_processor, IDirectXVideoProcessor_iface);
|
||||
}
|
||||
|
||||
static const DXVA2_VideoProcessorCaps software_processor_caps =
|
||||
{
|
||||
.DeviceCaps = DXVA2_VPDev_SoftwareDevice,
|
||||
.InputPool = D3DPOOL_SYSTEMMEM,
|
||||
.VideoProcessorOperations = DXVA2_VideoProcess_PlanarAlpha | DXVA2_VideoProcess_YUV2RGB |
|
||||
DXVA2_VideoProcess_StretchX | DXVA2_VideoProcess_StretchY | DXVA2_VideoProcess_SubRects |
|
||||
DXVA2_VideoProcess_SubStreams | DXVA2_VideoProcess_SubStreamsExtended | DXVA2_VideoProcess_YUV2RGBExtended,
|
||||
};
|
||||
|
||||
static const DXVA2_VideoProcessorCaps progressive_processor_caps =
|
||||
{
|
||||
.DeviceCaps = DXVA2_VPDev_HardwareDevice,
|
||||
.InputPool = D3DPOOL_DEFAULT,
|
||||
.VideoProcessorOperations = DXVA2_VideoProcess_YUV2RGB | DXVA2_VideoProcess_StretchX | DXVA2_VideoProcess_StretchY,
|
||||
};
|
||||
|
||||
static HRESULT WINAPI video_processor_QueryInterface(IDirectXVideoProcessor *iface, REFIID riid, void **obj)
|
||||
{
|
||||
if (IsEqualIID(riid, &IID_IDirectXVideoProcessor) ||
|
||||
|
@ -210,12 +228,11 @@ static HRESULT WINAPI video_processor_GetVideoProcessorCaps(IDirectXVideoProcess
|
|||
|
||||
if (IsEqualGUID(&processor->device, &DXVA2_VideoProcSoftwareDevice))
|
||||
{
|
||||
memset(caps, 0, sizeof(*caps));
|
||||
caps->DeviceCaps = DXVA2_VPDev_SoftwareDevice;
|
||||
caps->InputPool = D3DPOOL_SYSTEMMEM;
|
||||
caps->VideoProcessorOperations = DXVA2_VideoProcess_PlanarAlpha | DXVA2_VideoProcess_YUV2RGB |
|
||||
DXVA2_VideoProcess_StretchX | DXVA2_VideoProcess_StretchY | DXVA2_VideoProcess_SubRects |
|
||||
DXVA2_VideoProcess_SubStreams | DXVA2_VideoProcess_SubStreamsExtended | DXVA2_VideoProcess_YUV2RGBExtended;
|
||||
*caps = software_processor_caps;
|
||||
}
|
||||
else if (IsEqualGUID(&processor->device, &DXVA2_VideoProcProgressiveDevice))
|
||||
{
|
||||
*caps = progressive_processor_caps;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -419,28 +436,66 @@ static HRESULT WINAPI device_manager_processor_service_RegisterVideoProcessorSof
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static BOOL dxva_is_supported_stream_format(const DXVA2_VideoDesc *video_desc)
|
||||
struct dxva_processor_device_desc
|
||||
{
|
||||
return video_desc->Format == D3DFMT_A8R8G8B8 ||
|
||||
video_desc->Format == D3DFMT_X8R8G8B8 ||
|
||||
video_desc->Format == D3DFMT_YUY2;
|
||||
const GUID *guid;
|
||||
const D3DFORMAT *input_formats;
|
||||
};
|
||||
|
||||
static const D3DFORMAT software_processor_input_formats[] =
|
||||
{
|
||||
D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_YUY2, 0
|
||||
};
|
||||
|
||||
static const D3DFORMAT progressive_processor_input_formats[] =
|
||||
{
|
||||
D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_YUY2, D3DFMT_NV12, 0
|
||||
};
|
||||
|
||||
static const struct dxva_processor_device_desc processor_devices[] =
|
||||
{
|
||||
{ &DXVA2_VideoProcProgressiveDevice, progressive_processor_input_formats },
|
||||
{ &DXVA2_VideoProcSoftwareDevice, software_processor_input_formats },
|
||||
};
|
||||
|
||||
static BOOL dxva_is_supported_stream_format(const DXVA2_VideoDesc *video_desc, const D3DFORMAT *formats)
|
||||
{
|
||||
while (*formats)
|
||||
{
|
||||
if (*formats == video_desc->Format) return TRUE;
|
||||
formats++;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI device_manager_processor_service_GetVideoProcessorDeviceGuids(
|
||||
IDirectXVideoProcessorService *iface, const DXVA2_VideoDesc *video_desc, UINT *count, GUID **guids)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
FIXME("%p, %p, %p, %p semi-stub.\n", iface, video_desc, count, guids);
|
||||
|
||||
*count = 0;
|
||||
|
||||
if (!dxva_is_supported_stream_format(video_desc))
|
||||
return E_FAIL;
|
||||
|
||||
if (!(*guids = CoTaskMemAlloc(sizeof(**guids))))
|
||||
if (!(*guids = CoTaskMemAlloc(ARRAY_SIZE(processor_devices) * sizeof(**guids))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
memcpy(*guids, &DXVA2_VideoProcSoftwareDevice, sizeof(**guids));
|
||||
*count = 1;
|
||||
for (i = 0; i < ARRAY_SIZE(processor_devices); ++i)
|
||||
{
|
||||
if (dxva_is_supported_stream_format(video_desc, processor_devices[i].input_formats))
|
||||
{
|
||||
(*guids)[*count] = *processor_devices[i].guid;
|
||||
*count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*count)
|
||||
{
|
||||
CoTaskMemFree(*guids);
|
||||
*guids = NULL;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -453,7 +508,7 @@ static HRESULT WINAPI device_manager_processor_service_GetVideoProcessorRenderTa
|
|||
|
||||
if (IsEqualGUID(deviceguid, &DXVA2_VideoProcSoftwareDevice))
|
||||
{
|
||||
if (!dxva_is_supported_stream_format(video_desc))
|
||||
if (!dxva_is_supported_stream_format(video_desc, software_processor_input_formats))
|
||||
{
|
||||
WARN("Unsupported content format %#x.\n", video_desc->Format);
|
||||
return E_FAIL;
|
||||
|
@ -468,6 +523,23 @@ static HRESULT WINAPI device_manager_processor_service_GetVideoProcessorRenderTa
|
|||
|
||||
return S_OK;
|
||||
}
|
||||
else if (IsEqualGUID(deviceguid, &DXVA2_VideoProcProgressiveDevice))
|
||||
{
|
||||
if (!dxva_is_supported_stream_format(video_desc, progressive_processor_input_formats))
|
||||
{
|
||||
WARN("Unsupported content format %#x.\n", video_desc->Format);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (!(*formats = CoTaskMemAlloc(2 * sizeof(**formats))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
*count = 2;
|
||||
(*formats)[0] = D3DFMT_X8R8G8B8;
|
||||
(*formats)[1] = D3DFMT_NV12;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
FIXME("Unsupported device %s.\n", debugstr_guid(deviceguid));
|
||||
|
||||
|
@ -484,12 +556,26 @@ static HRESULT WINAPI device_manager_processor_service_GetVideoProcessorSubStrea
|
|||
}
|
||||
|
||||
static HRESULT WINAPI device_manager_processor_service_GetVideoProcessorCaps(
|
||||
IDirectXVideoProcessorService *iface, REFGUID deviceguid, const DXVA2_VideoDesc *video_desc,
|
||||
IDirectXVideoProcessorService *iface, REFGUID device, const DXVA2_VideoDesc *video_desc,
|
||||
D3DFORMAT rt_format, DXVA2_VideoProcessorCaps *caps)
|
||||
{
|
||||
FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(deviceguid), video_desc, rt_format, caps);
|
||||
TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(device), video_desc, rt_format, caps);
|
||||
|
||||
return E_NOTIMPL;
|
||||
if (IsEqualGUID(device, &DXVA2_VideoProcSoftwareDevice))
|
||||
{
|
||||
*caps = software_processor_caps;
|
||||
}
|
||||
else if (IsEqualGUID(device, &DXVA2_VideoProcProgressiveDevice))
|
||||
{
|
||||
*caps = progressive_processor_caps;
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("Unrecognized device %s.\n", debugstr_guid(device));
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI device_manager_processor_service_GetProcAmpRange(
|
||||
|
|
|
@ -546,8 +546,157 @@ done:
|
|||
DestroyWindow(window);
|
||||
}
|
||||
|
||||
static BOOL check_format_list(D3DFORMAT format, const D3DFORMAT *list, unsigned int count)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < count; ++i)
|
||||
if (list[i] == format) return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void test_progressive_device(void)
|
||||
{
|
||||
static const unsigned int processor_ops = DXVA2_VideoProcess_YUV2RGB |
|
||||
DXVA2_VideoProcess_StretchX | DXVA2_VideoProcess_StretchY;
|
||||
IDirectXVideoProcessorService *service;
|
||||
IDirectXVideoProcessor *processor;
|
||||
IDirect3DDeviceManager9 *manager;
|
||||
D3DFORMAT format, *rt_formats;
|
||||
DXVA2_VideoProcessorCaps caps;
|
||||
DXVA2_VideoDesc video_desc;
|
||||
IDirect3DDevice9 *device;
|
||||
unsigned int count, i, j;
|
||||
GUID guid, *guids;
|
||||
IDirect3D9 *d3d;
|
||||
HANDLE handle;
|
||||
HWND window;
|
||||
UINT token;
|
||||
HRESULT hr;
|
||||
|
||||
static const D3DFORMAT input_formats[] =
|
||||
{
|
||||
D3DFMT_A8R8G8B8,
|
||||
D3DFMT_X8R8G8B8,
|
||||
D3DFMT_YUY2,
|
||||
MAKEFOURCC('N','V','1','2'),
|
||||
};
|
||||
|
||||
static const D3DFORMAT support_rt_formats[] =
|
||||
{
|
||||
D3DFMT_X8R8G8B8,
|
||||
MAKEFOURCC('N','V','1','2'),
|
||||
D3DFMT_YUY2,
|
||||
};
|
||||
|
||||
window = create_window();
|
||||
d3d = Direct3DCreate9(D3D_SDK_VERSION);
|
||||
ok(!!d3d, "Failed to create a D3D object.\n");
|
||||
if (!(device = create_device(d3d, window)))
|
||||
{
|
||||
skip("Failed to create a D3D device, skipping tests.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
hr = DXVA2CreateDirect3DDeviceManager9(&token, &manager);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IDirect3DDeviceManager9_ResetDevice(manager, device, token);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
handle = NULL;
|
||||
hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IDirect3DDeviceManager9_GetVideoService(manager, handle, &IID_IDirectXVideoProcessorService,
|
||||
(void **)&service);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
memset(&video_desc, 0, sizeof(video_desc));
|
||||
video_desc.SampleWidth = 64;
|
||||
video_desc.SampleHeight = 64;
|
||||
video_desc.Format = MAKEFOURCC('N','V','1','2');
|
||||
|
||||
hr = IDirectXVideoProcessorService_CreateVideoProcessor(service, &DXVA2_VideoProcProgressiveDevice, &video_desc,
|
||||
D3DFMT_A8R8G8B8, 0, &processor);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
win_skip("VideoProcProgressiveDevice is not supported.\n");
|
||||
goto unsupported;
|
||||
}
|
||||
IDirectXVideoProcessor_Release(processor);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(input_formats); ++i)
|
||||
{
|
||||
init_video_desc(&video_desc, input_formats[i]);
|
||||
|
||||
/* Check that progressive device is returned for given input format. */
|
||||
count = 0;
|
||||
hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids(service, &video_desc, &count, &guids);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
ok(count > 0, "Unexpected device count.\n");
|
||||
for (j = 0; j < count; ++j)
|
||||
{
|
||||
if (IsEqualGUID(&guids[j], &DXVA2_VideoProcProgressiveDevice)) break;
|
||||
}
|
||||
ok(j < count, "Expected progressive device for format %#x.\n", input_formats[i]);
|
||||
CoTaskMemFree(guids);
|
||||
|
||||
count = 0;
|
||||
hr = IDirectXVideoProcessorService_GetVideoProcessorRenderTargets(service, &DXVA2_VideoProcProgressiveDevice,
|
||||
&video_desc, &count, &rt_formats);
|
||||
ok(hr == S_OK, "Unexpected hr %#x, format %d.\n", hr, input_formats[i]);
|
||||
ok(count > 0, "Unexpected format count %u.\n", count);
|
||||
for (j = 0; j < count; ++j)
|
||||
{
|
||||
ok(check_format_list(rt_formats[j], support_rt_formats, ARRAY_SIZE(support_rt_formats)),
|
||||
"Unexpected rt format %#x for input format %#x.\n", rt_formats[j], input_formats[i]);
|
||||
}
|
||||
CoTaskMemFree(rt_formats);
|
||||
}
|
||||
|
||||
memset(&video_desc, 0, sizeof(video_desc));
|
||||
video_desc.SampleWidth = 64;
|
||||
video_desc.SampleHeight = 64;
|
||||
video_desc.Format = MAKEFOURCC('N','V','1','2');
|
||||
|
||||
hr = IDirectXVideoProcessorService_CreateVideoProcessor(service, &DXVA2_VideoProcProgressiveDevice, &video_desc,
|
||||
D3DFMT_A8R8G8B8, 0, &processor);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IDirectXVideoProcessor_GetVideoProcessorCaps(processor, &caps);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
ok(caps.DeviceCaps == DXVA2_VPDev_HardwareDevice, "Unexpected device type %#x.\n", caps.DeviceCaps);
|
||||
ok(caps.InputPool == D3DPOOL_DEFAULT, "Unexpected input pool %#x.\n", caps.InputPool);
|
||||
ok(!caps.NumForwardRefSamples, "Unexpected sample count.\n");
|
||||
ok(!caps.NumBackwardRefSamples, "Unexpected sample count.\n");
|
||||
ok(!caps.Reserved, "Unexpected field.\n");
|
||||
ok((caps.VideoProcessorOperations & processor_ops) == processor_ops, "Unexpected processor operations %#x.\n",
|
||||
caps.VideoProcessorOperations);
|
||||
|
||||
hr = IDirectXVideoProcessor_GetCreationParameters(processor, &guid, NULL, &format, NULL);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
ok(IsEqualGUID(&guid, &DXVA2_VideoProcProgressiveDevice), "Unexpected device guid.\n");
|
||||
ok(format == D3DFMT_A8R8G8B8, "Unexpected format %u.\n", format);
|
||||
|
||||
IDirectXVideoProcessor_Release(processor);
|
||||
|
||||
unsupported:
|
||||
IDirectXVideoProcessorService_Release(service);
|
||||
|
||||
hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
IDirect3DDevice9_Release(device);
|
||||
IDirect3DDeviceManager9_Release(manager);
|
||||
|
||||
done:
|
||||
IDirect3D9_Release(d3d);
|
||||
DestroyWindow(window);
|
||||
}
|
||||
|
||||
START_TEST(dxva2)
|
||||
{
|
||||
test_device_manager();
|
||||
test_video_processor();
|
||||
test_progressive_device();
|
||||
}
|
||||
|
|
|
@ -956,6 +956,8 @@ static HRESULT WINAPI video_mixer_transform_SetOutputType(IMFTransform *iface, D
|
|||
if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateVideoProcessor(service, &mixer->output.rt_formats[i].device,
|
||||
&video_desc, rt_format, MAX_MIXER_INPUT_SUBSTREAMS, &mixer->processor)))
|
||||
{
|
||||
ERR("picked dxva device %s\n", debugstr_guid(&mixer->output.rt_formats[i].device));
|
||||
|
||||
if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&mixer->aperture,
|
||||
sizeof(mixer->aperture), NULL)))
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue