From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/d3d11/device.c | 8 +++-- dlls/d3d11/tests/d3d11.c | 39 +++++++++++++--------- dlls/wined3d/decoder.c | 68 +++++++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d.spec | 1 + include/wine/wined3d.h | 2 ++ 5 files changed, 100 insertions(+), 18 deletions(-)
diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index 59d7adf86ce..1053dace677 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -3405,8 +3405,12 @@ static HRESULT STDMETHODCALLTYPE d3d11_video_context_SubmitDecoderBuffers(ID3D11 static HRESULT STDMETHODCALLTYPE d3d11_video_context_DecoderExtension(ID3D11VideoContext *iface, ID3D11VideoDecoder *decoder, const D3D11_VIDEO_DECODER_EXTENSION *extension) { - FIXME("iface %p, decoder %p, extension %p, stub!\n", iface, decoder, extension); - return E_NOTIMPL; + struct d3d_video_decoder *decoder_impl = unsafe_impl_from_ID3D11VideoDecoder(decoder); + + TRACE("iface %p, decoder %p, extension %p.\n", iface, decoder, extension); + + return wined3d_decoder_extension(decoder_impl->wined3d_decoder, extension->Function, extension->pPrivateInputData, + extension->PrivateInputDataSize, extension->pPrivateOutputData, extension->PrivateOutputDataSize); }
static void STDMETHODCALLTYPE d3d11_video_context_VideoProcessorSetOutputTargetRect( diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index 3c1cf932a04..af90fa2a7aa 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -37077,7 +37077,7 @@ static void test_h264_decoder(void) extension.pPrivateOutputData = &h264_status; extension.PrivateOutputDataSize = sizeof(h264_status); hr = ID3D11VideoContext_DecoderExtension(video_context, decoder, &extension); - todo_wine ok(hr == E_FAIL /* AMD */ || hr == S_OK /* NVidia */, "Got hr %#lx.\n", hr); + ok(hr == E_FAIL /* AMD */ || hr == S_OK /* NVidia */, "Got hr %#lx.\n", hr); if (hr == S_OK) { DXVA_Status_H264 zero_status = {0}; @@ -37287,23 +37287,30 @@ static void test_h264_decoder(void) memset(&extension, 0, sizeof(extension)); extension.Function = DXVA_STATUS_REPORTING_FUNCTION; extension.pPrivateOutputData = &h264_status; + extension.PrivateOutputDataSize = sizeof(h264_status) - 1; + hr = ID3D11VideoContext_DecoderExtension(video_context, decoder, &extension); + ok(hr == E_FAIL, "Got hr %#lx.\n", hr); + + memset(&h264_status, 0xcc, sizeof(h264_status)); + memset(&extension, 0, sizeof(extension)); + extension.Function = DXVA_STATUS_REPORTING_FUNCTION; + extension.pPrivateInputData = (void *)0xdeadbeef; + extension.PrivateInputDataSize = 123; + extension.pPrivateOutputData = &h264_status; extension.PrivateOutputDataSize = sizeof(h264_status); hr = ID3D11VideoContext_DecoderExtension(video_context, decoder, &extension); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(h264_status.StatusReportFeedbackNumber == 2, "Got number %u.\n", h264_status.StatusReportFeedbackNumber); - ok(h264_status.CurrPic.bPicEntry == 1, "Got index %#x.\n", h264_status.CurrPic.bPicEntry); - ok(!h264_status.field_pic_flag, "Got field pic flag %#x.\n", h264_status.field_pic_flag); - ok(h264_status.bDXVA_Func == DXVA_PICTURE_DECODING_FUNCTION, "Got function %#x.\n", h264_status.bDXVA_Func); - ok(h264_status.bBufType == (UCHAR)~0, "Got buffer type %#x.\n", h264_status.bBufType); - ok(!h264_status.bStatus, "Got status %#x.\n", h264_status.bStatus); - ok(!h264_status.bReserved8Bits, "Got reserved %#x.\n", h264_status.bReserved8Bits); - /* AMD reports that 1 macroblock was successfully decoded, which is - * obviously wrong. - * NVidia returns 0xffff, which is valid and means that no estimate was - * provided. */ - } + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(h264_status.StatusReportFeedbackNumber == 2, "Got number %u.\n", h264_status.StatusReportFeedbackNumber); + ok(h264_status.CurrPic.bPicEntry == 1, "Got index %#x.\n", h264_status.CurrPic.bPicEntry); + ok(!h264_status.field_pic_flag, "Got field pic flag %#x.\n", h264_status.field_pic_flag); + ok(h264_status.bDXVA_Func == DXVA_PICTURE_DECODING_FUNCTION, "Got function %#x.\n", h264_status.bDXVA_Func); + ok(h264_status.bBufType == (UCHAR)~0, "Got buffer type %#x.\n", h264_status.bBufType); + ok(!h264_status.bStatus, "Got status %#x.\n", h264_status.bStatus); + ok(!h264_status.bReserved8Bits, "Got reserved %#x.\n", h264_status.bReserved8Bits); + /* AMD reports that 1 macroblock was successfully decoded, which is + * obviously wrong. + * NVidia returns 0xffff, which is valid and means that no estimate was + * provided. */
for (unsigned int i = 0; i < ARRAY_SIZE(output_views); ++i) ID3D11VideoDecoderOutputView_Release(output_views[i]); diff --git a/dlls/wined3d/decoder.c b/dlls/wined3d/decoder.c index 073791c328e..b56468dcec4 100644 --- a/dlls/wined3d/decoder.c +++ b/dlls/wined3d/decoder.c @@ -28,6 +28,12 @@ struct wined3d_decoder struct wined3d_decoder_desc desc; struct wined3d_buffer *bitstream, *parameters, *matrix, *slice_control; struct wined3d_decoder_output_view *output_view; + + /* Accessed from both the CS and application threads. */ + CRITICAL_SECTION feedback_cs; + unsigned int feedback_number; + uint8_t feedback_pic_entry; + bool feedback_field; };
static void wined3d_decoder_cleanup(struct wined3d_decoder *decoder) @@ -36,6 +42,7 @@ static void wined3d_decoder_cleanup(struct wined3d_decoder *decoder) wined3d_buffer_decref(decoder->parameters); wined3d_buffer_decref(decoder->matrix); wined3d_buffer_decref(decoder->slice_control); + wined3d_lock_cleanup(&decoder->feedback_cs); }
ULONG CDECL wined3d_decoder_decref(struct wined3d_decoder *decoder) @@ -82,6 +89,7 @@ static HRESULT wined3d_decoder_init(struct wined3d_decoder *decoder, decoder->ref = 1; decoder->device = device; decoder->desc = *desc; + wined3d_lock_init(&decoder->feedback_cs, "wined3d_decoder.feedback_cs");
buffer_desc.byte_width = sizeof(DXVA_PicParams_H264); if (FAILED(hr = wined3d_buffer_create(device, &buffer_desc, @@ -1240,6 +1248,12 @@ static void wined3d_decoder_vk_decode_h264(struct wined3d_decoder_vk *decoder_vk
wined3d_decoder_vk_blit_output(decoder_vk, context_vk, output_view_vk, slot_index);
+ EnterCriticalSection(&decoder_vk->d.feedback_cs); + decoder_vk->d.feedback_number = h264_params->StatusReportFeedbackNumber; + decoder_vk->d.feedback_pic_entry = h264_params->CurrPic.bPicEntry; + decoder_vk->d.feedback_field = h264_params->field_pic_flag; + LeaveCriticalSection(&decoder_vk->d.feedback_cs); + out: wined3d_context_vk_destroy_vk_video_parameters(context_vk, vk_params, context_vk->current_command_buffer.id); free(slice_offsets); @@ -1364,3 +1378,57 @@ HRESULT CDECL wined3d_decoder_decode(struct wined3d_decoder *decoder, wined3d_cs_emit_decode(decoder, decoder->output_view, bitstream_size, slice_control_size); return S_OK; } + +HRESULT CDECL wined3d_decoder_extension(struct wined3d_decoder *decoder, unsigned int function, + const void *input, unsigned int input_size, void *output, unsigned int output_size) +{ + TRACE("decoder %p, function %#x, input %p, input_size %u, output %p, output_size %u.\n", + decoder, function, input, input_size, output, output_size); + + if (function == DXVA_STATUS_REPORTING_FUNCTION) + { + DXVA_Status_H264 *status = output; + unsigned int feedback_number; + uint8_t feedback_pic_entry; + bool feedback_field; + + if (output_size < sizeof(*status)) + { + WARN("Invalid size %u.\n", output_size); + return E_FAIL; + } + + /* FIXME: We should use Vulkan result status queries here. */ + + /* In lieu of real status information, we report the frame done as soon + * as the command has been submitted. That's earlier than it should be, + * but the application can't tell the difference. */ + + EnterCriticalSection(&decoder->feedback_cs); + feedback_number = decoder->feedback_number; + feedback_pic_entry = decoder->feedback_pic_entry; + feedback_field = decoder->feedback_field; + LeaveCriticalSection(&decoder->feedback_cs); + + /* AMD returns E_FAIL here; NVidia returns S_OK with zeroed output. */ + if (!feedback_number) + return E_FAIL; + + status->StatusReportFeedbackNumber = feedback_number; + status->CurrPic.bPicEntry = feedback_pic_entry; + status->field_pic_flag = feedback_field; + status->bDXVA_Func = DXVA_PICTURE_DECODING_FUNCTION; + status->bBufType = (UCHAR)~0; + status->bStatus = 0; + status->bReserved8Bits = 0; + /* 0xffff means no estimate provided. NVidia returns this. + * AMD returns 1, which is obviously wrong. */ + status->wNumMbsAffected = 0xffff; + return S_OK; + } + else + { + FIXME("Unhandled function %#x.\n", function); + return E_NOTIMPL; + } +} diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 94e418ca885..dc86887c251 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -45,6 +45,7 @@ @ cdecl wined3d_decoder_decref(ptr) @ cdecl wined3d_decoder_decode(ptr long long) @ cdecl wined3d_decoder_end_frame(ptr) +@ cdecl wined3d_decoder_extension(ptr long ptr long ptr long) @ cdecl wined3d_decoder_get_buffer(ptr long)
@ cdecl wined3d_decoder_output_view_create(ptr ptr ptr ptr ptr) diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index a3d449f14c6..2c57b55cb1a 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2386,6 +2386,8 @@ HRESULT __cdecl wined3d_decoder_decode(struct wined3d_decoder *decoder, unsigned int bitstream_size, unsigned int slice_control_size); ULONG __cdecl wined3d_decoder_decref(struct wined3d_decoder *decoder); HRESULT __cdecl wined3d_decoder_end_frame(struct wined3d_decoder *decoder); +HRESULT __cdecl wined3d_decoder_extension(struct wined3d_decoder *decoder, unsigned int function, + const void *input, unsigned int input_size, void *output, unsigned int output_size); struct wined3d_resource * __cdecl wined3d_decoder_get_buffer( struct wined3d_decoder *decoder, enum wined3d_decoder_buffer_type type);