From: Elizabeth Figura zfigura@codeweavers.com
This patch contains all the boilerplate for splitting purposes; the actual implementation is deferred to a following patch. --- dlls/d3d11/device.c | 30 +++++++++++++++++++-- dlls/wined3d/cs.c | 48 ++++++++++++++++++++++++++++++++++ dlls/wined3d/decoder.c | 23 ++++++++++++++++ dlls/wined3d/wined3d.spec | 1 + dlls/wined3d/wined3d_private.h | 5 ++++ include/wine/wined3d.h | 2 ++ 6 files changed, 107 insertions(+), 2 deletions(-)
diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index 64baad68859..cf62e5151ef 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -3232,8 +3232,34 @@ static HRESULT STDMETHODCALLTYPE d3d11_video_context_DecoderEndFrame( static HRESULT STDMETHODCALLTYPE d3d11_video_context_SubmitDecoderBuffers(ID3D11VideoContext *iface, ID3D11VideoDecoder *decoder, UINT count, const D3D11_VIDEO_DECODER_BUFFER_DESC *buffers) { - FIXME("iface %p, decoder %p, count %u, buffers %p, stub!\n", iface, decoder, count, buffers); - return E_NOTIMPL; + struct d3d_video_decoder *decoder_impl = unsafe_impl_from_ID3D11VideoDecoder(decoder); + unsigned int bitstream_size = 0, slice_control_size = 0; + + TRACE("iface %p, decoder %p, count %u, buffers %p.\n", iface, decoder, count, buffers); + + for (unsigned int i = 0; i < count; ++i) + { + const D3D11_VIDEO_DECODER_BUFFER_DESC *buffer = &buffers[i]; + + TRACE(" [%u] type %#x, size %u, first MB %u, MB count %u.\n", + i, buffer->BufferType, buffer->DataSize, buffer->FirstMBaddress, buffer->NumMBsInBuffer); + + switch (buffer->BufferType) + { + case D3D11_VIDEO_DECODER_BUFFER_BITSTREAM: + bitstream_size = buffer->DataSize; + break; + + case D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL: + slice_control_size = buffer->DataSize; + break; + + default: + break; + } + } + + return wined3d_decoder_decode(decoder_impl->wined3d_decoder, bitstream_size, slice_control_size); }
static HRESULT STDMETHODCALLTYPE d3d11_video_context_DecoderExtension(ID3D11VideoContext *iface, diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 9bac7afdba2..1c5685220b1 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -140,6 +140,7 @@ enum wined3d_cs_op WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW, WINED3D_CS_OP_COPY_UAV_COUNTER, WINED3D_CS_OP_GENERATE_MIPMAPS, + WINED3D_CS_OP_DECODE, WINED3D_CS_OP_EXECUTE_COMMAND_LIST, WINED3D_CS_OP_STOP, }; @@ -532,6 +533,14 @@ struct wined3d_cs_generate_mipmaps struct wined3d_shader_resource_view *view; };
+struct wined3d_cs_decode +{ + enum wined3d_cs_op opcode; + struct wined3d_decoder *decoder; + struct wined3d_decoder_output_view *output_view; + unsigned int bitstream_size, slice_control_size; +}; + struct wined3d_cs_execute_command_list { enum wined3d_cs_op opcode; @@ -626,6 +635,7 @@ static const char *debug_cs_op(enum wined3d_cs_op op) WINED3D_TO_STR(WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW); WINED3D_TO_STR(WINED3D_CS_OP_COPY_UAV_COUNTER); WINED3D_TO_STR(WINED3D_CS_OP_GENERATE_MIPMAPS); + WINED3D_TO_STR(WINED3D_CS_OP_DECODE); WINED3D_TO_STR(WINED3D_CS_OP_EXECUTE_COMMAND_LIST); WINED3D_TO_STR(WINED3D_CS_OP_STOP); #undef WINED3D_TO_STR @@ -2940,6 +2950,43 @@ void wined3d_device_context_emit_generate_mipmaps(struct wined3d_device_context wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT); }
+static void wined3d_cs_exec_decode(struct wined3d_cs *cs, const void *data) +{ + const struct wined3d_cs_decode *op = data; + struct wined3d_context *context; + + context = context_acquire(cs->c.device, NULL, 0); + cs->c.device->adapter->decoder_ops->decode(context, op->decoder, + op->output_view, op->bitstream_size, op->slice_control_size); + context_release(context); +} + +void wined3d_cs_emit_decode(struct wined3d_decoder *decoder, struct wined3d_decoder_output_view *output_view, + unsigned int bitstream_size, unsigned int slice_control_size) +{ + struct wined3d_device_context *context = &output_view->texture->resource.device->cs->c; + struct wined3d_cs_decode *op; + + op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); + op->opcode = WINED3D_CS_OP_DECODE; + op->decoder = decoder; + op->output_view = output_view; + op->bitstream_size = bitstream_size; + op->slice_control_size = slice_control_size; + + wined3d_device_context_reference_resource(context, &output_view->texture->resource); + wined3d_device_context_reference_resource(context, + wined3d_decoder_get_buffer(decoder, WINED3D_DECODER_BUFFER_BITSTREAM)); + wined3d_device_context_reference_resource(context, + wined3d_decoder_get_buffer(decoder, WINED3D_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX)); + wined3d_device_context_reference_resource(context, + wined3d_decoder_get_buffer(decoder, WINED3D_DECODER_BUFFER_PICTURE_PARAMETERS)); + wined3d_device_context_reference_resource(context, + wined3d_decoder_get_buffer(decoder, WINED3D_DECODER_BUFFER_SLICE_CONTROL)); + + wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT); +} + static void wined3d_cs_emit_stop(struct wined3d_cs *cs) { struct wined3d_cs_stop *op; @@ -3009,6 +3056,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view, /* WINED3D_CS_OP_COPY_UAV_COUNTER */ wined3d_cs_exec_copy_uav_counter, /* WINED3D_CS_OP_GENERATE_MIPMAPS */ wined3d_cs_exec_generate_mipmaps, + /* WINED3D_CS_OP_DECODE */ wined3d_cs_exec_decode, /* WINED3D_CS_OP_EXECUTE_COMMAND_LIST */ wined3d_cs_exec_execute_command_list, };
diff --git a/dlls/wined3d/decoder.c b/dlls/wined3d/decoder.c index 1a33f759174..578b00d1f6b 100644 --- a/dlls/wined3d/decoder.c +++ b/dlls/wined3d/decoder.c @@ -440,11 +440,19 @@ static HRESULT wined3d_decoder_vk_create(struct wined3d_device *device, return WINED3D_OK; }
+static void wined3d_decoder_vk_decode(struct wined3d_context *context, struct wined3d_decoder *decoder, + struct wined3d_decoder_output_view *output_view, + unsigned int bitstream_size, unsigned int slice_control_size) +{ + FIXME("Not implemented.\n"); +} + const struct wined3d_decoder_ops wined3d_decoder_vk_ops = { .get_profiles = wined3d_decoder_vk_get_profiles, .create = wined3d_decoder_vk_create, .destroy = wined3d_decoder_vk_destroy, + .decode = wined3d_decoder_vk_decode, };
struct wined3d_resource * CDECL wined3d_decoder_get_buffer( @@ -501,3 +509,18 @@ HRESULT CDECL wined3d_decoder_end_frame(struct wined3d_decoder *decoder)
return S_OK; } + +HRESULT CDECL wined3d_decoder_decode(struct wined3d_decoder *decoder, + unsigned int bitstream_size, unsigned int slice_control_size) +{ + TRACE("decoder %p, bitstream_size %u, slice_control_size %u.\n", decoder, bitstream_size, slice_control_size); + + if (!decoder->output_view) + { + ERR("Not in frame.\n"); + return E_INVALIDARG; + } + + wined3d_cs_emit_decode(decoder, decoder->output_view, bitstream_size, slice_control_size); + return S_OK; +} diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index e9125e52cf6..dba67917004 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -43,6 +43,7 @@ @ cdecl wined3d_decoder_begin_frame(ptr ptr) @ cdecl wined3d_decoder_create(ptr ptr ptr) @ cdecl wined3d_decoder_decref(ptr) +@ cdecl wined3d_decoder_decode(ptr long long) @ cdecl wined3d_decoder_end_frame(ptr) @ cdecl wined3d_decoder_get_buffer(ptr long)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index e73ba018929..936bd46c15f 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3701,6 +3701,8 @@ void wined3d_cs_emit_add_dirty_texture_region(struct wined3d_cs *cs, struct wined3d_texture *texture, unsigned int layer); void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *rects, uint32_t flags, const struct wined3d_color *color, float depth, DWORD stencil); +void wined3d_cs_emit_decode(struct wined3d_decoder *decoder, struct wined3d_decoder_output_view *output_view, + unsigned int bitstream_size, unsigned int slice_control_size); void wined3d_device_context_emit_clear_uav(struct wined3d_device_context *context, struct wined3d_unordered_access_view *view, const struct wined3d_uvec4 *clear_value, bool fp); void wined3d_cs_emit_preload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource); @@ -4486,6 +4488,9 @@ struct wined3d_decoder_ops HRESULT (*create)(struct wined3d_device *device, const struct wined3d_decoder_desc *desc, struct wined3d_decoder **decoder); void (*destroy)(struct wined3d_decoder *decoder); + void (*decode)(struct wined3d_context *context, struct wined3d_decoder *decoder, + struct wined3d_decoder_output_view *output_view, + unsigned int bitstream_size, unsigned int slice_control_size); };
extern const struct wined3d_decoder_ops wined3d_decoder_vk_ops; diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 7a0434925c0..11aa2499c05 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2382,6 +2382,8 @@ HRESULT __cdecl wined3d_decoder_begin_frame(struct wined3d_decoder *decoder, struct wined3d_decoder_output_view *view); HRESULT __cdecl wined3d_decoder_create(struct wined3d_device *device, const struct wined3d_decoder_desc *desc, struct wined3d_decoder **decoder); +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); struct wined3d_resource * __cdecl wined3d_decoder_get_buffer(
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/wined3d/context_vk.c | 174 +++++++++++++++++++++++++++++++++++--- dlls/wined3d/decoder.c | 95 +++++++++++++++++++++ dlls/wined3d/wined3d_vk.h | 45 ++++++++++ 3 files changed, 302 insertions(+), 12 deletions(-)
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index 42c54faeb8b..cc04b1cc1cf 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -1200,6 +1200,116 @@ static void wined3d_context_vk_remove_command_buffer(struct wined3d_context_vk * *buffer = context_vk->submitted.buffers[--context_vk->submitted.buffer_count]; }
+bool wined3d_aux_command_pool_vk_get_buffer(struct wined3d_context_vk *context_vk, + struct wined3d_aux_command_pool_vk *pool, struct wined3d_aux_command_buffer_vk *buffer) +{ + VkCommandBufferBeginInfo begin_info = {.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + VkResult vr; + + if (pool->buffer_count) + { + *buffer = pool->buffers[--pool->buffer_count]; + } + else + { + VkCommandBufferAllocateInfo command_buffer_info = {.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO}; + VkSemaphoreCreateInfo semaphore_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; + + if ((vr = VK_CALL(vkCreateSemaphore(device_vk->vk_device, &semaphore_info, NULL, &buffer->signal_semaphore))) < 0) + { + ERR("Failed to create signal_semaphore, vr %s.\n", wined3d_debug_vkresult(vr)); + return false; + } + + if ((vr = VK_CALL(vkCreateSemaphore(device_vk->vk_device, &semaphore_info, NULL, &buffer->wait_semaphore))) < 0) + { + ERR("Failed to create wait_semaphore, vr %s.\n", wined3d_debug_vkresult(vr)); + VK_CALL(vkDestroySemaphore(device_vk->vk_device, buffer->signal_semaphore, NULL)); + return false; + } + + command_buffer_info.commandPool = pool->vk_pool; + command_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + command_buffer_info.commandBufferCount = 1; + if ((vr = VK_CALL(vkAllocateCommandBuffers(device_vk->vk_device, + &command_buffer_info, &buffer->vk_command_buffer))) < 0) + { + WARN("Failed to allocate Vulkan command buffer, vr %s.\n", wined3d_debug_vkresult(vr)); + VK_CALL(vkDestroySemaphore(device_vk->vk_device, buffer->signal_semaphore, NULL)); + VK_CALL(vkDestroySemaphore(device_vk->vk_device, buffer->wait_semaphore, NULL)); + return false; + } + } + + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + if ((vr = VK_CALL(vkBeginCommandBuffer(buffer->vk_command_buffer, &begin_info))) < 0) + { + WARN("Failed to begin command buffer, vr %s.\n", wined3d_debug_vkresult(vr)); + VK_CALL(vkFreeCommandBuffers(device_vk->vk_device, pool->vk_pool, 1, &buffer->vk_command_buffer)); + return false; + } + + return true; +} + +void wined3d_aux_command_pool_vk_retire_buffer( + struct wined3d_context_vk *context_vk, struct wined3d_aux_command_pool_vk *pool, + const struct wined3d_aux_command_buffer_vk *buffer, uint64_t command_buffer_id) +{ + struct wined3d_retired_object_vk *o; + + /* No point checking if it's complete. Auxiliary command buffers are + * always submitted before the main command buffer that depends on them. */ + + if (!(o = wined3d_context_vk_get_retired_object_vk(context_vk))) + { + ERR("Leaking auxiliary command buffer %p.\n", buffer->vk_command_buffer); + return; + } + + o->type = WINED3D_RETIRED_AUX_COMMAND_BUFFER_VK; + o->u.aux_command_buffer.buffer = *buffer; + o->u.aux_command_buffer.pool = pool; + o->command_buffer_id = command_buffer_id; +} + +static void wined3d_aux_command_pool_vk_complete_buffer(struct wined3d_context_vk *context_vk, + struct wined3d_aux_command_pool_vk *pool, const struct wined3d_aux_command_buffer_vk *buffer) +{ + struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + + if (!wined3d_array_reserve((void **)&pool->buffers, &pool->buffers_size, + pool->buffer_count + 1, sizeof(*pool->buffers))) + { + VK_CALL(vkFreeCommandBuffers(device_vk->vk_device, pool->vk_pool, 1, &buffer->vk_command_buffer)); + return; + } + + pool->buffers[pool->buffer_count++] = *buffer; +} + +static void wined3d_aux_command_pool_vk_cleanup(struct wined3d_context_vk *context_vk, + struct wined3d_aux_command_pool_vk *pool) +{ + struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + + for (unsigned int i = 0; i < pool->buffer_count; ++i) + { + struct wined3d_aux_command_buffer_vk *buffer = &pool->buffers[i]; + + VK_CALL(vkDestroySemaphore(device_vk->vk_device, buffer->wait_semaphore, NULL)); + VK_CALL(vkDestroySemaphore(device_vk->vk_device, buffer->signal_semaphore, NULL)); + VK_CALL(vkFreeCommandBuffers(device_vk->vk_device, + pool->vk_pool, 1, &buffer->vk_command_buffer)); + } + VK_CALL(vkDestroyCommandPool(device_vk->vk_device, pool->vk_pool, NULL)); + free(pool->buffers); +} + static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *context_vk, VkFence vk_fence) { struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); @@ -1311,6 +1421,11 @@ static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *cont TRACE("Destroyed video session 0x%s.\n", wine_dbgstr_longlong(o->u.vk_video_session)); break;
+ case WINED3D_RETIRED_AUX_COMMAND_BUFFER_VK: + wined3d_aux_command_pool_vk_complete_buffer(context_vk, + o->u.aux_command_buffer.pool, &o->u.aux_command_buffer.buffer); + break; + default: ERR("Unhandled object type %#x.\n", o->type); break; @@ -1788,6 +1903,7 @@ void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk) * this needs to happen after all command buffers are freed, because * vkFreeCommandBuffers() requires a valid pool handle. */ VK_CALL(vkDestroyCommandPool(device_vk->vk_device, context_vk->vk_command_pool, NULL)); + wined3d_aux_command_pool_vk_cleanup(context_vk, &context_vk->decode_pool); wined3d_context_vk_destroy_query_pools(context_vk, &context_vk->free_occlusion_query_pools); wined3d_context_vk_destroy_query_pools(context_vk, &context_vk->free_timestamp_query_pools); wined3d_context_vk_destroy_query_pools(context_vk, &context_vk->free_pipeline_statistics_query_pools); @@ -1989,11 +2105,26 @@ void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context
VK_CALL(vkResetFences(device_vk->vk_device, 1, &buffer->vk_fence));
+ if (wait_semaphore_count) + { + wined3d_array_reserve((void **)&context_vk->wait_semaphores, &context_vk->wait_semaphores_size, + context_vk->wait_semaphore_count + wait_semaphore_count, sizeof(*context_vk->wait_semaphores)); + memcpy(context_vk->wait_semaphores + context_vk->wait_semaphore_count, + wait_semaphores, wait_semaphore_count * sizeof(VkSemaphore)); + + wined3d_array_reserve((void **)&context_vk->wait_stages, &context_vk->wait_stages_size, + context_vk->wait_semaphore_count + wait_semaphore_count, sizeof(*context_vk->wait_stages)); + memcpy(context_vk->wait_stages + context_vk->wait_semaphore_count, + wait_stages, wait_semaphore_count * sizeof(VkPipelineStageFlags)); + + context_vk->wait_semaphore_count += wait_semaphore_count; + } + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = NULL; - submit_info.waitSemaphoreCount = wait_semaphore_count; - submit_info.pWaitSemaphores = wait_semaphores; - submit_info.pWaitDstStageMask = wait_stages; + submit_info.waitSemaphoreCount = context_vk->wait_semaphore_count; + submit_info.pWaitSemaphores = context_vk->wait_semaphores; + submit_info.pWaitDstStageMask = context_vk->wait_stages; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &buffer->vk_command_buffer; submit_info.signalSemaphoreCount = signal_semaphore_count; @@ -2007,6 +2138,8 @@ void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context context_vk->submitted.buffer_count + 1, sizeof(*context_vk->submitted.buffers))) ERR("Failed to grow submitted command buffer array.\n");
+ context_vk->wait_semaphore_count = 0; + context_vk->submitted.buffers[context_vk->submitted.buffer_count++] = *buffer;
buffer->vk_command_buffer = VK_NULL_HANDLE; @@ -4182,13 +4315,26 @@ VkCommandBuffer wined3d_context_vk_apply_compute_state(struct wined3d_context_vk return vk_command_buffer; }
+static VkCommandPool create_command_pool(struct wined3d_device_vk *device_vk, + const struct wined3d_vk_info *vk_info, uint32_t queue_family_index) +{ + VkCommandPoolCreateInfo command_pool_info = {.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; + VkCommandPool pool; + VkResult vr; + + command_pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + command_pool_info.queueFamilyIndex = queue_family_index; + if ((vr = VK_CALL(vkCreateCommandPool(device_vk->vk_device, &command_pool_info, NULL, &pool))) == VK_SUCCESS) + return pool; + ERR("Failed to create Vulkan command pool, vr %s.\n", wined3d_debug_vkresult(vr)); + return VK_NULL_HANDLE; +} + HRESULT wined3d_context_vk_init(struct wined3d_context_vk *context_vk, struct wined3d_swapchain *swapchain) { - VkCommandPoolCreateInfo command_pool_info; const struct wined3d_vk_info *vk_info; struct wined3d_adapter_vk *adapter_vk; struct wined3d_device_vk *device_vk; - VkResult vr;
TRACE("context_vk %p, swapchain %p.\n", context_vk, swapchain);
@@ -4198,19 +4344,23 @@ HRESULT wined3d_context_vk_init(struct wined3d_context_vk *context_vk, struct wi adapter_vk = wined3d_adapter_vk(device_vk->d.adapter); context_vk->vk_info = vk_info = &adapter_vk->vk_info;
- command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - command_pool_info.pNext = NULL; - command_pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - command_pool_info.queueFamilyIndex = device_vk->graphics_queue.vk_queue_family_index; - if ((vr = VK_CALL(vkCreateCommandPool(device_vk->vk_device, - &command_pool_info, NULL, &context_vk->vk_command_pool))) < 0) + if (!(context_vk->vk_command_pool = create_command_pool(device_vk, + vk_info, device_vk->graphics_queue.vk_queue_family_index))) { - ERR("Failed to create Vulkan command pool, vr %s.\n", wined3d_debug_vkresult(vr)); wined3d_context_cleanup(&context_vk->c); return E_FAIL; } context_vk->current_command_buffer.id = 1;
+ if (device_vk->decode_queue.vk_queue + && !(context_vk->decode_pool.vk_pool = create_command_pool(device_vk, + vk_info, device_vk->decode_queue.vk_queue_family_index))) + { + VK_CALL(vkDestroyCommandPool(device_vk->vk_device, context_vk->vk_command_pool, NULL)); + wined3d_context_cleanup(&context_vk->c); + return E_FAIL; + } + wined3d_context_vk_init_graphics_pipeline_key(context_vk);
list_init(&context_vk->render_pass_queries); diff --git a/dlls/wined3d/decoder.c b/dlls/wined3d/decoder.c index 578b00d1f6b..5a4fd33b65c 100644 --- a/dlls/wined3d/decoder.c +++ b/dlls/wined3d/decoder.c @@ -159,6 +159,9 @@ struct wined3d_decoder_vk uint64_t command_buffer_id; struct wined3d_allocator_block *session_memory; VkDeviceMemory vk_session_memory; + + bool needs_wait_semaphore; + struct wined3d_aux_command_buffer_vk command_buffer; };
static struct wined3d_decoder_vk *wined3d_decoder_vk(struct wined3d_decoder *decoder) @@ -440,11 +443,103 @@ static HRESULT wined3d_decoder_vk_create(struct wined3d_device *device, return WINED3D_OK; }
+static bool get_decode_command_buffer(struct wined3d_decoder_vk *decoder_vk, + struct wined3d_context_vk *context_vk, struct wined3d_decoder_output_view *view) +{ + const struct wined3d_texture_vk *texture_vk = wined3d_texture_vk(view->texture); + + if (!wined3d_aux_command_pool_vk_get_buffer(context_vk, &context_vk->decode_pool, &decoder_vk->command_buffer)) + return false; + + /* If the output texture in question is in use by the current main CB, + * we will need this ACB to wait for the main CB to complete. + * + * We check this by comparing IDs. + * Note that if view_vk->command_buffer_id == current_command_buffer.id + * then the current CB must be active, otherwise the view should not have + * been referenced to it. */ + if (texture_vk->image.command_buffer_id == context_vk->current_command_buffer.id) + { + wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, + 1, &decoder_vk->command_buffer.wait_semaphore); + decoder_vk->needs_wait_semaphore = true; + } + else + { + /* Submit the main CB anyway. We don't strictly need to do this + * immediately, but we need to do it before the resource will be used. + * We also need to do this because resources we're tracking (session, + * session parameters, reference frames) need to be tied to the next + * main CB rather than the current one. + * Submitting now saves us the work of tracking that information, + * and the resource will probably be used almost immediately anyway. */ + wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL); + decoder_vk->needs_wait_semaphore = false; + } + + return true; +} + +static void submit_decode_command_buffer(struct wined3d_decoder_vk *decoder_vk, + struct wined3d_context_vk *context_vk) +{ + static const VkPipelineStageFlags stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); + VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO}; + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + VkResult vr; + + /* We don't strictly need to submit the ACB here. But ffmpeg and gstreamer + * do, so it's probably the right thing to do. + * + * We don't strictly need to submit the main CB here either; we could delay + * until we use the output resource. However that's a bit more complex to + * track, and I'm not sure that there's a performance reason *not* to + * submit early? */ + + VK_CALL(vkEndCommandBuffer(decoder_vk->command_buffer.vk_command_buffer)); + + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &decoder_vk->command_buffer.vk_command_buffer; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &decoder_vk->command_buffer.signal_semaphore; + if (decoder_vk->needs_wait_semaphore) + { + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &decoder_vk->command_buffer.wait_semaphore; + submit_info.pWaitDstStageMask = &stage_mask; + } + + if ((vr = VK_CALL(vkQueueSubmit(device_vk->decode_queue.vk_queue, 1, &submit_info, VK_NULL_HANDLE))) < 0) + ERR("Failed to submit, vr %d.\n", vr); + + /* Mark that the next CB needs to wait on our semaphore. */ + wined3d_array_reserve((void **)&context_vk->wait_semaphores, &context_vk->wait_semaphores_size, + context_vk->wait_semaphore_count + 1, sizeof(*context_vk->wait_semaphores)); + context_vk->wait_semaphores[context_vk->wait_semaphore_count] = decoder_vk->command_buffer.signal_semaphore; + wined3d_array_reserve((void **)&context_vk->wait_stages, &context_vk->wait_stages_size, + context_vk->wait_semaphore_count + 1, sizeof(*context_vk->wait_stages)); + context_vk->wait_stages[context_vk->wait_semaphore_count] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + ++context_vk->wait_semaphore_count; + + /* Retire this buffer. */ + wined3d_aux_command_pool_vk_retire_buffer(context_vk, &context_vk->decode_pool, + &decoder_vk->command_buffer, context_vk->current_command_buffer.id); +} + static void wined3d_decoder_vk_decode(struct wined3d_context *context, struct wined3d_decoder *decoder, struct wined3d_decoder_output_view *output_view, unsigned int bitstream_size, unsigned int slice_control_size) { + struct wined3d_decoder_vk *decoder_vk = wined3d_decoder_vk(decoder); + struct wined3d_context_vk *context_vk = wined3d_context_vk(context); + + if (!get_decode_command_buffer(decoder_vk, context_vk, output_view)) + return; + FIXME("Not implemented.\n"); + + submit_decode_command_buffer(decoder_vk, context_vk); }
const struct wined3d_decoder_ops wined3d_decoder_vk_ops = diff --git a/dlls/wined3d/wined3d_vk.h b/dlls/wined3d/wined3d_vk.h index fcc275490c7..c3317ea6ce1 100644 --- a/dlls/wined3d/wined3d_vk.h +++ b/dlls/wined3d/wined3d_vk.h @@ -433,6 +433,17 @@ struct wined3d_command_buffer_vk VkFence vk_fence; };
+struct wined3d_aux_command_buffer_vk +{ + VkCommandBuffer vk_command_buffer; + /* Semaphore that the auxiliary CB signals and the main CB will wait on. */ + VkSemaphore signal_semaphore; + /* Semaphore that the main CB signals and the auxiliary CB will wait on. + * This is necessary for when the main CB uses resources that the auxiliary + * CB needs to use. */ + VkSemaphore wait_semaphore; +}; + enum wined3d_retired_object_type_vk { WINED3D_RETIRED_FREE_VK, @@ -450,6 +461,7 @@ enum wined3d_retired_object_type_vk WINED3D_RETIRED_EVENT_VK, WINED3D_RETIRED_PIPELINE_VK, WINED3D_RETIRED_VIDEO_SESSION_VK, + WINED3D_RETIRED_AUX_COMMAND_BUFFER_VK, };
struct wined3d_retired_object_vk @@ -481,6 +493,11 @@ struct wined3d_retired_object_vk uint32_t start; uint32_t count; } queries; + struct + { + struct wined3d_aux_command_pool_vk *pool; + struct wined3d_aux_command_buffer_vk buffer; + } aux_command_buffer; } u; uint64_t command_buffer_id; }; @@ -595,6 +612,28 @@ struct wined3d_shader_descriptor_writes_vk SIZE_T size, count; };
+/* In order to track whether resources can be destroyed or reused, we use + * the sequence ID of a command buffer submitted to the graphics queue. + * + * In order to extend this system to command buffers submitted to different + * queues, we use a semaphore to associate these "auxiliary" command buffers + * with the next graphics queue submission. These command buffers then get + * an associated command_buffer_id and are freed back to the auxiliary + * command pool via wined3d_retired_object_vk, just like any other resource. + */ +struct wined3d_aux_command_pool_vk +{ + VkCommandPool vk_pool; + struct wined3d_aux_command_buffer_vk *buffers; + SIZE_T buffers_size, buffer_count; +}; + +bool wined3d_aux_command_pool_vk_get_buffer(struct wined3d_context_vk *context_vk, + struct wined3d_aux_command_pool_vk *pool, struct wined3d_aux_command_buffer_vk *buffer); +void wined3d_aux_command_pool_vk_retire_buffer( + struct wined3d_context_vk *context_vk, struct wined3d_aux_command_pool_vk *pool, + const struct wined3d_aux_command_buffer_vk *buffer, uint64_t command_buffer_id); + struct wined3d_context_vk { struct wined3d_context c; @@ -632,6 +671,10 @@ struct wined3d_context_vk /* Number of draw or dispatch calls that have been recorded into the * current command buffer. */ unsigned int command_buffer_work_count; + /* Semaphores that the current command buffer must wait on. */ + VkSemaphore *wait_semaphores; + VkPipelineStageFlags *wait_stages; + SIZE_T wait_semaphore_count, wait_semaphores_size, wait_stages_size;
struct { @@ -640,6 +683,8 @@ struct wined3d_context_vk SIZE_T buffer_count; } submitted, completed;
+ struct wined3d_aux_command_pool_vk decode_pool; + struct wined3d_shader_descriptor_writes_vk descriptor_writes;
VkFramebuffer vk_framebuffer;
From: Elizabeth Figura zfigura@codeweavers.com
Even if there is no active command buffer. --- dlls/wined3d/context_vk.c | 99 +++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 45 deletions(-)
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index cc04b1cc1cf..5d2c9cd0a3f 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -2048,11 +2048,11 @@ void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context unsigned int signal_semaphore_count, const VkSemaphore *signal_semaphores) { struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); + VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO}; const struct wined3d_vk_info *vk_info = context_vk->vk_info; struct wined3d_query_pool_vk *pool_vk, *pool_vk_next; struct wined3d_command_buffer_vk *buffer; struct wined3d_query_vk *query_vk; - VkSubmitInfo submit_info; VkResult vr;
TRACE("context_vk %p, wait_semaphore_count %u, wait_semaphores %p, wait_stages %p," @@ -2061,49 +2061,53 @@ void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context signal_semaphore_count, signal_semaphores);
buffer = &context_vk->current_command_buffer; - if (!buffer->vk_command_buffer) + if (!buffer->vk_command_buffer && !signal_semaphore_count + && !wait_semaphore_count && !context_vk->wait_semaphore_count) return;
- TRACE("Submitting command buffer %p with id 0x%s.\n", - buffer->vk_command_buffer, wine_dbgstr_longlong(buffer->id)); + if (buffer->vk_command_buffer) + { + TRACE("Submitting command buffer %p with id 0x%s.\n", + buffer->vk_command_buffer, wine_dbgstr_longlong(buffer->id));
- wined3d_context_vk_end_current_render_pass(context_vk); + wined3d_context_vk_end_current_render_pass(context_vk);
- LIST_FOR_EACH_ENTRY_SAFE(pool_vk, pool_vk_next, &context_vk->completed_query_pools, - struct wined3d_query_pool_vk, completed_entry) - { - list_remove(&pool_vk->completed_entry); - list_init(&pool_vk->completed_entry); + LIST_FOR_EACH_ENTRY_SAFE(pool_vk, pool_vk_next, &context_vk->completed_query_pools, + struct wined3d_query_pool_vk, completed_entry) + { + list_remove(&pool_vk->completed_entry); + list_init(&pool_vk->completed_entry);
- wined3d_context_vk_reset_completed_queries(context_vk, pool_vk, buffer); - } + wined3d_context_vk_reset_completed_queries(context_vk, pool_vk, buffer); + }
- LIST_FOR_EACH_ENTRY(query_vk, &context_vk->active_queries, struct wined3d_query_vk, entry) - wined3d_query_vk_suspend(query_vk, context_vk); - - context_vk->graphics.vk_pipeline = VK_NULL_HANDLE; - context_vk->update_compute_pipeline = 1; - context_vk->update_stream_output = 1; - context_vk->c.update_shader_resource_bindings = 1; - context_vk->c.update_compute_shader_resource_bindings = 1; - context_vk->c.update_unordered_access_view_bindings = 1; - context_vk->c.update_compute_unordered_access_view_bindings = 1; - context_vk->c.update_primitive_type = 1; - context_vk->c.update_patch_vertex_count = 1; - context_vk->c.update_multisample_state = 1; - context_invalidate_state(&context_vk->c, STATE_STREAMSRC); - context_invalidate_state(&context_vk->c, STATE_INDEXBUFFER); - context_invalidate_state(&context_vk->c, STATE_BLEND); - context_invalidate_state(&context_vk->c, STATE_BLEND_FACTOR); - context_invalidate_state(&context_vk->c, STATE_DEPTH_STENCIL); - context_invalidate_state(&context_vk->c, STATE_RASTERIZER); - context_invalidate_state(&context_vk->c, STATE_STENCIL_REF); - context_invalidate_state(&context_vk->c, STATE_VIEWPORT); - context_invalidate_state(&context_vk->c, STATE_SCISSORRECT); - - VK_CALL(vkEndCommandBuffer(buffer->vk_command_buffer)); - - VK_CALL(vkResetFences(device_vk->vk_device, 1, &buffer->vk_fence)); + LIST_FOR_EACH_ENTRY(query_vk, &context_vk->active_queries, struct wined3d_query_vk, entry) + wined3d_query_vk_suspend(query_vk, context_vk); + + context_vk->graphics.vk_pipeline = VK_NULL_HANDLE; + context_vk->update_compute_pipeline = 1; + context_vk->update_stream_output = 1; + context_vk->c.update_shader_resource_bindings = 1; + context_vk->c.update_compute_shader_resource_bindings = 1; + context_vk->c.update_unordered_access_view_bindings = 1; + context_vk->c.update_compute_unordered_access_view_bindings = 1; + context_vk->c.update_primitive_type = 1; + context_vk->c.update_patch_vertex_count = 1; + context_vk->c.update_multisample_state = 1; + context_invalidate_state(&context_vk->c, STATE_STREAMSRC); + context_invalidate_state(&context_vk->c, STATE_INDEXBUFFER); + context_invalidate_state(&context_vk->c, STATE_BLEND); + context_invalidate_state(&context_vk->c, STATE_BLEND_FACTOR); + context_invalidate_state(&context_vk->c, STATE_DEPTH_STENCIL); + context_invalidate_state(&context_vk->c, STATE_RASTERIZER); + context_invalidate_state(&context_vk->c, STATE_STENCIL_REF); + context_invalidate_state(&context_vk->c, STATE_VIEWPORT); + context_invalidate_state(&context_vk->c, STATE_SCISSORRECT); + + VK_CALL(vkEndCommandBuffer(buffer->vk_command_buffer)); + + VK_CALL(vkResetFences(device_vk->vk_device, 1, &buffer->vk_fence)); + }
if (wait_semaphore_count) { @@ -2120,26 +2124,31 @@ void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context context_vk->wait_semaphore_count += wait_semaphore_count; }
- submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.pNext = NULL; submit_info.waitSemaphoreCount = context_vk->wait_semaphore_count; submit_info.pWaitSemaphores = context_vk->wait_semaphores; submit_info.pWaitDstStageMask = context_vk->wait_stages; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &buffer->vk_command_buffer; + if (buffer->vk_command_buffer) + { + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &buffer->vk_command_buffer; + } submit_info.signalSemaphoreCount = signal_semaphore_count; submit_info.pSignalSemaphores = signal_semaphores;
- if ((vr = VK_CALL(vkQueueSubmit(device_vk->graphics_queue.vk_queue, 1, &submit_info, buffer->vk_fence))) < 0) + if ((vr = VK_CALL(vkQueueSubmit(device_vk->graphics_queue.vk_queue, 1, &submit_info, + buffer->vk_command_buffer ? buffer->vk_fence : VK_NULL_HANDLE))) < 0) ERR("Failed to submit command buffer %p, vr %s.\n", buffer->vk_command_buffer, wined3d_debug_vkresult(vr));
+ context_vk->wait_semaphore_count = 0; + + if (!buffer->vk_command_buffer) + return; + if (!wined3d_array_reserve((void **)&context_vk->submitted.buffers, &context_vk->submitted.buffers_size, context_vk->submitted.buffer_count + 1, sizeof(*context_vk->submitted.buffers))) ERR("Failed to grow submitted command buffer array.\n");
- context_vk->wait_semaphore_count = 0; - context_vk->submitted.buffers[context_vk->submitted.buffer_count++] = *buffer;
buffer->vk_command_buffer = VK_NULL_HANDLE;
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/wined3d/context_vk.c | 4 ++-- dlls/wined3d/device.c | 2 +- dlls/wined3d/texture.c | 6 +++--- dlls/wined3d/wined3d_vk.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index 5d2c9cd0a3f..645f65fed64 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -610,7 +610,7 @@ BOOL wined3d_context_vk_create_bo(struct wined3d_context_vk *context_vk, VkDevic BOOL wined3d_context_vk_create_image(struct wined3d_context_vk *context_vk, VkImageType vk_image_type, VkImageUsageFlags usage, VkFormat vk_format, unsigned int width, unsigned int height, unsigned int depth, unsigned int sample_count, unsigned int mip_levels, unsigned int layer_count, unsigned int flags, - struct wined3d_image_vk *image) + const void *next, struct wined3d_image_vk *image) { struct wined3d_adapter_vk *adapter_vk = wined3d_adapter_vk(context_vk->c.device->adapter); struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); @@ -621,7 +621,7 @@ BOOL wined3d_context_vk_create_image(struct wined3d_context_vk *context_vk, VkIm VkResult vr;
create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - create_info.pNext = NULL; + create_info.pNext = next; create_info.flags = flags; create_info.imageType = vk_image_type; create_info.format = vk_format; diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 02836acb861..a5b3c246485 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -806,7 +806,7 @@ static bool wined3d_null_image_vk_init(struct wined3d_image_vk *image, struct wi
if (!wined3d_context_vk_create_image(context_vk, type, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_FORMAT_R8G8B8A8_UNORM, - 1, 1, 1, sample_count, 1, layer_count, flags, image)) + 1, 1, 1, sample_count, 1, layer_count, flags, NULL, image)) { return false; } diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 1dbb02b2428..178b37fadc8 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -5437,7 +5437,7 @@ BOOL wined3d_texture_vk_prepare_texture(struct wined3d_texture_vk *texture_vk,
if (!wined3d_context_vk_create_image(context_vk, vk_image_type, vk_usage, format_vk->vk_format, resource->width, resource->height, resource->depth, max(1, wined3d_resource_get_sample_count(resource)), - texture_vk->t.level_count, texture_vk->t.layer_count, flags, &texture_vk->image)) + texture_vk->t.level_count, texture_vk->t.layer_count, flags, NULL, &texture_vk->image)) { return FALSE; } @@ -6956,7 +6956,7 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
if (!wined3d_context_vk_create_image(context_vk, vk_image_type, usage, vk_format, resolve_region.extent.width, resolve_region.extent.height, 1, - src_sample_count, 1, 1, 0, &src_image)) + src_sample_count, 1, 1, 0, NULL, &src_image)) goto barrier_next;
wined3d_context_vk_reference_image(context_vk, &src_image); @@ -7025,7 +7025,7 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
if (!wined3d_context_vk_create_image(context_vk, vk_image_type, usage, vk_format, resolve_region.extent.width, resolve_region.extent.height, 1, - VK_SAMPLE_COUNT_1_BIT, 1, 1, 0, &dst_image)) + VK_SAMPLE_COUNT_1_BIT, 1, 1, 0, NULL, &dst_image)) goto barrier_next;
wined3d_context_vk_reference_image(context_vk, &dst_image); diff --git a/dlls/wined3d/wined3d_vk.h b/dlls/wined3d/wined3d_vk.h index c3317ea6ce1..5e033e2d824 100644 --- a/dlls/wined3d/wined3d_vk.h +++ b/dlls/wined3d/wined3d_vk.h @@ -737,7 +737,7 @@ BOOL wined3d_context_vk_create_bo(struct wined3d_context_vk *context_vk, VkDevic BOOL wined3d_context_vk_create_image(struct wined3d_context_vk *context_vk, VkImageType vk_image_type, VkImageUsageFlags usage, VkFormat vk_format, unsigned int width, unsigned int height, unsigned int depth, unsigned int sample_count, unsigned int mip_levels, unsigned int layer_count, unsigned int flags, - struct wined3d_image_vk *image); + const void *next, struct wined3d_image_vk *image); void wined3d_context_vk_destroy_allocator_block(struct wined3d_context_vk *context_vk, struct wined3d_allocator_block *block, uint64_t command_buffer_id); void wined3d_context_vk_destroy_bo(struct wined3d_context_vk *context_vk,
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/wined3d/context_vk.c | 30 ++ dlls/wined3d/decoder.c | 663 +++++++++++++++++++++++++++++++++++++- dlls/wined3d/wined3d_vk.h | 11 + 3 files changed, 701 insertions(+), 3 deletions(-)
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index 645f65fed64..7fea48d83d2 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -1118,6 +1118,31 @@ void wined3d_context_vk_destroy_vk_video_session(struct wined3d_context_vk *cont o->command_buffer_id = command_buffer_id; }
+void wined3d_context_vk_destroy_vk_video_parameters(struct wined3d_context_vk *context_vk, + VkVideoSessionParametersKHR vk_video_parameters, uint64_t command_buffer_id) +{ + struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + struct wined3d_retired_object_vk *o; + + if (context_vk->completed_command_buffer_id >= command_buffer_id) + { + VK_CALL(vkDestroyVideoSessionParametersKHR(device_vk->vk_device, vk_video_parameters, NULL)); + TRACE("Destroyed video parameters 0x%s.\n", wine_dbgstr_longlong(vk_video_parameters)); + return; + } + + if (!(o = wined3d_context_vk_get_retired_object_vk(context_vk))) + { + ERR("Leaking video parameters 0x%s.\n", wine_dbgstr_longlong(vk_video_parameters)); + return; + } + + o->type = WINED3D_RETIRED_VIDEO_PARAMETERS_VK; + o->u.vk_video_parameters = vk_video_parameters; + o->command_buffer_id = command_buffer_id; +} + void wined3d_context_vk_destroy_image(struct wined3d_context_vk *context_vk, struct wined3d_image_vk *image) { wined3d_context_vk_destroy_vk_image(context_vk, image->vk_image, image->command_buffer_id); @@ -1421,6 +1446,11 @@ static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *cont TRACE("Destroyed video session 0x%s.\n", wine_dbgstr_longlong(o->u.vk_video_session)); break;
+ case WINED3D_RETIRED_VIDEO_PARAMETERS_VK: + VK_CALL(vkDestroyVideoSessionParametersKHR(device_vk->vk_device, o->u.vk_video_parameters, NULL)); + TRACE("Destroyed video parameters 0x%s.\n", wine_dbgstr_longlong(o->u.vk_video_parameters)); + break; + case WINED3D_RETIRED_AUX_COMMAND_BUFFER_VK: wined3d_aux_command_pool_vk_complete_buffer(context_vk, o->u.aux_command_buffer.pool, &o->u.aux_command_buffer.buffer); diff --git a/dlls/wined3d/decoder.c b/dlls/wined3d/decoder.c index 5a4fd33b65c..f204c354bd4 100644 --- a/dlls/wined3d/decoder.c +++ b/dlls/wined3d/decoder.c @@ -152,6 +152,9 @@ const struct wined3d_decoder_ops wined3d_null_decoder_ops = .get_profiles = wined3d_null_decoder_get_profiles, };
+/* DXVA_PicParams_H264 only allows for 16 reference frames. */ +#define MAX_VK_DECODE_REFERENCE_SLOTS 16 + struct wined3d_decoder_vk { struct wined3d_decoder d; @@ -160,8 +163,22 @@ struct wined3d_decoder_vk struct wined3d_allocator_block *session_memory; VkDeviceMemory vk_session_memory;
+ bool distinct_dpb; + + bool initialized; + bool needs_wait_semaphore; struct wined3d_aux_command_buffer_vk command_buffer; + + VkDeviceSize bitstream_alignment; + + struct wined3d_decoder_image_vk + { + uint8_t dxva_index; + bool used; + struct wined3d_image_vk output_image, dpb_image; + VkImageView output_view, dpb_view; + } images[MAX_VK_DECODE_REFERENCE_SLOTS + 1]; };
static struct wined3d_decoder_vk *wined3d_decoder_vk(struct wined3d_decoder *decoder) @@ -276,6 +293,22 @@ static void wined3d_decoder_vk_destroy_object(void *object) else VK_CALL(vkFreeMemory(device_vk->vk_device, decoder_vk->vk_session_memory, NULL));
+ for (unsigned int i = 0; i < ARRAY_SIZE(decoder_vk->images); ++i) + { + struct wined3d_decoder_image_vk *image = &decoder_vk->images[i]; + + if (image->output_image.vk_image) + { + wined3d_context_vk_destroy_image(context_vk, &image->output_image); + wined3d_context_vk_destroy_vk_image_view(context_vk, image->output_view, decoder_vk->command_buffer_id); + } + if (decoder_vk->distinct_dpb && image->dpb_image.vk_image) + { + wined3d_context_vk_destroy_image(context_vk, &image->dpb_image); + wined3d_context_vk_destroy_vk_image_view(context_vk, image->dpb_view, decoder_vk->command_buffer_id); + } + } + wined3d_context_vk_destroy_vk_video_session(context_vk, decoder_vk->vk_session, decoder_vk->command_buffer_id);
free(decoder_vk); @@ -289,6 +322,58 @@ static void wined3d_decoder_vk_destroy(struct wined3d_decoder *decoder) wined3d_cs_destroy_object(decoder->device->cs, wined3d_decoder_vk_destroy_object, decoder_vk); }
+static bool wined3d_decoder_vk_create_image(struct wined3d_decoder_vk *decoder_vk, + struct wined3d_context_vk *context_vk, VkImageUsageFlags usage, VkImageLayout layout, + struct wined3d_image_vk *image, VkImageView *view) +{ + const struct wined3d_format *output_format = wined3d_get_format( + decoder_vk->d.device->adapter, decoder_vk->d.desc.output_format, 0); + VkVideoProfileListInfoKHR profile_list = {.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR}; + VkImageViewCreateInfo view_desc = {.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + VkVideoProfileInfoKHR profile = {.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR}; + struct wined3d_device_vk *device_vk = wined3d_device_vk(decoder_vk->d.device); + VkFormat vk_format = wined3d_format_vk(output_format)->vk_format; + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + VkImageSubresourceRange vk_range = {0}; + VkResult vr; + + if (!decoder_vk->distinct_dpb) + usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR; + + profile_list.profileCount = 1; + profile_list.pProfiles = &profile; + fill_vk_profile_info(&profile, &decoder_vk->d.desc.codec, decoder_vk->d.desc.output_format); + + if (!wined3d_context_vk_create_image(context_vk, VK_IMAGE_TYPE_2D, usage, vk_format, + decoder_vk->d.desc.width, decoder_vk->d.desc.height, 1, 1, 1, 1, 0, &profile_list, image)) + { + ERR("Failed to create output image.\n"); + return false; + } + + vk_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + vk_range.levelCount = 1; + vk_range.layerCount = 1; + + wined3d_context_vk_image_barrier(context_vk, decoder_vk->command_buffer.vk_command_buffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, + VK_IMAGE_LAYOUT_UNDEFINED, layout, image->vk_image, &vk_range); + + view_desc.image = image->vk_image; + view_desc.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_desc.format = vk_format; + view_desc.subresourceRange = vk_range; + + if ((vr = VK_CALL(vkCreateImageView(device_vk->vk_device, &view_desc, NULL, view)))) + { + ERR("Failed to create image view, vr %s.\n", wined3d_debug_vkresult(vr)); + wined3d_context_vk_destroy_image(context_vk, image); + return false; + } + + return true; +} + static void bind_video_session_memory(struct wined3d_decoder_vk *decoder_vk) { struct wined3d_adapter_vk *adapter_vk = wined3d_adapter_vk(decoder_vk->d.device->adapter); @@ -401,6 +486,9 @@ static void wined3d_decoder_vk_cs_init(void *object) session_desc.maxDpbSlots = caps.maxDpbSlots; session_desc.maxActiveReferencePictures = caps.maxActiveReferencePictures; session_desc.pStdHeaderVersion = &caps.stdHeaderVersion; + + if (decode_caps.flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR) + decoder_vk->distinct_dpb = true; } else { @@ -417,6 +505,8 @@ static void wined3d_decoder_vk_cs_init(void *object)
TRACE("Created video session 0x%s.\n", wine_dbgstr_longlong(decoder_vk->vk_session));
+ decoder_vk->bitstream_alignment = caps.minBitstreamBufferSizeAlignment; + bind_video_session_memory(decoder_vk); }
@@ -527,19 +617,586 @@ static void submit_decode_command_buffer(struct wined3d_decoder_vk *decoder_vk, &decoder_vk->command_buffer, context_vk->current_command_buffer.id); }
+static void wined3d_decoder_vk_initialize(struct wined3d_decoder_vk *decoder_vk, + const struct wined3d_vk_info *vk_info) +{ + static const VkVideoCodingControlInfoKHR control_info = + { + .sType = VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR, + .flags = VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR, + }; + + VK_CALL(vkCmdControlVideoCodingKHR(decoder_vk->command_buffer.vk_command_buffer, &control_info)); + + decoder_vk->initialized = true; +} + +static StdVideoH264LevelIdc get_vk_h264_level(unsigned int mb_count) +{ + static const struct + { + StdVideoH264LevelIdc level; + unsigned int max_mb_count; + } + levels[] = + { + {STD_VIDEO_H264_LEVEL_IDC_6_0, 696320}, + {STD_VIDEO_H264_LEVEL_IDC_5_1, 184320}, + {STD_VIDEO_H264_LEVEL_IDC_5_0, 110400}, + {STD_VIDEO_H264_LEVEL_IDC_4_2, 34816}, + {STD_VIDEO_H264_LEVEL_IDC_4_0, 32768}, + {STD_VIDEO_H264_LEVEL_IDC_3_2, 20480}, + {STD_VIDEO_H264_LEVEL_IDC_3_1, 18000}, + {STD_VIDEO_H264_LEVEL_IDC_2_2, 8100}, + {STD_VIDEO_H264_LEVEL_IDC_2_1, 4752}, + {STD_VIDEO_H264_LEVEL_IDC_1_2, 2376}, + {STD_VIDEO_H264_LEVEL_IDC_1_1, 900}, + {STD_VIDEO_H264_LEVEL_IDC_1_0, 396}, + }; + + if (mb_count > levels[0].max_mb_count) + { + ERR("Macroblock count %u exceeds the limit for any known level!\n", mb_count); + return STD_VIDEO_H264_LEVEL_IDC_6_2; + } + + for (unsigned int i = 0; i < ARRAY_SIZE(levels) - 1; ++i) + { + if (mb_count > levels[i + 1].max_mb_count) + return levels[i].level; + } + return STD_VIDEO_H264_LEVEL_IDC_1_0; +} + +static VkVideoSessionParametersKHR create_h264_params(struct wined3d_decoder_vk *decoder_vk, + struct wined3d_context_vk *context_vk) +{ + VkVideoDecodeH264SessionParametersCreateInfoKHR h264_create_info = + {.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR}; + VkVideoDecodeH264SessionParametersAddInfoKHR h264_add_info = + {.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR}; + VkVideoSessionParametersCreateInfoKHR create_info = + {.sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR}; + struct wined3d_device_vk *device_vk = wined3d_device_vk(decoder_vk->d.device); + const struct wined3d_vk_info *vk_info = &device_vk->vk_info; + const DXVA_PicParams_H264 *h264_params; + StdVideoH264ScalingLists scaling_lists; + VkVideoSessionParametersKHR vk_params; + StdVideoH264SequenceParameterSet sps; + StdVideoH264PictureParameterSet pps; + const DXVA_Qmatrix_H264 *matrices; + VkResult vr; + + h264_params = wined3d_buffer_load_sysmem(decoder_vk->d.parameters, &context_vk->c); + matrices = wined3d_buffer_load_sysmem(decoder_vk->d.matrix, &context_vk->c); + + create_info.pNext = &h264_create_info; + create_info.videoSession = decoder_vk->vk_session; + + h264_create_info.maxStdPPSCount = 1; + h264_create_info.maxStdSPSCount = 1; + h264_create_info.pParametersAddInfo = &h264_add_info; + + h264_add_info.stdPPSCount = 1; + h264_add_info.pStdPPSs = &pps; + h264_add_info.stdSPSCount = 1; + h264_add_info.pStdSPSs = &sps; + + /* DXVA doesn't pass constraint set information. + * Since we don't know whether the frame conforms to any given constraint + * set, we must set all constraint set flags to zero. */ + sps.flags.constraint_set0_flag = 0; + sps.flags.constraint_set1_flag = 0; + sps.flags.constraint_set2_flag = 0; + sps.flags.constraint_set3_flag = 0; + /* Since we set the profile to High, constraint_set4_flag can be set if + * frame_mbs_only_flag is 1. */ + sps.flags.constraint_set4_flag = h264_params->frame_mbs_only_flag; + sps.flags.constraint_set5_flag = 0; + sps.flags.direct_8x8_inference_flag = h264_params->direct_8x8_inference_flag; + /* We don't have mb_adaptive_frame_field_flag, but we do have MbaffFrameFlag + * which is (mb_adaptive_frame_field_flag && !field_pic_flag). + * If field_pic_flag is 1, we don't know, so we set it to 1, which is the + * less constrained option. */ + if (!h264_params->field_pic_flag) + sps.flags.mb_adaptive_frame_field_flag = h264_params->MbaffFrameFlag; + else + sps.flags.mb_adaptive_frame_field_flag = 1; + sps.flags.frame_mbs_only_flag = h264_params->frame_mbs_only_flag; + sps.flags.delta_pic_order_always_zero_flag = h264_params->delta_pic_order_always_zero_flag; + /* separate_colour_plane_flag is only relevant to 4:4:4, and DXVA does not + * support 4:4:4. */ + sps.flags.separate_colour_plane_flag = 0; + /* We don't have this value, so we have to say it's allowed. */ + sps.flags.gaps_in_frame_num_value_allowed_flag = 1; + /* The High profile requires this value to be zero. */ + sps.flags.qpprime_y_zero_transform_bypass_flag = 0; + /* As far as I can tell, frame cropping is just something DXVA defers to + * the application. Report zero here. */ + sps.flags.frame_cropping_flag = 0; + /* FIXME: What on earth do we put here? */ + sps.flags.seq_scaling_matrix_present_flag = 0; + /* We don't have VUI parameters. They are not necessary to construct the + * actual output image, so reporting 0 here should be okay. */ + sps.flags.vui_parameters_present_flag = 0; + /* DXVA does not encode profiles. The specification does however state that + * all video must conform to the High profile. */ + sps.profile_idc = STD_VIDEO_H264_PROFILE_IDC_HIGH; + sps.level_idc = get_vk_h264_level((h264_params->wFrameWidthInMbsMinus1 + 1) + * (h264_params->wFrameHeightInMbsMinus1 + 1) * h264_params->num_ref_frames); + sps.chroma_format_idc = h264_params->chroma_format_idc; + /* As far as I can tell, the point here is that we can specify multiple + * SPS / PPS structures in a single frame and then specify which one we + * actually want to use when calling vkCmdDecodeVideoKHR(). + * This seems pointless when vkCmdDecodeVideoKHR() is only ever called + * once per frame anyway, and it's not clear that there's any reason to try + * to batch multiple decode calls per frame, especially when the DXVA API + * doesn't do this explicitly. + * Hence it doesn't matter what we set the ID to here as long as it's + * unique and we use the same ID later. */ + sps.seq_parameter_set_id = 0; + sps.bit_depth_luma_minus8 = h264_params->bit_depth_luma_minus8; + sps.bit_depth_chroma_minus8 = h264_params->bit_depth_chroma_minus8; + sps.log2_max_frame_num_minus4 = h264_params->log2_max_frame_num_minus4; + sps.pic_order_cnt_type = h264_params->pic_order_cnt_type; + /* FIXME: What on earth do we put here? + * Mesa source code suggests drivers don't care. */ + sps.offset_for_non_ref_pic = 0; + sps.offset_for_top_to_bottom_field = 0; + sps.log2_max_pic_order_cnt_lsb_minus4 = h264_params->log2_max_pic_order_cnt_lsb_minus4; + /* FIXME: What on earth do we put here? */ + sps.num_ref_frames_in_pic_order_cnt_cycle = 0; + /* This was renamed in the spec. */ + sps.max_num_ref_frames = h264_params->num_ref_frames; + sps.reserved1 = 0; + sps.pic_width_in_mbs_minus1 = h264_params->wFrameWidthInMbsMinus1; + if (h264_params->frame_mbs_only_flag) + sps.pic_height_in_map_units_minus1 = h264_params->wFrameHeightInMbsMinus1; + else + sps.pic_height_in_map_units_minus1 = ((h264_params->wFrameHeightInMbsMinus1 + 1) >> 1) - 1; + /* No frame cropping; see above. */ + sps.frame_crop_left_offset = 0; + sps.frame_crop_right_offset = 0; + sps.frame_crop_top_offset = 0; + sps.frame_crop_bottom_offset = 0; + sps.reserved2 = 0; + /* We're setting num_ref_frames_in_pic_order_cnt_cycle = 0, whether that's + * correct or not, so this array may as well be NULL. */ + sps.pOffsetForRefFrame = NULL; + /* No scaling lists; see above. */ + sps.pScalingLists = NULL; + /* No VUI; see above. */ + sps.pSequenceParameterSetVui = NULL; + + pps.flags.transform_8x8_mode_flag = h264_params->transform_8x8_mode_flag; + pps.flags.redundant_pic_cnt_present_flag = h264_params->redundant_pic_cnt_present_flag; + pps.flags.constrained_intra_pred_flag = h264_params->constrained_intra_pred_flag; + pps.flags.deblocking_filter_control_present_flag = h264_params->deblocking_filter_control_present_flag; + pps.flags.weighted_pred_flag = h264_params->weighted_pred_flag; + /* This was renamed in the spec. */ + pps.flags.bottom_field_pic_order_in_frame_present_flag = h264_params->pic_order_present_flag; + pps.flags.entropy_coding_mode_flag = h264_params->entropy_coding_mode_flag; + /* FIXME: What on earth do we put here? */ + pps.flags.pic_scaling_matrix_present_flag = 1; + /* See sps.seq_parameter_set_id. */ + pps.seq_parameter_set_id = 0; + pps.pic_parameter_set_id = 0; + /* This is an odd one. The Vulkan API doesn't seem to have a way to specify + * num_ref_idx_l*_active_minus1 or num_ref_idx_active_override_flag. + * GStreamer and ffmpeg both treat these two fields as being identical. */ + pps.num_ref_idx_l0_default_active_minus1 = h264_params->num_ref_idx_l0_active_minus1; + pps.num_ref_idx_l1_default_active_minus1 = h264_params->num_ref_idx_l1_active_minus1; + pps.weighted_bipred_idc = h264_params->weighted_bipred_idc; + pps.pic_init_qp_minus26 = h264_params->pic_init_qp_minus26; + pps.pic_init_qs_minus26 = h264_params->pic_init_qs_minus26; + pps.chroma_qp_index_offset = h264_params->chroma_qp_index_offset; + pps.second_chroma_qp_index_offset = h264_params->second_chroma_qp_index_offset; + /* No scaling lists; see above. */ + pps.pScalingLists = &scaling_lists; + + /* We supply all six 4x4 matrices, and the first two 8x8 matrices. */ + scaling_lists.scaling_list_present_mask = wined3d_mask_from_size(8); + /* FIXME: Should this be the inverse? The spec is hard to read. */ + scaling_lists.use_default_scaling_matrix_mask = 0; + memcpy(scaling_lists.ScalingList4x4, matrices->bScalingLists4x4, sizeof(matrices->bScalingLists4x4)); + memcpy(scaling_lists.ScalingList8x8, matrices->bScalingLists8x8, sizeof(matrices->bScalingLists8x8)); + + if ((vr = VK_CALL(vkCreateVideoSessionParametersKHR(device_vk->vk_device, + &create_info, NULL, &vk_params))) == VK_SUCCESS) + return vk_params; + ERR("Failed to create parameters, vr %d.\n", vr); + return VK_NULL_HANDLE; +} + +struct h264_reference_info +{ + VkVideoPictureResourceInfoKHR picture_info; + VkVideoDecodeH264DpbSlotInfoKHR h264_dpb_slot; + StdVideoDecodeH264ReferenceInfo h264_reference; +}; + +static void init_h264_reference_info(VkVideoReferenceSlotInfoKHR *reference_slot, + struct h264_reference_info *info, struct wined3d_decoder_vk *decoder_vk, unsigned int slot_index) +{ + reference_slot->sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR; + reference_slot->pNext = &info->h264_dpb_slot; + reference_slot->slotIndex = slot_index; + reference_slot->pPictureResource = &info->picture_info; + + info->picture_info.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR; + info->picture_info.codedExtent.width = decoder_vk->d.desc.width; + info->picture_info.codedExtent.height = decoder_vk->d.desc.height; + info->picture_info.baseArrayLayer = 0; + info->picture_info.imageViewBinding = decoder_vk->images[slot_index].dpb_view; + + info->h264_dpb_slot.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR; + info->h264_dpb_slot.pStdReferenceInfo = &info->h264_reference; +} + +static bool find_reference_slot(struct wined3d_decoder_vk *decoder_vk, + uint8_t dxva_index, unsigned int *vulkan_index) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(decoder_vk->images); ++i) + { + if (decoder_vk->images[i].dpb_view && decoder_vk->images[i].dxva_index == dxva_index) + { + *vulkan_index = i; + return true; + } + } + + ERR("Reference index %u was never written.\n", dxva_index); + return false; +} + +static bool find_unused_slot(struct wined3d_decoder_vk *decoder_vk, unsigned int *vulkan_index) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(decoder_vk->images); ++i) + { + if (!decoder_vk->images[i].used) + { + *vulkan_index = i; + return true; + } + } + + return false; +} + +static void wined3d_decoder_vk_blit_output(struct wined3d_decoder_vk *decoder_vk, struct wined3d_context_vk *context_vk, + struct wined3d_decoder_output_view_vk *output_view_vk, unsigned int slot_index) +{ + struct wined3d_texture_vk *texture_vk = wined3d_texture_vk(output_view_vk->v.texture); + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + VkCommandBuffer command_buffer; + VkImageCopy regions[2] = {0}; + VkImageLayout dst_layout; + VkImage src_image; + + command_buffer = wined3d_context_vk_get_command_buffer(context_vk); + + if (texture_vk->layout == VK_IMAGE_LAYOUT_GENERAL) + dst_layout = VK_IMAGE_LAYOUT_GENERAL; + else + dst_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + regions[0].srcSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT; + regions[0].srcSubresource.layerCount = 1; + regions[0].dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT; + regions[0].dstSubresource.baseArrayLayer = output_view_vk->v.desc.u.texture.layer_idx; + regions[0].dstSubresource.layerCount = 1; + regions[0].extent.width = texture_vk->t.resource.width; + regions[0].extent.height = texture_vk->t.resource.height; + regions[0].extent.depth = 1; + + regions[1] = regions[0]; + regions[1].srcSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT; + regions[1].dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT; + regions[1].extent.width /= 2; + regions[1].extent.height /= 2; + + src_image = decoder_vk->images[slot_index].output_image.vk_image; + + VK_CALL(vkCmdCopyImage(command_buffer, src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + texture_vk->image.vk_image, dst_layout, 2, regions)); +} + +static void wined3d_decoder_vk_decode_h264(struct wined3d_decoder_vk *decoder_vk, struct wined3d_context_vk *context_vk, + struct wined3d_decoder_output_view_vk *output_view_vk, VkVideoDecodeInfoKHR *decode_info, + const DXVA_PicParams_H264 *h264_params, const void *slice_control, unsigned int slice_control_size) +{ + VkVideoDecodeH264PictureInfoKHR vk_h264_picture = {.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_KHR}; + VkVideoReferenceSlotInfoKHR setup_reference_slot = {.sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR}; + VkVideoBeginCodingInfoKHR begin_info = {.sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR}; + VkVideoEndCodingInfoKHR end_info = {.sType = VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR}; + VkVideoReferenceSlotInfoKHR reference_slots[MAX_VK_DECODE_REFERENCE_SLOTS + 1] = {0}; + struct h264_reference_info references[MAX_VK_DECODE_REFERENCE_SLOTS] = {0}; + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + struct h264_reference_info setup_reference = {0}; + StdVideoDecodeH264ReferenceInfo *h264_reference; + StdVideoDecodeH264PictureInfo h264_picture; + struct wined3d_decoder_image_vk *image; + VkVideoSessionParametersKHR vk_params; + unsigned int slot_count = 0; + unsigned int slot_index; + uint32_t *slice_offsets; + size_t slice_count; + + if (decoder_vk->d.desc.long_slice_info) + { + const DXVA_Slice_H264_Long *slices = slice_control; + + slice_count = slice_control_size / sizeof(*slices); + if (!(slice_offsets = malloc(slice_count * sizeof(*slice_offsets)))) + return; + + for (size_t i = 0; i < slice_count; ++i) + slice_offsets[i] = slices[i].BSNALunitDataLocation; + } + else + { + const DXVA_Slice_H264_Short *slices = slice_control; + + slice_count = slice_control_size / sizeof(*slices); + if (!(slice_offsets = malloc(slice_count * sizeof(*slice_offsets)))) + return; + + for (size_t i = 0; i < slice_count; ++i) + slice_offsets[i] = slices[i].BSNALunitDataLocation; + } + + if (!(vk_params = create_h264_params(decoder_vk, context_vk))) + { + free(slice_offsets); + return; + } + + /* We cannot use the DXVA index or the frame number as an reference slot + * index. Vulkan requires that reference slot indices be less than the + * total number of reference images, and drivers impose a maximum of 16 + * reference images for H.264. However, the DXVA index and frame number may + * both exceed 16. + * + * Fortunately, DXVA specifies that references must be provided if they will + * be used for decoding this or any subsequent frames. That is, if an frame + * is not listed in the DXVA references, we can use it as the slot index for + * this output image. + * + * Therefore we mark all images as "unused" at the beginning of this + * function, then mark images as "used" when enumerating references. + * Afterward we pick the first unused slot, which will be used for this + * image. */ + for (unsigned int i = 0; i < ARRAY_SIZE(decoder_vk->images); ++i) + decoder_vk->images[i].used = false; + + begin_info.videoSession = decoder_vk->vk_session; + begin_info.videoSessionParameters = vk_params; + + TRACE("Decoding frame %02x/%02x, RefPicFlag %#x, reference frames", + h264_params->CurrPic.bPicEntry, h264_params->frame_num, h264_params->RefPicFlag); + + for (unsigned int i = 0; i < ARRAY_SIZE(h264_params->RefFrameList); ++i) + { + unsigned int field_flags = ((h264_params->UsedForReferenceFlags >> (2 * i)) & 3u); + + if (h264_params->RefFrameList[i].bPicEntry == 0xff) + continue; + + TRACE(" %02x/%02x", h264_params->RefFrameList[i].bPicEntry, h264_params->FrameNumList[i]); + + /* NVidia's DXVA implementation apparently expects each frame to appear + * in its own references list. Vulkan does not expect or need this. */ + if (h264_params->RefFrameList[i].Index7Bits == h264_params->CurrPic.Index7Bits) + continue; + + if (!find_reference_slot(decoder_vk, h264_params->RefFrameList[i].Index7Bits, &slot_index)) + goto out; + image = &decoder_vk->images[slot_index]; + + image->used = true; + + if (decoder_vk->distinct_dpb) + wined3d_context_vk_reference_image(context_vk, &image->dpb_image); + else + wined3d_context_vk_reference_image(context_vk, &image->output_image); + + init_h264_reference_info(&reference_slots[slot_count], &references[slot_count], decoder_vk, slot_index); + + h264_reference = &references[slot_count].h264_reference; + + /* If it's a frame reference, DXVA sets both flags, but Vulkan + * is supposed to set neither flag. */ + h264_reference->flags.top_field_flag = (field_flags == 1); + h264_reference->flags.bottom_field_flag = (field_flags == 2); + h264_reference->flags.used_for_long_term_reference = h264_params->RefFrameList[i].AssociatedFlag; + h264_reference->flags.is_non_existing = !!(h264_params->NonExistingFrameFlags & (1u << i)); + /* Vulkan is underspecified here; FrameNum is only defined for + * short-term references. Microsoft's DXVA H.264 specification actually + * says this is FrameNum *or* LongTermFrameIdx. + * GStreamer and ffmpeg seem to broadly agree that the Vulkan field is + * overloaded in the same way. + * [GStreamer however puts PicNum / LongTermPicNum here instead.] */ + h264_reference->FrameNum = h264_params->FrameNumList[i]; + h264_reference->PicOrderCnt[0] = h264_params->FieldOrderCntList[i][0]; + h264_reference->PicOrderCnt[1] = h264_params->FieldOrderCntList[i][1]; + + ++slot_count; + } + + TRACE(".\n"); + + /* Current decoding reference slot. */ + + if (!find_unused_slot(decoder_vk, &slot_index)) + { + ERR("No unused reference slot.\n"); + goto out; + } + image = &decoder_vk->images[slot_index]; + + image->dxva_index = h264_params->CurrPic.Index7Bits; + + if (!image->output_view) + { + VkImageUsageFlags usage = VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + if (!decoder_vk->distinct_dpb) + usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR; + + if (!wined3d_decoder_vk_create_image(decoder_vk, context_vk, usage, + VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR, &image->output_image, &image->output_view)) + goto out; + + if (decoder_vk->distinct_dpb) + { + if (!wined3d_decoder_vk_create_image(decoder_vk, context_vk, VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR, + VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR, &image->dpb_image, &image->dpb_view)) + goto out; + wined3d_context_vk_reference_image(context_vk, &image->dpb_image); + } + else + { + image->dpb_view = image->output_view; + } + } + wined3d_context_vk_reference_image(context_vk, &image->output_image); + + init_h264_reference_info(&setup_reference_slot, &setup_reference, decoder_vk, slot_index); + + h264_reference = &setup_reference.h264_reference; + /* FIXME: What on earth do we put here? For some reason DXVA supplies these + * flags for reference frames, but not for the current frame. + * Mesa source code suggests that drivers don't care about anything in + * pSetupReferenceSlot other than the slot index and image view, + * and in fact don't even need any of VkVideoBeginCodingInfoKHR at all + * for decoding, so just fill these as zero for now... */ + h264_reference->flags.top_field_flag = 0; + h264_reference->flags.bottom_field_flag = 0; + h264_reference->flags.used_for_long_term_reference = 0; + h264_reference->flags.is_non_existing = 0; + /* See above s.v. FrameNum. + * Yes, this information is duplicated. */ + h264_reference->FrameNum = h264_params->frame_num; + h264_reference->PicOrderCnt[0] = h264_params->CurrFieldOrderCnt[0]; + h264_reference->PicOrderCnt[1] = h264_params->CurrFieldOrderCnt[1]; + + /* We have to duplicate this information into the reference slot array + * for vkCmdBeginVideoCodingKHR, but marked as in inactive reference. */ + reference_slots[slot_count] = setup_reference_slot; + reference_slots[slot_count].slotIndex = -1; + + begin_info.referenceSlotCount = slot_count + 1; + begin_info.pReferenceSlots = reference_slots; + + vk_h264_picture.pStdPictureInfo = &h264_picture; + vk_h264_picture.sliceCount = slice_count; + vk_h264_picture.pSliceOffsets = slice_offsets; + + decode_info->pNext = &vk_h264_picture; + decode_info->pSetupReferenceSlot = &setup_reference_slot; + decode_info->pReferenceSlots = reference_slots; + decode_info->referenceSlotCount = slot_count; + decode_info->dstPictureResource.imageViewBinding = image->output_view; + + h264_picture.flags.field_pic_flag = h264_params->field_pic_flag; + /* ffmpeg treats these two as identical. */ + h264_picture.flags.is_intra = h264_params->IntraPicFlag; + /* FIXME: What on earth do we put here? + * Mesa source code suggests drivers don't care. */ + h264_picture.flags.IdrPicFlag = 0; + h264_picture.flags.bottom_field_flag = h264_params->CurrPic.AssociatedFlag; + /* This is not documented very well, but GStreamer and ffmpeg seem to agree + * that this is what this means. */ + h264_picture.flags.is_reference = h264_params->RefPicFlag; + /* FIXME: What on earth do we put here? + * Mesa source code suggests drivers don't care. */ + h264_picture.flags.complementary_field_pair = 0; + /* See above s.v. seq_parameter_set_id. */ + h264_picture.seq_parameter_set_id = 0; + h264_picture.pic_parameter_set_id = 0; + h264_picture.reserved1 = 0; + h264_picture.reserved2 = 0; + h264_picture.frame_num = h264_params->frame_num; + /* See above s.v. IdrPicFlag. */ + h264_picture.idr_pic_id = 0; + h264_picture.PicOrderCnt[0] = h264_params->CurrFieldOrderCnt[0]; + h264_picture.PicOrderCnt[1] = h264_params->CurrFieldOrderCnt[1]; + + VK_CALL(vkCmdBeginVideoCodingKHR(decoder_vk->command_buffer.vk_command_buffer, &begin_info)); + if (!decoder_vk->initialized) + wined3d_decoder_vk_initialize(decoder_vk, vk_info); + VK_CALL(vkCmdDecodeVideoKHR(decoder_vk->command_buffer.vk_command_buffer, decode_info)); + VK_CALL(vkCmdEndVideoCodingKHR(decoder_vk->command_buffer.vk_command_buffer, &end_info)); + + submit_decode_command_buffer(decoder_vk, context_vk); + + wined3d_decoder_vk_blit_output(decoder_vk, context_vk, output_view_vk, slot_index); + +out: + wined3d_context_vk_destroy_vk_video_parameters(context_vk, vk_params, context_vk->current_command_buffer.id); + free(slice_offsets); +} + static void wined3d_decoder_vk_decode(struct wined3d_context *context, struct wined3d_decoder *decoder, struct wined3d_decoder_output_view *output_view, unsigned int bitstream_size, unsigned int slice_control_size) { - struct wined3d_decoder_vk *decoder_vk = wined3d_decoder_vk(decoder); + struct wined3d_decoder_output_view_vk *output_view_vk = wined3d_decoder_output_view_vk(output_view); + VkVideoDecodeInfoKHR decode_info = {.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR}; + unsigned int sub_resource_idx = output_view_vk->v.desc.u.texture.layer_idx; struct wined3d_context_vk *context_vk = wined3d_context_vk(context); + struct wined3d_decoder_vk *decoder_vk = wined3d_decoder_vk(decoder); + struct wined3d_texture *texture = output_view_vk->v.texture; + const void *parameters, *slice_control; + struct wined3d_bo_vk *bitstream_bo; + + wined3d_buffer_load_location(decoder_vk->d.bitstream, &context_vk->c, WINED3D_LOCATION_BUFFER); + bitstream_bo = wined3d_bo_vk(decoder_vk->d.bitstream->buffer_object); + + parameters = wined3d_buffer_load_sysmem(decoder_vk->d.parameters, &context_vk->c); + slice_control = wined3d_buffer_load_sysmem(decoder_vk->d.slice_control, &context_vk->c); + + wined3d_texture_prepare_location(texture, sub_resource_idx, &context_vk->c, WINED3D_LOCATION_TEXTURE_RGB); + wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB); + wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
if (!get_decode_command_buffer(decoder_vk, context_vk, output_view)) return;
- FIXME("Not implemented.\n"); + decode_info.srcBuffer = bitstream_bo->vk_buffer; + decode_info.srcBufferOffset = bitstream_bo->b.buffer_offset; + decode_info.srcBufferRange = align(bitstream_size, decoder_vk->bitstream_alignment); + decode_info.dstPictureResource.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR; + decode_info.dstPictureResource.codedExtent.width = decoder_vk->d.desc.width; + decode_info.dstPictureResource.codedExtent.height = decoder_vk->d.desc.height; + decode_info.dstPictureResource.baseArrayLayer = 0;
- submit_decode_command_buffer(decoder_vk, context_vk); + wined3d_decoder_vk_decode_h264(decoder_vk, context_vk, output_view_vk, + &decode_info, parameters, slice_control, slice_control_size); + + wined3d_context_vk_reference_bo(context_vk, bitstream_bo); + wined3d_context_vk_reference_texture(context_vk, wined3d_texture_vk(texture)); + decoder_vk->command_buffer_id = context_vk->current_command_buffer.id; }
const struct wined3d_decoder_ops wined3d_decoder_vk_ops = diff --git a/dlls/wined3d/wined3d_vk.h b/dlls/wined3d/wined3d_vk.h index 5e033e2d824..db1dc17c62a 100644 --- a/dlls/wined3d/wined3d_vk.h +++ b/dlls/wined3d/wined3d_vk.h @@ -215,10 +215,17 @@ struct wined3d_device_vk; VK_DEVICE_PFN(vkDestroySwapchainKHR) \ VK_DEVICE_PFN(vkGetSwapchainImagesKHR) \ VK_DEVICE_PFN(vkQueuePresentKHR) \ + /* VK_KHR_video_decode_queue */ \ + VK_DEVICE_EXT_PFN(vkCmdDecodeVideoKHR) \ /* VK_KHR_video_queue */ \ VK_DEVICE_EXT_PFN(vkBindVideoSessionMemoryKHR) \ + VK_DEVICE_EXT_PFN(vkCmdBeginVideoCodingKHR) \ + VK_DEVICE_EXT_PFN(vkCmdControlVideoCodingKHR) \ + VK_DEVICE_EXT_PFN(vkCmdEndVideoCodingKHR) \ VK_DEVICE_EXT_PFN(vkCreateVideoSessionKHR) \ + VK_DEVICE_EXT_PFN(vkCreateVideoSessionParametersKHR) \ VK_DEVICE_EXT_PFN(vkDestroyVideoSessionKHR) \ + VK_DEVICE_EXT_PFN(vkDestroyVideoSessionParametersKHR) \ VK_DEVICE_EXT_PFN(vkGetVideoSessionMemoryRequirementsKHR)
#define DECLARE_VK_PFN(name) PFN_##name name; @@ -461,6 +468,7 @@ enum wined3d_retired_object_type_vk WINED3D_RETIRED_EVENT_VK, WINED3D_RETIRED_PIPELINE_VK, WINED3D_RETIRED_VIDEO_SESSION_VK, + WINED3D_RETIRED_VIDEO_PARAMETERS_VK, WINED3D_RETIRED_AUX_COMMAND_BUFFER_VK, };
@@ -487,6 +495,7 @@ struct wined3d_retired_object_vk VkEvent vk_event; VkPipeline vk_pipeline; VkVideoSessionKHR vk_video_session; + VkVideoSessionParametersKHR vk_video_parameters; struct { struct wined3d_query_pool_vk *pool_vk; @@ -760,6 +769,8 @@ void wined3d_context_vk_destroy_vk_event(struct wined3d_context_vk *context_vk, VkEvent vk_event, uint64_t command_buffer_id); void wined3d_context_vk_destroy_vk_pipeline(struct wined3d_context_vk *context_vk, VkPipeline vk_pipeline, uint64_t command_buffer_id); +void wined3d_context_vk_destroy_vk_video_parameters(struct wined3d_context_vk *context_vk, + VkVideoSessionParametersKHR vk_video_parameters, uint64_t command_buffer_id); void wined3d_context_vk_destroy_vk_video_session(struct wined3d_context_vk *context_vk, VkPipeline vk_video_session, uint64_t command_buffer_id); void wined3d_context_vk_end_current_render_pass(struct wined3d_context_vk *context_vk);
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/d3d11/tests/Makefile.in | 3 +- dlls/d3d11/tests/d3d11.c | 441 +++++++++++++++++++++++++++++++++++ dlls/d3d11/tests/h264_frame0 | Bin 0 -> 1016 bytes dlls/d3d11/tests/h264_frame1 | Bin 0 -> 461 bytes dlls/d3d11/tests/resource.rc | 30 +++ include/dxva.h | 19 ++ 6 files changed, 492 insertions(+), 1 deletion(-) create mode 100644 dlls/d3d11/tests/h264_frame0 create mode 100644 dlls/d3d11/tests/h264_frame1 create mode 100644 dlls/d3d11/tests/resource.rc
diff --git a/dlls/d3d11/tests/Makefile.in b/dlls/d3d11/tests/Makefile.in index fbae8aa09c6..e3a3de7f243 100644 --- a/dlls/d3d11/tests/Makefile.in +++ b/dlls/d3d11/tests/Makefile.in @@ -2,4 +2,5 @@ TESTDLL = d3d11.dll IMPORTS = d3d11 dxgi user32 gdi32 d3dcompiler
SOURCES = \ - d3d11.c + d3d11.c \ + resource.rc diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index 8bd3fcb922c..56ca5cca394 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -28,6 +28,7 @@ #include "initguid.h" #include "d3d11_4.h" #include "d3dcompiler.h" +#include "dxva.h" #include "winternl.h" #include "wine/wined3d.h" #include "wine/test.h" @@ -36798,6 +36799,445 @@ fail_match: release_test_context(&test_context); }
+struct yuv +{ + uint8_t y, u, v; +}; + +static void get_readback_nv12(struct resource_readback *rb, unsigned int x, unsigned int y, struct yuv *colour) +{ + colour->y = get_readback_u8(rb, x, y, 0); + colour->u = get_readback_u8(rb, x & ~1, rb->height + y / 2, 0); + colour->v = get_readback_u8(rb, (x & ~1) + 1, rb->height + y / 2, 0); +} + +static void test_h264_decoder(void) +{ + D3D11_VIDEO_DECODER_BUFFER_DESC buffers[4] = {{0}}; + ID3D11Texture2D *output_texture, *readback_texture; + ID3D11VideoDecoderOutputView *output_views[17]; + unsigned int count, size, bitstream_size; + D3D11_VIDEO_DECODER_EXTENSION extension; + D3D11_VIDEO_DECODER_CONFIG config = {0}; + D3D11_TEXTURE2D_DESC texture_desc = {0}; + struct d3d11_test_context test_context; + DXVA_Slice_H264_Short *h264_slice; + ID3D11VideoContext *video_context; + DXVA_PicParams_H264 *h264_params; + ID3D11VideoDevice *video_device; + DXVA_Qmatrix_H264 *h264_matrix; + D3D11_VIDEO_DECODER_DESC desc; + DXVA_Status_H264 h264_status; + struct resource_readback rb; + ID3D11VideoDecoder *decoder; + void *bitstream, *buffer2; + struct yuv colour; + GUID profile; + HRESULT hr; + HRSRC rsrc; + + DXVA_PicParams_H264 h264_params_template = + { + .wFrameWidthInMbsMinus1 = 19, + .wFrameHeightInMbsMinus1 = 14, + .num_ref_frames = 4, + .chroma_format_idc = 1, + .RefPicFlag = 1, + .weighted_pred_flag = 1, + .weighted_bipred_idc = 2, + .MbsConsecutiveFlag = 1, + .frame_mbs_only_flag = 1, + .transform_8x8_mode_flag = 1, + .Reserved16Bits = 3, + .chroma_qp_index_offset = -2, + .second_chroma_qp_index_offset = -2, + .ContinuationFlag = 1, + .num_ref_idx_l0_active_minus1 = 2, + .log2_max_pic_order_cnt_lsb_minus4 = 2, + .direct_8x8_inference_flag = 1, + .entropy_coding_mode_flag = 1, + .deblocking_filter_control_present_flag = 1, + }; + + if (!init_test_context(&test_context, NULL)) + return; + + hr = ID3D11Device_QueryInterface(test_context.device, &IID_ID3D11VideoDevice, (void **)&video_device); + if (hr == E_NOINTERFACE) + { + skip("Failed to get ID3D11VideoDevice.\n"); + release_test_context(&test_context); + return; + } + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + count = ID3D11VideoDevice_GetVideoDecoderProfileCount(video_device); + for (unsigned int i = 0; i < count; ++i) + { + hr = ID3D11VideoDevice_GetVideoDecoderProfile(video_device, i, &profile); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + /* Native seems to have an off-by-one error; trying to pass "count" + * as an index succeeds and leaves a garbage GUID in the output, which is + * not consistent across runs. */ + hr = ID3D11VideoDevice_GetVideoDecoderProfile(video_device, count + 1, &profile); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + + hr = ID3D11DeviceContext_QueryInterface(test_context.immediate_context, + &IID_ID3D11VideoContext, (void **)&video_context); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + desc.Guid = DXVA_ModeH264_VLD_NoFGT; + desc.SampleWidth = 320; + desc.SampleHeight = 240; + desc.OutputFormat = DXGI_FORMAT_NV12; + + hr = ID3D11VideoDevice_GetVideoDecoderConfigCount(video_device, &desc, &count); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr == S_OK) + ok(count >= 1, "Got no configs.\n"); + else + count = 0; + + for (unsigned int i = 0; i < count; ++i) + { + memset(&config, 0xcc, sizeof(config)); + hr = ID3D11VideoDevice_GetVideoDecoderConfig(video_device, &desc, 0, &config); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ok(IsEqualGUID(&config.guidConfigBitstreamEncryption, &DXVA_NoEncrypt), + "Got guidConfigBitstreamEncryption %s.\n", debugstr_guid(&config.guidConfigBitstreamEncryption)); + ok(IsEqualGUID(&config.guidConfigMBcontrolEncryption, &DXVA_NoEncrypt), + "Got guidConfigMBcontrolEncryption %s.\n", debugstr_guid(&config.guidConfigMBcontrolEncryption)); + ok(IsEqualGUID(&config.guidConfigResidDiffEncryption, &DXVA_NoEncrypt), + "Got guidConfigResidDiffEncryption %s.\n", debugstr_guid(&config.guidConfigResidDiffEncryption)); + /* NVidia sets 1, AMD sets 2. + * + * Nevertheless NVidia seems to be fine with short slice info. */ + ok(config.ConfigBitstreamRaw == 1 || config.ConfigBitstreamRaw == 2, + "Got ConfigBitstreamRaw %u.\n", config.ConfigBitstreamRaw); + ok(!config.ConfigMBcontrolRasterOrder, "Got ConfigMBcontrolRasterOrder %u.\n", + config.ConfigMBcontrolRasterOrder); + ok(!config.ConfigResidDiffHost, "Got ConfigResidDiffHost %u.\n", config.ConfigResidDiffHost); + ok(!config.ConfigSpatialResid8, "Got ConfigSpatialResid8 %u.\n", config.ConfigSpatialResid8); + ok(!config.ConfigResid8Subtraction, "Got ConfigResid8Subtraction %u.\n", config.ConfigResid8Subtraction); + ok(!config.ConfigSpatialHost8or9Clipping, "Got ConfigSpatialHost8or9Clipping %u.\n", + config.ConfigSpatialHost8or9Clipping); + ok(!config.ConfigSpatialResidInterleaved, "Got ConfigSpatialResidInterleaved %u.\n", + config.ConfigSpatialResidInterleaved); + ok(!config.ConfigIntraResidUnsigned, "Got ConfigIntraResidUnsigned %u.\n", config.ConfigIntraResidUnsigned); + ok(config.ConfigResidDiffAccelerator == 1, "Got ConfigResidDiffAccelerator %u.\n", + config.ConfigResidDiffAccelerator); + ok(config.ConfigHostInverseScan == 1, "Got ConfigHostInverseScan %u.\n", config.ConfigHostInverseScan); + ok(config.ConfigSpecificIDCT == 2, "Got ConfigSpecificIDCT %u.\n", config.ConfigSpecificIDCT); + ok(!config.Config4GroupedCoefs, "Got Config4GroupedCoefs %u.\n", config.Config4GroupedCoefs); + /* AMD has 0 for ConfigMinRenderTargetBuffCount; NVidia has 3. */ + /* AMD has 0x4000 for ConfigDecoderSpecific. + * This flag is an extension bit related to interleaved decoding. */ + ok(!config.ConfigDecoderSpecific || config.ConfigDecoderSpecific == 0x4000, + "Got ConfigDecoderSpecific %u.\n", config.ConfigDecoderSpecific); + } + + hr = ID3D11VideoDevice_GetVideoDecoderConfig(video_device, &desc, count, &config); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + + memset(&config, 0, sizeof(config)); + config.guidConfigBitstreamEncryption = DXVA_NoEncrypt; + config.guidConfigMBcontrolEncryption = DXVA_NoEncrypt; + config.guidConfigResidDiffEncryption = DXVA_NoEncrypt; + config.ConfigBitstreamRaw = 2; + config.ConfigResidDiffAccelerator = 1; + config.ConfigHostInverseScan = 1; + config.ConfigSpecificIDCT = 2; + config.ConfigMinRenderTargetBuffCount = 1; + + memset(&desc.Guid, 0xcc, sizeof(desc.Guid)); + hr = ID3D11VideoDevice_CreateVideoDecoder(video_device, &desc, &config, &decoder); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + + desc.Guid = DXVA_ModeH264_VLD_NoFGT; + hr = ID3D11VideoDevice_CreateVideoDecoder(video_device, &desc, &config, &decoder); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + texture_desc.Width = 320; + texture_desc.Height = 240; + texture_desc.MipLevels = 1; + texture_desc.ArraySize = ARRAY_SIZE(output_views); + texture_desc.Format = DXGI_FORMAT_NV12; + texture_desc.SampleDesc.Count = 1; + texture_desc.BindFlags = D3D11_BIND_DECODER; + texture_desc.Usage = D3D11_USAGE_DEFAULT; + hr = ID3D11Device_CreateTexture2D(test_context.device, &texture_desc, NULL, &output_texture); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + texture_desc.ArraySize = 1; + texture_desc.BindFlags = 0; + hr = ID3D11Device_CreateTexture2D(test_context.device, &texture_desc, NULL, &readback_texture); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + for (unsigned int i = 0; i < ARRAY_SIZE(output_views); ++i) + { + D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc = + { + .DecodeProfile = desc.Guid, + .ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D, + .Texture2D.ArraySlice = i, + }; + + view_desc.ViewDimension = D3D11_VDOV_DIMENSION_UNKNOWN; + hr = ID3D11VideoDevice_CreateVideoDecoderOutputView(video_device, + (ID3D11Resource *)output_texture, &view_desc, &output_views[i]); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + + view_desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D; + hr = ID3D11VideoDevice_CreateVideoDecoderOutputView(video_device, + (ID3D11Resource *)output_texture, &view_desc, &output_views[i]); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + + memset(&h264_status, 0xcc, sizeof(h264_status)); + memset(&extension, 0, sizeof(extension)); + extension.Function = DXVA_STATUS_REPORTING_FUNCTION; + 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); + if (hr == S_OK) + { + DXVA_Status_H264 zero_status = {0}; + + ok(!memcmp(&h264_status, &zero_status, sizeof(zero_status)), "Expected zeroed structure.\n"); + } + + hr = ID3D11VideoContext_DecoderBeginFrame(video_context, decoder, output_views[0], 0, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_GetDecoderBuffer(video_context, decoder, + D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS, &size, (void **)&h264_params); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(size >= sizeof(*h264_params), "Got size %u.\n", size); + + hr = ID3D11VideoContext_GetDecoderBuffer(video_context, decoder, + D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS, &size, &buffer2); + todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_ReleaseDecoderBuffer(video_context, + decoder, D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_ReleaseDecoderBuffer(video_context, + decoder, D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS); + todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_GetDecoderBuffer(video_context, decoder, + D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS, &size, &buffer2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(size >= sizeof(*h264_params), "Got size %u.\n", size); + ok(buffer2 == h264_params, "Buffer pointers didn't match.\n"); + + *h264_params = h264_params_template; + h264_params->CurrPic.Index7Bits = 0; + h264_params->IntraPicFlag = 1; + h264_params->StatusReportFeedbackNumber = 1; + for (unsigned int i = 0; i < 16; ++i) + h264_params->RefFrameList[i].bPicEntry = 0xff; + h264_params->CurrFieldOrderCnt[0] = 0; + h264_params->CurrFieldOrderCnt[1] = 0; + h264_params->frame_num = 0; + + hr = ID3D11VideoContext_ReleaseDecoderBuffer(video_context, + decoder, D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_GetDecoderBuffer(video_context, decoder, + D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX, &size, (void **)&h264_matrix); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(size >= sizeof(*h264_matrix), "Got size %u.\n", size); + + /* All scaling list fields are UCHARs; set them all to 16. */ + memset(h264_matrix, 16, sizeof(*h264_matrix)); + + hr = ID3D11VideoContext_ReleaseDecoderBuffer(video_context, + decoder, D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + rsrc = FindResourceW(NULL, L"h264_frame0", (const WCHAR *)RT_RCDATA); + ok(!!rsrc, "Failed to load resource, error %lu.\n", GetLastError()); + bitstream_size = SizeofResource(NULL, rsrc); + + hr = ID3D11VideoContext_GetDecoderBuffer(video_context, decoder, + D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL, &size, (void **)&h264_slice); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(size >= sizeof(*h264_slice) * 4, "Got size %u.\n", size); + + h264_slice[0].BSNALunitDataLocation = 0; + h264_slice[0].SliceBytesInBuffer = bitstream_size; + h264_slice[0].wBadSliceChopping = 0; + + hr = ID3D11VideoContext_ReleaseDecoderBuffer(video_context, + decoder, D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_GetDecoderBuffer(video_context, decoder, + D3D11_VIDEO_DECODER_BUFFER_BITSTREAM, &size, &bitstream); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(size >= bitstream_size, "Got size %u, expected at least %u.\n", size, bitstream_size); + + memcpy(bitstream, LockResource(LoadResource(GetModuleHandleW(NULL), rsrc)), bitstream_size); + + hr = ID3D11VideoContext_ReleaseDecoderBuffer(video_context, + decoder, D3D11_VIDEO_DECODER_BUFFER_BITSTREAM); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + buffers[0].BufferType = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS; + buffers[0].DataSize = sizeof(*h264_params); + buffers[1].BufferType = D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX; + buffers[1].DataSize = sizeof(*h264_matrix); + buffers[2].BufferType = D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL; + buffers[2].DataSize = sizeof(*h264_slice); + buffers[3].BufferType = D3D11_VIDEO_DECODER_BUFFER_BITSTREAM; + buffers[3].DataSize = bitstream_size; + hr = ID3D11VideoContext_SubmitDecoderBuffers(video_context, decoder, ARRAY_SIZE(buffers), buffers); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_DecoderEndFrame(video_context, decoder); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + /* Second frame. */ + + rsrc = FindResourceW(NULL, L"h264_frame1", (const WCHAR *)RT_RCDATA); + ok(!!rsrc, "Failed to load resource, error %lu.\n", GetLastError()); + bitstream_size = SizeofResource(NULL, rsrc); + + hr = ID3D11VideoContext_DecoderBeginFrame(video_context, decoder, output_views[1], 0, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_GetDecoderBuffer(video_context, decoder, + D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS, &size, (void **)&h264_matrix); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(size >= sizeof(*h264_matrix), "Got size %u.\n", size); + + *h264_params = h264_params_template; + h264_params->CurrPic.Index7Bits = 1; + h264_params->StatusReportFeedbackNumber = 2; + h264_params->RefFrameList[0].Index7Bits = 0; + h264_params->RefFrameList[0].AssociatedFlag = 0; + for (unsigned int i = 1; i < 16; ++i) + h264_params->RefFrameList[i].bPicEntry = 0xff; + h264_params->CurrFieldOrderCnt[0] = 2; + h264_params->CurrFieldOrderCnt[1] = 2; + h264_params->FieldOrderCntList[0][0] = 0; + h264_params->FieldOrderCntList[0][1] = 0; + h264_params->FrameNumList[0] = 0; + h264_params->UsedForReferenceFlags = 0x3; + h264_params->frame_num = 1; + + hr = ID3D11VideoContext_ReleaseDecoderBuffer(video_context, + decoder, D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_GetDecoderBuffer(video_context, decoder, + D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX, &size, (void **)&h264_matrix); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(size >= sizeof(*h264_matrix), "Got size %u.\n", size); + + /* All scaling list fields are UCHARs; set them all to 16. */ + memset(h264_matrix, 16, sizeof(*h264_matrix)); + + hr = ID3D11VideoContext_ReleaseDecoderBuffer(video_context, + decoder, D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_GetDecoderBuffer(video_context, decoder, + D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL, &size, (void **)&h264_slice); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(size >= sizeof(*h264_slice) * 4, "Got size %u.\n", size); + + h264_slice[0].BSNALunitDataLocation = 0; + h264_slice[0].SliceBytesInBuffer = bitstream_size; + h264_slice[0].wBadSliceChopping = 0; + + hr = ID3D11VideoContext_ReleaseDecoderBuffer(video_context, + decoder, D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_GetDecoderBuffer(video_context, decoder, + D3D11_VIDEO_DECODER_BUFFER_BITSTREAM, &size, &bitstream); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(size >= bitstream_size, "Got size %u, expected at least %u.\n", size, bitstream_size); + + memcpy(bitstream, LockResource(LoadResource(GetModuleHandleW(NULL), rsrc)), bitstream_size); + + hr = ID3D11VideoContext_ReleaseDecoderBuffer(video_context, + decoder, D3D11_VIDEO_DECODER_BUFFER_BITSTREAM); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + buffers[3].DataSize = bitstream_size; + hr = ID3D11VideoContext_SubmitDecoderBuffers(video_context, decoder, ARRAY_SIZE(buffers), buffers); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = ID3D11VideoContext_DecoderEndFrame(video_context, decoder); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + /* We cannot use get_texture_readback() directly. + * Direct3D11 seems to forbid CPU NV12 arrays. */ + ID3D11DeviceContext_CopySubresourceRegion(test_context.immediate_context, + (ID3D11Resource *)readback_texture, 0, 0, 0, 0, (ID3D11Resource *)output_texture, 0, NULL); + get_texture_readback(readback_texture, 0, &rb); + get_readback_nv12(&rb, 148, 109, &colour); + ok(colour.y == 49 && colour.u == 109 && colour.v == 184, + "Got (Y, U, V) values (%u, %u, %u).\n", colour.y, colour.u, colour.v); + get_readback_nv12(&rb, 176, 136, &colour); + ok(colour.y == 41 && colour.u == 240 && colour.v == 110, + "Got (Y, U, V) values (%u, %u, %u).\n", colour.y, colour.u, colour.v); + release_resource_readback(&rb); + + ID3D11DeviceContext_CopySubresourceRegion(test_context.immediate_context, + (ID3D11Resource *)readback_texture, 0, 0, 0, 0, (ID3D11Resource *)output_texture, 1, NULL); + get_texture_readback(readback_texture, 0, &rb); + get_readback_nv12(&rb, 148, 109, &colour); + ok(colour.y == 41 && colour.u == 240 && colour.v == 110, + "Got (Y, U, V) values (%u, %u, %u).\n", colour.y, colour.u, colour.v); + get_readback_nv12(&rb, 176, 136, &colour); + ok(colour.y == 49 && colour.u == 109 && colour.v == 184, + "Got (Y, U, V) values (%u, %u, %u).\n", colour.y, colour.u, colour.v); + release_resource_readback(&rb); + + /* The status query is asynchronous and does not wait for any frames to be + * completed. Call it after downloading the frames so we're sure that + * they're done. */ + + memset(&h264_status, 0xcc, sizeof(h264_status)); + memset(&extension, 0, sizeof(extension)); + extension.Function = DXVA_STATUS_REPORTING_FUNCTION; + 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. */ + } + + for (unsigned int i = 0; i < ARRAY_SIZE(output_views); ++i) + ID3D11VideoDecoderOutputView_Release(output_views[i]); + ID3D11Texture2D_Release(readback_texture); + ID3D11Texture2D_Release(output_texture); + ID3D11VideoDecoder_Release(decoder); + ID3D11VideoContext_Release(video_context); + ID3D11VideoDevice_Release(video_device); + release_test_context(&test_context); +} + START_TEST(d3d11) { unsigned int argc, i; @@ -37004,6 +37444,7 @@ START_TEST(d3d11) queue_test(test_stencil_export); queue_test(test_high_resource_count); queue_test(test_nv12); + queue_test(test_h264_decoder);
run_queued_tests();
diff --git a/dlls/d3d11/tests/h264_frame0 b/dlls/d3d11/tests/h264_frame0 new file mode 100644 index 0000000000000000000000000000000000000000..f3648472764b1bc4cf5f5250af3ecca5f6cf0d31 GIT binary patch literal 1016 zcmV<U0|)#700Cu)ga8`<{_cXl1vg*B55qk1`p_X<`09f6(BBo+{+rY;BN%byw*Us> zd+(~c`%O$W{{bcd00)pfBWm;i_&Ja8tYUWUQlx&q6e0Fj7b6hjdI*|U2j~32i?qI> zeRI7lcphyh7~L-aw3}ZsAN4-?>~+bu54J!=JJJZQ(HO?@@VPh{3I^JuwM_@Bu-H7O z4Qq4m1{|xMqs|K~3K<yX_A3^zL>|pBx&mMRr9`A!BW73t<#|Al;Fb4pL8WkCb3247 zcj|%1&F6Lf>T7?hnPyqcNgDBZNOH^sHmk${k!MJEt-`Sl#IjS5?7b>`6%l@gu4(w` ztTM{gjw;~9<s&_U$|FLk7_H&1a`?0@>`}65$gu|5i85}EQ(Sq}|3{Xgobc=bl&!sV zi%}o&g`<Lt?OO4^*2iY$M+iKZuc*%~)x|T%fkrrf2d?NhZh6WDxn#tiMQ{F|4?l#4 zdDkL}$wNP0Td9L;K;mGc&H9V)1f7r`85)=%3P{Z@*HXVc#z{@XScnh?Yi1V%5r#b6 zc(e~#lwo9Y&WvB=1zXSt9`u0b+jnC&BElR?XjkR6I1jEc$j+i3nrexF*?sS-Sh=hU z0G&=?<rrj|Jp1qTnag<p;f!$Nw1mfpw_GHtgE?)D(>TmOXl*fdFwy>0I*nl94_6B; z1J4NH#dRXA6v8?t47;uhe8S3O-cIWpo&%HD;bVO7ko8&+Z~YsC%R;w@U6MiqQSB@k zT_zak&nFL8*2|1nqk^ZI0>cYQhjb*SPcZP=O0+U$2#V>ipG#Q0vob8lDT4Vw=6Yt# z!hZb~?;K3}{77kwOM+ey2%wY-ZG+{w?Tzv2rF9s=_^wiX<&=8acd6$31=DO+p7axk zMrz!V<MgT}af>8P{n{2<hD!)02va~+Y2X<o*xw=7?_LP$Q{r7Cx)wgl%m`b97w;x2 z-+f=S1vKrZlXCR_?7?VUY!~Mw{k$tBwy5RHXW8OT7?<cLCH94dS17Qb<E^eae8vcJ zy}Xy8MXkTr>;JB3SAF>RNN8&?Iyl)d**!)sTfH$7k(-U6K!M20p&D%tf|#?=8(dLR zMKkN@`kx33obTq=TFyLC6~Mm*aG!TfA|p}>K3vE1*(suZz|bnZ2J5f{g5uIMS_^@% z8O-RN`0+0_{0{N}+3RtXxqX;xuP>vt-OTbH+RWs18F@MwMvk;Xu0oAg>GCBVN}4Hm zN34(X8AK=2fnOKVSSp&L>VL5|P5=GVeg8&pDKvhEOg(uw3Mf#A1=atHuM<h(i1ep7 mG%gP$;hYQKwG27+AZXax6i!(yA@T`%xfClt>AtHT{yKr%;Q9>!
literal 0 HcmV?d00001
diff --git a/dlls/d3d11/tests/h264_frame1 b/dlls/d3d11/tests/h264_frame1 new file mode 100644 index 0000000000000000000000000000000000000000..f20c8b8da2f35c2a1782d7aefe4233e7ac57eca6 GIT binary patch literal 461 zcmV;;0W$so00BXoA#6df{@SKk0GR(RhS7FdCwbZKnE#L+TX-e*8<zBK7zA7@FWPS3 zhqvg%A;vM*WKE2XPty+*PcZS!GV)7DcmK*WxaL9-Ke?;x*|J@H=+r1q=>Z!$pPNiO zDr4!Ajp&#(R)H#+%H1%y_=KVj#dVwwrz%)_9DaD}I+RXFEhakVUc&*J4JQ~hlDlu1 z@*}tqQM|<^3{iIBXoTrZ|9{tO_x7<{SOt52OMld7rY8grn1XKQ#ffmm;c^FV6wRhD z7p}fl@_}4ZsmYc^_uJ2Gg&1^*iKG0cIo3qd3wL4#VG`Xcx)tsJJTAFXH5xM6-z#X; zoJQA!t_t9z3_nX^hBI-XGU{O;aP22Pm!}Mn;BI^H`H;DM3}Y;|K#o4X8Sd`FmBydZ za!>=eX0{psutV{-YA;PjIRx9o-tzRB<@PsfYzXvVfJlLTje<^%^}M6^YE6n`;Ruxt zeK;>zw<j)v+Sv<q%~)ub;gKJ-+UP*=Bxu|#kz93?(N*jsM5)~U8}4NmRmyij)eRb2 z?;*m#so_BDNFlK!$(k5e2nzwU6n(WU$!=uX7Q%MY;-7VMs5VWa>*!aC+mk*!INO1s DOzq?f
literal 0 HcmV?d00001
diff --git a/dlls/d3d11/tests/resource.rc b/dlls/d3d11/tests/resource.rc new file mode 100644 index 00000000000..19ff889e1d9 --- /dev/null +++ b/dlls/d3d11/tests/resource.rc @@ -0,0 +1,30 @@ +/* + * Resource file for d3d11 tests. + * + * Copyright 2024 Elizabeth Figura for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "windef.h" + +/* First two frames of h264 data from the following test pipeline: + * + * gst-launch-1.0 videotestsrc num-buffers=2 pattern=ball background-color=0x000000ff foreground-color=0x007f0000 ! x264enc ! h264parse ! d3d11h264dec ! fakesink + */ +/* @makedep: h264_frame0 */ +h264_frame0 RCDATA h264_frame0 +/* @makedep: h264_frame1 */ +h264_frame1 RCDATA h264_frame1 diff --git a/include/dxva.h b/include/dxva.h index a566c672ae1..6bbf27f7238 100644 --- a/include/dxva.h +++ b/include/dxva.h @@ -110,6 +110,14 @@ DEFINE_GUID(DXVA_NoEncrypt, 0x1b81bed0, 0xa0c7,0x11d3, 0xb9,0x84,0x00,0xc0,0x4f, #define DXVA_USUAL_BLOCK_HEIGHT 8 #define DXVA_USUAL_BLOCK_SIZE (DXVA_USUAL_BLOCK_WIDTH * DXVA_USUAL_BLOCK_HEIGHT)
+#define DXVA_PICTURE_DECODING_FUNCTION 1 +#define DXVA_ALPHA_BLEND_DATA_LOAD_FUNCTION 2 +#define DXVA_ALPHA_BLEND_COMBINATION_FUNCTION 3 +#define DXVA_PICTURE_RESAMPLE_FUNCTION 4 +#define DXVA_DEBLOCKING_FILTER_FUNCTION 5 +#define DXVA_FILM_GRAIN_SYNTHESIS_FUNCTION 6 +#define DXVA_STATUS_REPORTING_FUNCTION 7 + #include <pshpack1.h>
typedef struct _DXVA_PicEntry_H264 @@ -316,6 +324,17 @@ typedef struct _DXVA_Slice_H264_Short USHORT wBadSliceChopping; } DXVA_Slice_H264_Short, *LPDXVA_Slice_H264_Short;
+typedef struct _DXVA_Status_H264 +{ + UINT StatusReportFeedbackNumber; + DXVA_PicEntry_H264 CurrPic; + UCHAR field_pic_flag; + UCHAR bDXVA_Func; + UCHAR bBufType; + UCHAR bStatus; + UCHAR bReserved8Bits; + USHORT wNumMbsAffected; +} DXVA_Status_H264, *LPDXVA_Status_H264;
typedef struct _DXVA_PicEntry_HEVC {
On my machine, D3D11 tests fail with `Assertion failed: iface->lpVtbl == &d3d11_video_decoder_vtbl, file /home/jan/work/wine/dlls/d3d11/decoder.c, line 217`