54 ID3D12Resource *resource =
NULL;
55 D3D12_HEAP_PROPERTIES props = { .Type = D3D12_HEAP_TYPE_DEFAULT };
56 D3D12_RESOURCE_DESC
desc;
58 if (reference_only_map ==
NULL) {
67 for (
i = 0;
i <
ctx->max_num_ref + 1;
i++) {
68 if (reference_only_map[
i].resource !=
NULL &&
69 reference_only_map[
i].output_resource == output_resource) {
70 reference_only_map[
i].
used = 1;
76 for (
i = 0;
i <
ctx->max_num_ref + 1;
i++) {
77 if (!reference_only_map[
i].used && reference_only_map[
i].resource !=
NULL) {
78 reference_only_map[
i].
used = 1;
79 resource = reference_only_map[
i].
resource;
86 for (
i = 0;
i <
ctx->max_num_ref + 1;
i++) {
87 if (reference_only_map[
i].resource ==
NULL)
91 if (
i ==
ctx->max_num_ref + 1) {
97 output_resource->lpVtbl->GetDesc(output_resource, &
desc);
98 desc.Flags = D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
100 if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->
device, &props, D3D12_HEAP_FLAG_NONE, &
desc,
101 D3D12_RESOURCE_STATE_COMMON,
NULL, &IID_ID3D12Resource, (
void **)&reference_only_map[
i].
resource))) {
106 reference_only_map[
i].
used = 1;
107 resource = reference_only_map[
i].
resource;
118 if (reference_only_map !=
NULL) {
119 for (
i = 0;
i <
ctx->max_num_ref + 1;
i++) {
120 if (reference_only_map[
i].resource !=
NULL) {
134 if (reference_only_map ==
NULL)
136 memset(
ctx->ref_only_resources, 0,
ctx->max_num_ref *
sizeof(*(
ctx->ref_only_resources)));
137 for (j = 0; j <
ctx->max_num_ref + 1; j++) {
138 for (
i = 0;
i <
ctx->max_num_ref;
i++) {
139 if (reference_only_map[j].used && reference_only_map[j].output_resource ==
ctx->ref_resources[
i]) {
140 ctx->ref_only_resources[
i] = reference_only_map[j].
resource;
144 if (
i ==
ctx->max_num_ref)
145 reference_only_map[j].
used = 0;
165 for (
i = 0;
i <
ctx->max_num_ref;
i++) {
166 if (
ctx->ref_resources[
i] && res ==
ctx->ref_resources[
i]) {
167 ctx->used_mask |= 1 <<
i;
173 for (
i = 0;
i <
ctx->max_num_ref;
i++) {
174 if (!((
ctx->used_mask >>
i) & 0x1)) {
175 ctx->ref_resources[
i] = res;
187 UINT64 bitstream_size)
191 D3D12_HEAP_PROPERTIES heap_props = { .Type = D3D12_HEAP_TYPE_UPLOAD };
193 D3D12_RESOURCE_DESC
desc;
199 (*ppBuffer)->lpVtbl->GetDesc(*ppBuffer, &
desc);
200 if (
desc.Width >= bitstream_size)
203 desc = (D3D12_RESOURCE_DESC) {
204 .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
205 .Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
207 .DepthOrArraySize = 1,
209 .Format = DXGI_FORMAT_UNKNOWN,
210 .SampleDesc = { .Count = 1, .Quality = 0 },
211 .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
212 .Flags = D3D12_RESOURCE_FLAG_NONE,
215 desc.Width = bitstream_size * 1.5;
217 hr = ID3D12Device_CreateCommittedResource(
ctx->device_ctx->device, &heap_props, D3D12_HEAP_FLAG_NONE,
218 &
desc, D3D12_RESOURCE_STATE_GENERIC_READ,
NULL,
219 &IID_ID3D12Resource, (
void **)&
buffer);
221 av_log(avctx,
AV_LOG_ERROR,
"Failed to create a new D3D12 bitstream buffer for uploading!\n");
232 ID3D12Resource **ppBuffer, UINT64 bitstream_size)
239 uint64_t completion = ID3D12Fence_GetCompletedValue(
ctx->sync_ctx.fence);
248 hr = ID3D12Device_CreateCommandAllocator(
ctx->device_ctx->device, D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE,
249 &IID_ID3D12CommandAllocator, (
void **)ppAllocator);
259 ID3D12Resource *pBuffer, uint64_t fence_value)
264 .command_allocator = pAllocator,
266 .fence_value = fence_value,
280 uint64_t completion = ID3D12Fence_GetCompletedValue(psync_ctx->
fence);
281 if (completion < psync_ctx->fence_value) {
282 if (FAILED(ID3D12Fence_SetEventOnCompletion(psync_ctx->
fence, psync_ctx->
fence_value, psync_ctx->
event)))
285 WaitForSingleObjectEx(psync_ctx->
event, INFINITE, FALSE);
305 DX_CHECK(ID3D12CommandQueue_Signal(
ctx->command_queue,
ctx->sync_ctx.fence, ++
ctx->sync_ctx.fence_value));
319 D3D12_VIDEO_DECODER_HEAP_DESC
desc = {
321 .Configuration =
ctx->cfg,
322 .DecodeWidth = frames_ctx->
width,
323 .DecodeHeight = frames_ctx->
height,
324 .Format = frames_hwctx->
format,
327 .MaxDecodePictureBufferCount =
ctx->max_num_ref,
331 &IID_ID3D12VideoDecoderHeap, (
void **)&
ctx->decoder_heap));
338 "[width(%d), height(%d)], on your device!\n", frames_ctx->
width, frames_ctx->
height);
346 D3D12_VIDEO_DECODER_DESC
desc;
352 D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT feature = {
354 .Configuration =
ctx->cfg,
355 .Width = frames_ctx->
width,
356 .Height = frames_ctx->
height,
357 .DecodeFormat = frames_hwctx->
format,
362 DX_CHECK(ID3D12VideoDevice_CheckFeatureSupport(device_hwctx->
video_device, D3D12_FEATURE_VIDEO_DECODE_SUPPORT,
363 &feature,
sizeof(feature)));
364 if (!(feature.SupportFlags & D3D12_VIDEO_DECODE_SUPPORT_FLAG_SUPPORTED)) {
368 if (!(feature.DecodeTier >= D3D12_VIDEO_DECODE_TIER_2)) {
369 av_log(avctx,
AV_LOG_ERROR,
"D3D12 video decode on this device requires tier %d support, "
370 "but it is not implemented.\n", feature.DecodeTier);
374 ctx->reference_only_map =
NULL;
375 ctx->ref_only_resources =
NULL;
376 if (feature.ConfigurationFlags & D3D12_VIDEO_DECODE_CONFIGURATION_FLAG_REFERENCE_ONLY_ALLOCATIONS_REQUIRED) {
377 av_log(avctx,
AV_LOG_VERBOSE,
"Reference-Only Allocations are required for this D3D12 decoder configuration.\n");
379 if (!
ctx->reference_only_map)
381 ctx->ref_only_resources =
av_calloc(
ctx->max_num_ref,
sizeof(*
ctx->ref_only_resources));
382 if (!
ctx->ref_only_resources)
386 desc = (D3D12_VIDEO_DECODER_DESC) {
388 .Configuration =
ctx->cfg,
392 (
void **)&
ctx->decoder));
395 if (!
ctx->decoder_ref)
426 ID3D12CommandAllocator *command_allocator =
NULL;
427 D3D12_COMMAND_QUEUE_DESC queue_desc = {
428 .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE,
430 .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
443 if (frames_ctx->
format !=
ctx->pix_fmt) {
457 if (!
ctx->ref_resources)
461 if (!
ctx->ref_subresources)
466 if (!
ctx->objects_queue)
469 DX_CHECK(ID3D12Device_CreateFence(
ctx->device_ctx->device, 0, D3D12_FENCE_FLAG_NONE,
470 &IID_ID3D12Fence, (
void **)&
ctx->sync_ctx.fence));
472 ctx->sync_ctx.event = CreateEvent(
NULL, FALSE, FALSE,
NULL);
473 if (!
ctx->sync_ctx.event)
480 DX_CHECK(ID3D12Device_CreateCommandQueue(
ctx->device_ctx->device, &queue_desc,
481 &IID_ID3D12CommandQueue, (
void **)&
ctx->command_queue));
483 DX_CHECK(ID3D12Device_CreateCommandList(
ctx->device_ctx->device, 0, queue_desc.Type,
484 command_allocator,
NULL, &IID_ID3D12CommandList, (
void **)&
ctx->command_list));
486 DX_CHECK(ID3D12VideoDecodeCommandList_Close(
ctx->command_list));
488 ID3D12CommandQueue_ExecuteCommandLists(
ctx->command_queue, 1, (ID3D12CommandList **)&
ctx->command_list);
510 int num_allocator = 0;
514 if (
ctx->sync_ctx.fence)
523 if (
ctx->objects_queue) {
530 av_log(avctx,
AV_LOG_VERBOSE,
"Total number of command allocators reused: %d\n", num_allocator);
537 if (
ctx->sync_ctx.event)
538 CloseHandle(
ctx->sync_ctx.event);
548 ID3D12Resource *current_resource,
int state_before,
int state_end)
551 ID3D12Resource **ref_resources =
ctx->ref_only_resources ?
ctx->ref_only_resources :
ctx->ref_resources;
554 for (
int i = 0;
i <
ctx->max_num_ref;
i++) {
555 if (((
ctx->used_mask >>
i) & 0x1) && ref_resources[
i] && ref_resources[
i] != current_resource) {
556 barriers[num_barrier].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
557 barriers[num_barrier].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
558 barriers[num_barrier].Transition = (D3D12_RESOURCE_TRANSITION_BARRIER) {
559 .pResource = ref_resources[
i],
560 .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
561 .StateBefore = state_before,
562 .StateAfter = state_end,
572 const void *pp,
unsigned pp_size,
573 const void *qm,
unsigned qm_size,
574 UINT64 bitstream_size,
580 ID3D12CommandAllocator *command_allocator =
NULL;
582 ID3D12Resource *output_resource = (ID3D12Resource*)
f->texture;
583 ID3D12Resource *ref_resource =
NULL;
585 ID3D12VideoDecodeCommandList *cmd_list =
ctx->command_list;
586 D3D12_RESOURCE_BARRIER barriers[32] = { 0 };
588 D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS input_args = {
589 .NumFrameArguments = 2,
592 .Type = D3D12_VIDEO_DECODE_ARGUMENT_TYPE_PICTURE_PARAMETERS,
597 .Type = D3D12_VIDEO_DECODE_ARGUMENT_TYPE_INVERSE_QUANTIZATION_MATRIX,
602 .pHeap =
ctx->decoder_heap,
605 D3D12_VIDEO_DECODE_OUTPUT_STREAM_ARGUMENTS output_args = {
606 .ConversionArguments = { 0 },
607 .OutputSubresource = 0,
608 .pOutputTexture2D = output_resource,
611 memset(
ctx->ref_subresources, 0,
sizeof(UINT) *
ctx->max_num_ref);
612 input_args.ReferenceFrames.NumTexture2Ds =
ctx->max_num_ref;
613 input_args.ReferenceFrames.pSubresources =
ctx->ref_subresources;
615 if (
ctx->reference_only_map) {
617 if (ref_resource ==
NULL) {
623 output_args.ConversionArguments.Enable = 1;
624 input_args.ReferenceFrames.ppTexture2Ds =
ctx->ref_only_resources;
625 output_args.ConversionArguments.pReferenceTexture2D = ref_resource;
626 output_args.ConversionArguments.ReferenceSubresource = 0;
628 ref_resource = output_resource;
629 input_args.ReferenceFrames.ppTexture2Ds =
ctx->ref_resources;
632 UINT num_barrier = 1;
633 barriers[0] = (D3D12_RESOURCE_BARRIER) {
634 .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
635 .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
637 .pResource = output_resource,
638 .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
639 .StateBefore = D3D12_RESOURCE_STATE_COMMON,
640 .StateAfter = D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE,
644 if (
ctx->reference_only_map) {
645 barriers[1] = (D3D12_RESOURCE_BARRIER) {
646 .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
647 .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
649 .pResource = ref_resource,
650 .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
651 .StateBefore = D3D12_RESOURCE_STATE_COMMON,
652 .StateAfter = D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE,
663 input_args.NumFrameArguments = 1;
673 DX_CHECK(ID3D12CommandAllocator_Reset(command_allocator));
675 DX_CHECK(ID3D12VideoDecodeCommandList_Reset(cmd_list, command_allocator));
679 ID3D12VideoDecodeCommandList_ResourceBarrier(cmd_list, num_barrier, barriers);
681 ID3D12VideoDecodeCommandList_DecodeFrame(cmd_list,
ctx->decoder, &output_args, &input_args);
683 for (
int i = 0;
i < num_barrier;
i++)
684 FFSWAP(D3D12_RESOURCE_STATES, barriers[
i].Transition.StateBefore, barriers[
i].Transition.StateAfter);
686 ID3D12VideoDecodeCommandList_ResourceBarrier(cmd_list, num_barrier, barriers);
688 DX_CHECK(ID3D12VideoDecodeCommandList_Close(cmd_list));
690 ID3D12CommandQueue_ExecuteCommandLists(
ctx->command_queue, 1, (ID3D12CommandList **)&
ctx->command_list);
692 DX_CHECK(ID3D12CommandQueue_Signal(
ctx->command_queue,
f->sync_ctx.fence, ++
f->sync_ctx.fence_value));
694 DX_CHECK(ID3D12CommandQueue_Signal(
ctx->command_queue,
ctx->sync_ctx.fence, ++
ctx->sync_ctx.fence_value));
703 if (command_allocator)
static AVFormatContext * ctx
Libavcodec external API header.
#define i(width, name, range_min, range_max)
common internal and external API header
static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
static void free_reference_only_resources(AVCodecContext *avctx)
av_cold int ff_d3d12va_decode_init(AVCodecContext *avctx)
init D3D12VADecodeContext
static int d3d12va_fence_completion(AVD3D12VASyncContext *psync_ctx)
static void prepare_reference_only_resources(AVCodecContext *avctx)
static int d3d12va_sync_with_gpu(AVCodecContext *avctx)
int ff_d3d12va_common_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
d3d12va common frame params
static int d3d12va_create_decoder_heap(AVCodecContext *avctx)
static int d3d12va_resize_bitstream_buffer(AVCodecContext *avctx, ID3D12Resource **ppBuffer, UINT64 bitstream_size)
static AVBufferRef * bufref_wrap_interface(IUnknown *iface)
static int d3d12va_get_valid_helper_objects(AVCodecContext *avctx, ID3D12CommandAllocator **ppAllocator, ID3D12Resource **ppBuffer, UINT64 bitstream_size)
int ff_d3d12va_common_end_frame(AVCodecContext *avctx, AVFrame *frame, const void *pp, unsigned pp_size, const void *qm, unsigned qm_size, UINT64 bitstream_size, int(*update_input_arguments)(AVCodecContext *, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *, ID3D12Resource *))
d3d12va common end frame
static ID3D12Resource * get_reference_only_resource(AVCodecContext *avctx, ID3D12Resource *output_resource)
av_cold int ff_d3d12va_decode_uninit(AVCodecContext *avctx)
uninit D3D12VADecodeContext
static int d3d12va_discard_helper_objects(AVCodecContext *avctx, ID3D12CommandAllocator *pAllocator, ID3D12Resource *pBuffer, uint64_t fence_value)
static int d3d12va_create_decoder(AVCodecContext *avctx)
unsigned ff_d3d12va_get_surface_index(const AVCodecContext *avctx, D3D12VADecodeContext *ctx, const AVFrame *frame, int curr)
static int d3d12va_update_reference_frames_state(AVCodecContext *avctx, D3D12_RESOURCE_BARRIER *barriers, ID3D12Resource *current_resource, int state_before, int state_end)
static void bufref_free_interface(void *opaque, uint8_t *data)
#define D3D12VA_VIDEO_DEC_ASYNC_DEPTH
#define D3D12VA_DECODE_CONTEXT(avctx)
#define D3D12VA_FRAMES_CONTEXT(avctx)
int ff_decode_get_hw_frames_ctx(AVCodecContext *avctx, enum AVHWDeviceType dev_type)
Make sure avctx.hw_frames_ctx is set.
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
AVBufferRef * av_buffer_create(uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
AVFifo * av_fifo_alloc2(size_t nb_elems, size_t elem_size, unsigned int flags)
Allocate and initialize an AVFifo with a given element size.
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
#define AV_FIFO_FLAG_AUTO_GROW
Automatically resize the FIFO on writes, so that the data fits.
int av_fifo_peek(const AVFifo *f, void *buf, size_t nb_elems, size_t offset)
Read data from a FIFO without modifying FIFO state.
int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
Write data into a FIFO.
int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems)
Read data from a FIFO.
#define AV_LOG_WARNING
Something somehow does not look correct.
#define AV_LOG_VERBOSE
Detailed information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
@ AV_HWDEVICE_TYPE_D3D12VA
An API-specific header for AV_HWDEVICE_TYPE_D3D12VA.
#define D3D12_OBJECT_RELEASE(pInterface)
A release macro used by D3D12 objects highly frequently.
#define DX_CHECK(hr)
A check macro used by D3D12 functions highly frequently.
#define FFSWAP(type, a, b)
void * av_calloc(size_t nmemb, size_t size)
Memory handling functions.
#define AV_PIX_FMT_YUV420P10
#define AV_PIX_FMT_YUV420P12
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
@ AV_PIX_FMT_D3D12
Hardware surfaces for Direct3D 12.
A reference to a data buffer.
uint8_t * data
The data buffer.
main external API structure.
enum AVPixelFormat sw_pix_fmt
Nominal unaccelerated pixel format, see AV_PIX_FMT_xxx.
const struct AVHWAccel * hwaccel
Hardware accelerator in use.
int64_t bit_rate
the average bitrate
int coded_width
Bitstream width / height, may be different from width/height e.g.
This struct is allocated as AVHWDeviceContext.hwctx.
ID3D12Device * device
Device used for objects creation and access.
ID3D12VideoDevice * video_device
If unset, this will be set from the device field on init.
D3D12VA frame descriptor for pool allocation.
This struct is allocated as AVHWFramesContext.hwctx.
DXGI_FORMAT format
DXGI_FORMAT format.
This struct is used to sync d3d12 execution.
HANDLE event
A handle to the event object that's raised when the fence reaches a certain value.
ID3D12Fence * fence
D3D12 fence object.
uint64_t fence_value
The fence value used for sync.
This structure describes decoded (raw) audio or video data.
enum AVPixelFormat pix_fmt
Supported pixel format.
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
This struct describes a set or pool of "hardware" frames (i.e.
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
int width
The allocated dimensions of the frames in this pool.
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
This structure is used to provide the necessary configurations and data to the FFmpeg Direct3D 12 HWA...
ID3D12CommandAllocator * command_allocator
ID3D12Resource * output_resource
ID3D12Resource * resource