FFmpeg
Loading...
Searching...
No Matches
hwcontext_d3d12va.c
Go to the documentation of this file.
1/*
2 * Direct3D 12 HW acceleration.
3 *
4 * copyright (c) 2022-2023 Wu Jianhua <toqsxw@outlook.com>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include "config.h"
24#include "common.h"
25#include "hwcontext.h"
26#include "hwcontext_internal.h"
28#include "hwcontext_d3d12va.h"
29#include "imgutils.h"
30#include "mem.h"
31#include "pixdesc.h"
32#include "pixfmt.h"
33#include "thread.h"
34#include "compat/w32dlfcn.h"
35#include <dxgi1_3.h>
36
37typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY2)(UINT Flags, REFIID riid, void **ppFactory);
38
39typedef struct D3D12VAFramesContext {
40 /**
41 * The public AVD3D12VAFramesContext. See hwcontext_d3d12va.h for it.
42 */
44
45 ID3D12Resource *staging_download_buffer;
46 ID3D12Resource *staging_upload_buffer;
47 ID3D12CommandQueue *command_queue;
48 ID3D12CommandAllocator *command_allocator;
49 ID3D12GraphicsCommandList *command_list;
54
55typedef struct D3D12VADevicePriv {
56 /**
57 * The public AVD3D12VADeviceContext. See hwcontext_d3d12va.h for it.
58 */
60 HANDLE d3d12lib;
61 HANDLE dxgilib;
63 PFN_D3D12_CREATE_DEVICE create_device;
64 PFN_D3D12_GET_DEBUG_INTERFACE get_debug_interface;
66
67static const struct {
68 DXGI_FORMAT d3d_format;
71 { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 },
72 { DXGI_FORMAT_P010, AV_PIX_FMT_P010 },
73 { DXGI_FORMAT_P016, AV_PIX_FMT_P012 },
74};
75
76static void d3d12va_default_lock(void *ctx)
77{
78 WaitForSingleObjectEx(ctx, INFINITE, FALSE);
79}
80
81static void d3d12va_default_unlock(void *ctx)
82{
83 ReleaseMutex(ctx);
84}
85
87{
88 uint64_t completion = ID3D12Fence_GetCompletedValue(psync_ctx->fence);
89 if (completion < psync_ctx->fence_value) {
90 if (FAILED(ID3D12Fence_SetEventOnCompletion(psync_ctx->fence, psync_ctx->fence_value, psync_ctx->event)))
91 return AVERROR(EINVAL);
92
93 WaitForSingleObjectEx(psync_ctx->event, INFINITE, FALSE);
94 }
95
96 return 0;
97}
98
99static inline int d3d12va_wait_queue_idle(AVD3D12VASyncContext *psync_ctx, ID3D12CommandQueue *command_queue)
100{
101 DX_CHECK(ID3D12CommandQueue_Signal(command_queue, psync_ctx->fence, ++psync_ctx->fence_value));
102 return d3d12va_fence_completion(psync_ctx);
103
104fail:
105 return AVERROR(EINVAL);
106}
107
108static int d3d12va_create_staging_buffer_resource(AVHWFramesContext *ctx, D3D12_RESOURCE_STATES states,
109 ID3D12Resource **ppResource, int download)
110{
111 AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
112 D3D12VAFramesContext *s = ctx->hwctx;
113 D3D12_HEAP_PROPERTIES props = { .Type = download ? D3D12_HEAP_TYPE_READBACK : D3D12_HEAP_TYPE_UPLOAD };
114 D3D12_RESOURCE_DESC desc = {
115 .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
116 .Alignment = 0,
117 .Width = s->luma_component_size + (s->luma_component_size >> 1),
118 .Height = 1,
119 .DepthOrArraySize = 1,
120 .MipLevels = 1,
121 .Format = DXGI_FORMAT_UNKNOWN,
122 .SampleDesc = { .Count = 1, .Quality = 0 },
123 .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
124 .Flags = D3D12_RESOURCE_FLAG_NONE,
125 };
126
127 if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->device, &props, D3D12_HEAP_FLAG_NONE, &desc,
128 states, NULL, &IID_ID3D12Resource, (void **)ppResource))) {
129 av_log(ctx, AV_LOG_ERROR, "Could not create the staging buffer resource\n");
130 return AVERROR_UNKNOWN;
131 }
132
133 return 0;
134}
135
137{
138 AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
139 D3D12VAFramesContext *s = ctx->hwctx;
140 AVD3D12VAFramesContext *frames_hwctx = &s->p;
141
142 D3D12_COMMAND_QUEUE_DESC queue_desc = {
143 .Type = D3D12_COMMAND_LIST_TYPE_COPY,
144 .Priority = 0,
145 .NodeMask = 0,
146 };
147
148 s->luma_component_size = FFALIGN(ctx->width * (frames_hwctx->format != DXGI_FORMAT_NV12 ? 2 : 1),
149 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * ctx->height;
150
151 DX_CHECK(ID3D12Device_CreateFence(device_hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
152 &IID_ID3D12Fence, (void **)&s->sync_ctx.fence));
153
154 s->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
155 if (!s->sync_ctx.event)
156 goto fail;
157
158 DX_CHECK(ID3D12Device_CreateCommandQueue(device_hwctx->device, &queue_desc,
159 &IID_ID3D12CommandQueue, (void **)&s->command_queue));
160
161 DX_CHECK(ID3D12Device_CreateCommandAllocator(device_hwctx->device, queue_desc.Type,
162 &IID_ID3D12CommandAllocator, (void **)&s->command_allocator));
163
164 DX_CHECK(ID3D12Device_CreateCommandList(device_hwctx->device, 0, queue_desc.Type,
165 s->command_allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)&s->command_list));
166
167 DX_CHECK(ID3D12GraphicsCommandList_Close(s->command_list));
168
169 ID3D12CommandQueue_ExecuteCommandLists(s->command_queue, 1, (ID3D12CommandList **)&s->command_list);
170
171 return d3d12va_wait_queue_idle(&s->sync_ctx, s->command_queue);
172
173fail:
174 return AVERROR(EINVAL);
175}
176
178{
179 D3D12VAFramesContext *s = ctx->hwctx;
180 AVD3D12VAFramesContext *hwctx = ctx->hwctx;
181
182 D3D12_OBJECT_RELEASE(s->sync_ctx.fence);
183 if (s->sync_ctx.event)
184 CloseHandle(s->sync_ctx.event);
185
186 D3D12_OBJECT_RELEASE(s->staging_download_buffer);
187 D3D12_OBJECT_RELEASE(s->staging_upload_buffer);
188 D3D12_OBJECT_RELEASE(s->command_allocator);
189 D3D12_OBJECT_RELEASE(s->command_list);
190 D3D12_OBJECT_RELEASE(s->command_queue);
191
192 if (hwctx->texture_array)
194}
195
196static int d3d12va_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
197{
198 HRESULT hr;
199 int nb_sw_formats = 0;
200 AVD3D12VADeviceContext *device_hwctx = ctx->hwctx;
201
203 sizeof(*constraints->valid_sw_formats));
204 if (!constraints->valid_sw_formats)
205 return AVERROR(ENOMEM);
206
207 for (int i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
208 D3D12_FEATURE_DATA_FORMAT_SUPPORT format_support = { supported_formats[i].d3d_format };
209 hr = ID3D12Device_CheckFeatureSupport(device_hwctx->device, D3D12_FEATURE_FORMAT_SUPPORT, &format_support, sizeof(format_support));
210 if (SUCCEEDED(hr) && (format_support.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D))
211 constraints->valid_sw_formats[nb_sw_formats++] = supported_formats[i].pix_fmt;
212 }
213 constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE;
214
215 constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
216 if (!constraints->valid_hw_formats)
217 return AVERROR(ENOMEM);
218
219 constraints->valid_hw_formats[0] = AV_PIX_FMT_D3D12;
220 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
221
222 return 0;
223}
224
225static void free_texture(void *opaque, uint8_t *data)
226{
228
230 D3D12_OBJECT_RELEASE(frame->texture);
231
232 D3D12_OBJECT_RELEASE(frame->sync_ctx.fence);
233 if (frame->sync_ctx.event)
234 CloseHandle(frame->sync_ctx.event);
235
236 av_freep(&data);
237}
238
240{
242 D3D12VAFramesContext *s = ctx->hwctx;
243 AVD3D12VAFramesContext *hwctx = ctx->hwctx;
244 AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
245 AVBufferRef *buf;
246
248
249 DX_CHECK(ID3D12Device_CreateFence(device_hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
250 &IID_ID3D12Fence, (void **)&frame->sync_ctx.fence));
251 frame->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
252 if (!frame->sync_ctx.event)
253 goto fail;
254
255 if (s->nb_surfaces_used >= ctx->initial_pool_size) {
256 av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n");
257 goto fail;
258 }
259
260 frame->texture = hwctx->texture_array;
261 frame->subresource_index = s->nb_surfaces_used;
262
263 buf = av_buffer_create((uint8_t *)frame, sizeof(*frame), free_texture, NULL, 0);
264
265 if (!buf)
266 goto fail;
267
268 s->nb_surfaces_used++;
269 return buf;
270fail:
271 free_texture(NULL, (uint8_t *)frame);
272 return NULL;
273}
274
275static AVBufferRef *d3d12va_pool_alloc(void *opaque, size_t size)
276{
278 AVD3D12VAFramesContext *hwctx = ctx->hwctx;
279 AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
280
281 AVBufferRef *buf;
283
284 if (ctx->initial_pool_size > 0 && hwctx->flags & AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY)
286
287 D3D12_HEAP_PROPERTIES props = { .Type = D3D12_HEAP_TYPE_DEFAULT };
288 D3D12_RESOURCE_DESC desc = {
289 .Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
290 .Alignment = 0,
291 .Width = ctx->width,
292 .Height = ctx->height,
293 .DepthOrArraySize = 1,
294 .MipLevels = 1,
295 .Format = hwctx->format,
296 .SampleDesc = {.Count = 1, .Quality = 0 },
297 .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
298 .Flags = hwctx->resource_flags,
299 };
300
302 if (!frame)
303 return NULL;
304
305 if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->device, &props, hwctx->heap_flags, &desc,
306 D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&frame->texture))) {
307 av_log(ctx, AV_LOG_ERROR, "Could not create the texture\n");
308 goto fail;
309 }
310
311 DX_CHECK(ID3D12Device_CreateFence(device_hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
312 &IID_ID3D12Fence, (void **)&frame->sync_ctx.fence));
313
314 frame->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
315 if (!frame->sync_ctx.event)
316 goto fail;
317
318 buf = av_buffer_create((uint8_t *)frame, sizeof(*frame), free_texture, NULL, 0);
319 if (!buf)
320 goto fail;
321
322 return buf;
323
324fail:
325 free_texture(NULL, (uint8_t *)frame);
326 return NULL;
327}
328
330{
331 AVD3D12VAFramesContext *hwctx = ctx->hwctx;
332 AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
333
334 D3D12_HEAP_PROPERTIES props = { .Type = D3D12_HEAP_TYPE_DEFAULT };
335
336 D3D12_RESOURCE_DESC desc = {
337 .Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
338 .Alignment = 0,
339 .Width = ctx->width,
340 .Height = ctx->height,
341 .DepthOrArraySize = ctx->initial_pool_size,
342 .MipLevels = 1,
343 .Format = hwctx->format,
344 .SampleDesc = {.Count = 1, .Quality = 0 },
345 .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
346 .Flags = hwctx->resource_flags,
347 };
348
349 if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->device, &props, hwctx->heap_flags, &desc,
350 D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&hwctx->texture_array))) {
351 av_log(ctx, AV_LOG_ERROR, "Could not create the texture array\n");
352 return AVERROR(EINVAL);
353 }
354 return 0;
355}
356
358{
359 AVD3D12VAFramesContext *hwctx = ctx->hwctx;
360 AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
361 int i;
362
363 for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
364 if (ctx->sw_format == supported_formats[i].pix_fmt) {
365 if (hwctx->format != DXGI_FORMAT_UNKNOWN &&
366 hwctx->format != supported_formats[i].d3d_format)
367 av_log(ctx, AV_LOG_WARNING, "Incompatible DXGI format provided by user, will be overided\n");
368 hwctx->format = supported_formats[i].d3d_format;
369 break;
370 }
371 }
372
374 av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n",
375 av_get_pix_fmt_name(ctx->sw_format));
376 return AVERROR(EINVAL);
377 }
378
379 hwctx->resource_flags |= device_hwctx->resource_flags;
380 hwctx->heap_flags |= device_hwctx->heap_flags;
381
382 if (ctx->initial_pool_size > 0 && hwctx->flags & AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY) {
384 if (err < 0)
385 return err;
386 }
387
390
391 if (!ffhwframesctx(ctx)->pool_internal)
392 return AVERROR(ENOMEM);
393
394 return 0;
395}
396
398{
399 int ret;
400
401 frame->buf[0] = av_buffer_pool_get(ctx->pool);
402 if (!frame->buf[0])
403 return AVERROR(ENOMEM);
404
405 ret = av_image_fill_arrays(frame->data, frame->linesize, NULL,
406 ctx->sw_format, ctx->width, ctx->height,
407 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
408 if (ret < 0)
409 return ret;
410
411 frame->data[0] = frame->buf[0]->data;
412 frame->format = AV_PIX_FMT_D3D12;
413 frame->width = ctx->width;
414 frame->height = ctx->height;
415
416 return 0;
417}
418
421 enum AVPixelFormat **formats)
422{
423 enum AVPixelFormat *fmts;
424
425 fmts = av_malloc_array(2, sizeof(*fmts));
426 if (!fmts)
427 return AVERROR(ENOMEM);
428
429 fmts[0] = ctx->sw_format;
430 fmts[1] = AV_PIX_FMT_NONE;
431
432 *formats = fmts;
433
434 return 0;
435}
436
438 const AVFrame *src)
439{
440 AVD3D12VADeviceContext *hwctx = ctx->device_ctx->hwctx;
441 D3D12VAFramesContext *s = ctx->hwctx;
442 AVD3D12VAFramesContext *frames_hwctx = &s->p;
443
444 int ret;
445 int download = src->format == AV_PIX_FMT_D3D12;
446 const AVFrame *frame = download ? src : dst;
447 const AVFrame *other = download ? dst : src;
448
449 AVD3D12VAFrame *f = (AVD3D12VAFrame *)frame->data[0];
450 ID3D12Resource *texture = (ID3D12Resource *)f->texture;
451
452 uint8_t *mapped_data;
453 uint8_t *data[4];
454 int linesizes[4];
455
456 D3D12_TEXTURE_COPY_LOCATION staging_y_location = { 0 };
457 D3D12_TEXTURE_COPY_LOCATION staging_uv_location = { 0 };
458
459 D3D12_TEXTURE_COPY_LOCATION texture_y_location = {
460 .pResource = texture,
461 .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
462 .SubresourceIndex = 0,
463 };
464
465 D3D12_TEXTURE_COPY_LOCATION texture_uv_location = {
466 .pResource = texture,
467 .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
468 .SubresourceIndex = 1,
469 };
470
471 D3D12_RESOURCE_BARRIER barrier = {
472 .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
473 .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
474 .Transition = {
475 .pResource = texture,
476 .StateBefore = D3D12_RESOURCE_STATE_COMMON,
477 .StateAfter = download ? D3D12_RESOURCE_STATE_COPY_SOURCE : D3D12_RESOURCE_STATE_COPY_DEST,
478 .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
479 },
480 };
481
482 if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format)
483 return AVERROR(EINVAL);
484
485 hwctx->lock(hwctx->lock_ctx);
486
487 if (!s->command_queue) {
489 if (ret < 0)
490 goto fail;
491 }
492
493 for (int i = 0; i < 4; i++)
494 linesizes[i] = FFALIGN(frame->width * (frames_hwctx->format != DXGI_FORMAT_NV12 ? 2 : 1),
495 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
496
497 staging_y_location = (D3D12_TEXTURE_COPY_LOCATION) {
498 .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
499 .PlacedFootprint = {
500 .Offset = 0,
501 .Footprint = {
502 .Format = frames_hwctx->format != DXGI_FORMAT_NV12 ?
503 DXGI_FORMAT_R16_UNORM : DXGI_FORMAT_R8_UNORM,
504 .Width = ctx->width,
505 .Height = ctx->height,
506 .Depth = 1,
507 .RowPitch = linesizes[0],
508 },
509 },
510 };
511
512 staging_uv_location = (D3D12_TEXTURE_COPY_LOCATION) {
513 .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
514 .PlacedFootprint = {
515 .Offset = s->luma_component_size,
516 .Footprint = {
517 .Format = frames_hwctx->format != DXGI_FORMAT_NV12 ?
518 DXGI_FORMAT_R16G16_UNORM : DXGI_FORMAT_R8G8_UNORM,
519 .Width = ctx->width >> 1,
520 .Height = ctx->height >> 1,
521 .Depth = 1,
522 .RowPitch = linesizes[0],
523 },
524 },
525 };
526
527 DX_CHECK(ID3D12CommandAllocator_Reset(s->command_allocator));
528
529 DX_CHECK(ID3D12GraphicsCommandList_Reset(s->command_list, s->command_allocator, NULL));
530
531 if (download) {
532 if (!s->staging_download_buffer) {
533 ret = d3d12va_create_staging_buffer_resource(ctx, D3D12_RESOURCE_STATE_COPY_DEST,
534 &s->staging_download_buffer, 1);
535 if (ret < 0) {
536 goto fail;
537 }
538 }
539
540 staging_y_location.pResource = staging_uv_location.pResource = s->staging_download_buffer;
541
542 ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
543
544 ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
545 &staging_y_location, 0, 0, 0,
546 &texture_y_location, NULL);
547
548 ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
549 &staging_uv_location, 0, 0, 0,
550 &texture_uv_location, NULL);
551
552 barrier.Transition.StateBefore = barrier.Transition.StateAfter;
553 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
554 ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
555
556 DX_CHECK(ID3D12GraphicsCommandList_Close(s->command_list));
557
558 DX_CHECK(ID3D12CommandQueue_Wait(s->command_queue, f->sync_ctx.fence, f->sync_ctx.fence_value));
559
560 ID3D12CommandQueue_ExecuteCommandLists(s->command_queue, 1, (ID3D12CommandList **)&s->command_list);
561
562 ret = d3d12va_wait_queue_idle(&s->sync_ctx, s->command_queue);
563 if (ret < 0)
564 goto fail;
565
566 DX_CHECK(ID3D12Resource_Map(s->staging_download_buffer, 0, NULL, (void **)&mapped_data));
567 av_image_fill_pointers(data, ctx->sw_format, ctx->height, mapped_data, linesizes);
568
569 av_image_copy2(dst->data, dst->linesize, data, linesizes,
570 ctx->sw_format, ctx->width, ctx->height);
571
572 ID3D12Resource_Unmap(s->staging_download_buffer, 0, NULL);
573 } else {
574 if (!s->staging_upload_buffer) {
575 ret = d3d12va_create_staging_buffer_resource(ctx, D3D12_RESOURCE_STATE_GENERIC_READ,
576 &s->staging_upload_buffer, 0);
577 if (ret < 0) {
578 goto fail;
579 }
580 }
581
582 staging_y_location.pResource = staging_uv_location.pResource = s->staging_upload_buffer;
583
584 DX_CHECK(ID3D12Resource_Map(s->staging_upload_buffer, 0, NULL, (void **)&mapped_data));
585 av_image_fill_pointers(data, ctx->sw_format, ctx->height, mapped_data, linesizes);
586
587 av_image_copy2(data, linesizes, src->data, src->linesize,
588 ctx->sw_format, ctx->width, ctx->height);
589
590 ID3D12Resource_Unmap(s->staging_upload_buffer, 0, NULL);
591
592 ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
593
594 ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
595 &texture_y_location, 0, 0, 0,
596 &staging_y_location, NULL);
597
598 ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
599 &texture_uv_location, 0, 0, 0,
600 &staging_uv_location, NULL);
601
602 barrier.Transition.StateBefore = barrier.Transition.StateAfter;
603 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
604 ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
605
606 DX_CHECK(ID3D12GraphicsCommandList_Close(s->command_list));
607
608 ID3D12CommandQueue_ExecuteCommandLists(s->command_queue, 1, (ID3D12CommandList **)&s->command_list);
609
610 ret = d3d12va_wait_queue_idle(&s->sync_ctx, s->command_queue);
611 if (ret < 0)
612 goto fail;
613 }
614
615 hwctx->unlock(hwctx->lock_ctx);
616
617 return 0;
618
619fail:
620 hwctx->unlock(hwctx->lock_ctx);
621 return AVERROR(EINVAL);
622}
623
625{
626 D3D12VADevicePriv *priv = hwdev->hwctx;
627
628#if !HAVE_UWP
629 priv->d3d12lib = dlopen("d3d12.dll", 0);
630 priv->dxgilib = dlopen("dxgi.dll", 0);
631
632 if (!priv->d3d12lib || !priv->dxgilib)
633 goto fail;
634
635 priv->create_device = (PFN_D3D12_CREATE_DEVICE)GetProcAddress(priv->d3d12lib, "D3D12CreateDevice");
636 if (!priv->create_device)
637 goto fail;
638
639 priv->create_dxgi_factory2 = (PFN_CREATE_DXGI_FACTORY2)GetProcAddress(priv->dxgilib, "CreateDXGIFactory2");
640 if (!priv->create_dxgi_factory2)
641 goto fail;
642
643 priv->get_debug_interface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(priv->d3d12lib, "D3D12GetDebugInterface");
644#else
645 priv->create_device = (PFN_D3D12_CREATE_DEVICE) D3D12CreateDevice;
646 priv->create_dxgi_factory2 = (PFN_CREATE_DXGI_FACTORY2) CreateDXGIFactory2;
647 priv->get_debug_interface = (PFN_D3D12_GET_DEBUG_INTERFACE) D3D12GetDebugInterface;
648#endif
649 return 0;
650
651#if !HAVE_UWP
652fail:
653 av_log(hwdev, AV_LOG_ERROR, "Failed to load D3D12 library or its functions\n");
654 return AVERROR_UNKNOWN;
655#endif
656}
657
659{
660 D3D12VADevicePriv *priv = hwdev->hwctx;
661 AVD3D12VADeviceContext *ctx = &priv->p;
662
663 D3D12_OBJECT_RELEASE(ctx->device);
664
665 if (priv->d3d12lib)
666 dlclose(priv->d3d12lib);
667
668 if (priv->dxgilib)
669 dlclose(priv->dxgilib);
670}
671
673{
675
676 if (!ctx->lock) {
677 ctx->lock_ctx = CreateMutex(NULL, 0, NULL);
678 if (ctx->lock_ctx == INVALID_HANDLE_VALUE) {
679 av_log(NULL, AV_LOG_ERROR, "Failed to create a mutex\n");
680 return AVERROR(EINVAL);
681 }
683 ctx->unlock = d3d12va_default_unlock;
684 }
685
686 if (!ctx->video_device)
687 DX_CHECK(ID3D12Device_QueryInterface(ctx->device, &IID_ID3D12VideoDevice, (void **)&ctx->video_device));
688
689 return 0;
690
691fail:
692 return AVERROR(EINVAL);
693}
694
696{
697 AVD3D12VADeviceContext *device_hwctx = hwdev->hwctx;
698
699 D3D12_OBJECT_RELEASE(device_hwctx->video_device);
700
701 if (device_hwctx->lock == d3d12va_default_lock) {
702 CloseHandle(device_hwctx->lock_ctx);
703 device_hwctx->lock_ctx = INVALID_HANDLE_VALUE;
704 device_hwctx->lock = NULL;
705 }
706}
707
708static int d3d12va_device_create(AVHWDeviceContext *hwdev, const char *device,
709 AVDictionary *opts, int flags)
710{
711 D3D12VADevicePriv *priv = hwdev->hwctx;
712 AVD3D12VADeviceContext *ctx = &priv->p;
713
714 HRESULT hr;
715 UINT create_flags = 0;
716 IDXGIAdapter *pAdapter = NULL;
717
718 int ret;
719 int is_debug = !!av_dict_get(opts, "debug", NULL, 0);
720
721 hwdev->free = d3d12va_device_free;
722
723 ret = d3d12va_load_functions(hwdev);
724 if (ret < 0)
725 return ret;
726
727 if (is_debug) {
728 ID3D12Debug *pDebug;
729 if (priv->get_debug_interface && SUCCEEDED(priv->get_debug_interface(&IID_ID3D12Debug, (void **)&pDebug))) {
730 create_flags |= DXGI_CREATE_FACTORY_DEBUG;
731 ID3D12Debug_EnableDebugLayer(pDebug);
732 D3D12_OBJECT_RELEASE(pDebug);
733 av_log(hwdev, AV_LOG_INFO, "D3D12 debug layer is enabled!\n");
734 }
735 }
736
737 if (!ctx->device) {
738 IDXGIFactory2 *pDXGIFactory = NULL;
739
740 hr = priv->create_dxgi_factory2(create_flags, &IID_IDXGIFactory2, (void **)&pDXGIFactory);
741 if (SUCCEEDED(hr)) {
742 int adapter = device ? atoi(device) : 0;
743 if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
744 pAdapter = NULL;
745 IDXGIFactory2_Release(pDXGIFactory);
746 }
747
748 if (pAdapter) {
749 DXGI_ADAPTER_DESC desc;
750 hr = IDXGIAdapter2_GetDesc(pAdapter, &desc);
751 if (!FAILED(hr)) {
752 av_log(hwdev, AV_LOG_INFO, "Using device %04x:%04x (%ls).\n",
753 desc.VendorId, desc.DeviceId, desc.Description);
754 }
755 }
756
757 hr = priv->create_device((IUnknown *)pAdapter, D3D_FEATURE_LEVEL_12_0, &IID_ID3D12Device, (void **)&ctx->device);
758 D3D12_OBJECT_RELEASE(pAdapter);
759 if (FAILED(hr)) {
760 av_log(hwdev, AV_LOG_ERROR, "Failed to create Direct 3D 12 device (%lx)\n", (long)hr);
761 return AVERROR_UNKNOWN;
762 }
763 }
764
765 if (av_dict_get(opts, "UAV", NULL, 0))
766 ctx->resource_flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
767
768 if (av_dict_get(opts, "RTV", NULL, 0))
769 ctx->resource_flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
770
771 if (av_dict_get(opts, "SHARED", NULL, 0))
772 ctx->heap_flags |= D3D12_HEAP_FLAG_SHARED;
773
774 return 0;
775}
776
779 .name = "D3D12VA",
780
781 .device_hwctx_size = sizeof(D3D12VADevicePriv),
782 .frames_hwctx_size = sizeof(D3D12VAFramesContext),
783
784 .device_create = d3d12va_device_create,
785 .device_init = d3d12va_device_init,
786 .device_uninit = d3d12va_device_uninit,
787 .frames_get_constraints = d3d12va_frames_get_constraints,
788 .frames_init = d3d12va_frames_init,
789 .frames_uninit = d3d12va_frames_uninit,
790 .frames_get_buffer = d3d12va_get_buffer,
791 .transfer_get_formats = d3d12va_transfer_get_formats,
792 .transfer_data_to = d3d12va_transfer_data,
793 .transfer_data_from = d3d12va_transfer_data,
794
795 .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_D3D12, AV_PIX_FMT_NONE },
796};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static AVFormatContext * ctx
static AVDictionary * opts
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define f(width, name)
Definition cbs_vp8.c:236
#define s(width, name)
Definition cbs_vp9.c:198
common internal and external API header
#define NULL
Definition coverity.c:32
static enum AVPixelFormat pix_fmt
static AVFrame * frame
#define fail
Definition test.h:479
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.
Definition buffer.c:55
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition buffer.c:390
AVBufferPool * av_buffer_pool_init2(size_t size, void *opaque, AVBufferRef *(*alloc)(void *opaque, size_t size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition buffer.c:259
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition dict.c:60
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition error.h:73
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, uint8_t *ptr, const int linesizes[4])
Fill plane data pointers for an image with pixel format pix_fmt and height height.
Definition imgutils.c:145
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], const uint8_t *src, enum AVPixelFormat pix_fmt, int width, int height, int align)
Setup the data pointers and linesizes based on the specified image parameters and the provided array.
Definition imgutils.c:446
static void av_image_copy2(uint8_t *const dst_data[4], const int dst_linesizes[4], uint8_t *const src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height)
Wrapper around av_image_copy() to workaround the limitation that the conversion from uint8_t * const ...
Definition imgutils.h:184
AVHWFrameTransferDirection
Definition hwcontext.h:406
@ AV_HWDEVICE_TYPE_D3D12VA
Definition hwcontext.h:40
static void free_texture(void *opaque, uint8_t *data)
DXGI_FORMAT d3d_format
static int d3d12va_device_init(AVHWDeviceContext *hwdev)
static void free_texture(void *opaque, uint8_t *data)
static int d3d12va_frames_init(AVHWFramesContext *ctx)
static int d3d12va_create_helper_objects(AVHWFramesContext *ctx)
static int d3d12va_transfer_get_formats(AVHWFramesContext *ctx, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
static int d3d12va_texture_array_init(AVHWFramesContext *ctx)
static AVBufferRef * d3d12va_pool_alloc(void *opaque, size_t size)
static int d3d12va_wait_queue_idle(AVD3D12VASyncContext *psync_ctx, ID3D12CommandQueue *command_queue)
static int d3d12va_fence_completion(AVD3D12VASyncContext *psync_ctx)
static int d3d12va_create_staging_buffer_resource(AVHWFramesContext *ctx, D3D12_RESOURCE_STATES states, ID3D12Resource **ppResource, int download)
static void d3d12va_frames_uninit(AVHWFramesContext *ctx)
static void d3d12va_default_unlock(void *ctx)
static void d3d12va_default_lock(void *ctx)
static AVBufferRef * d3d12va_pool_alloc_texture_array(AVHWFramesContext *ctx)
static int d3d12va_device_create(AVHWDeviceContext *hwdev, const char *device, AVDictionary *opts, int flags)
static int d3d12va_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
static int d3d12va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src)
const HWContextType ff_hwcontext_type_d3d12va
static int d3d12va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY2)(UINT Flags, REFIID riid, void **ppFactory)
static void d3d12va_device_uninit(AVHWDeviceContext *hwdev)
static void d3d12va_device_free(AVHWDeviceContext *hwdev)
static int d3d12va_load_functions(AVHWDeviceContext *hwdev)
An API-specific header for AV_HWDEVICE_TYPE_D3D12VA.
@ AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY
Indicates that frame data should be allocated using a texture array resource.
#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.
static FFHWFramesContext * ffhwframesctx(AVHWFramesContext *ctx)
misc image utilities
const char * desc
Definition libsvtav1.c:83
#define FFALIGN(x, a)
Definition macros.h:78
Memory handling functions.
const char data[16]
Definition mxf.c:149
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition pixdesc.c:3380
pixel format definitions
#define AV_PIX_FMT_P012
Definition pixfmt.h:609
#define AV_PIX_FMT_P010
Definition pixfmt.h:608
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ 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...
Definition pixfmt.h:96
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_D3D12
Hardware surfaces for Direct3D 12.
Definition pixfmt.h:440
formats
Definition signature.h:47
#define FF_ARRAY_ELEMS(a)
A reference to a data buffer.
Definition buffer.h:82
This struct is allocated as AVHWDeviceContext.hwctx.
void(* unlock)(void *lock_ctx)
ID3D12Device * device
Device used for objects creation and access.
void(* lock)(void *lock_ctx)
Callbacks for locking.
D3D12_RESOURCE_FLAGS resource_flags
Resource flags to be applied to D3D12 resources allocated for frames using this device context.
D3D12_HEAP_FLAGS heap_flags
Heap flags to be applied to D3D12 resources allocated for frames using this device context.
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.
D3D12_RESOURCE_FLAGS resource_flags
Options for working with resources.
AVD3D12VAFrameFlags flags
A combination of AVD3D12VAFrameFlags.
D3D12_HEAP_FLAGS heap_flags
Options for working with heaps allocation when creating resources.
ID3D12Resource * texture_array
In texture array mode, the D3D12 uses the same texture array (resource)for all pictures.
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.
Definition frame.h:472
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition frame.h:559
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition hwcontext.h:63
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition hwcontext.h:88
void(* free)(struct AVHWDeviceContext *ctx)
This field may be set by the caller before calling av_hwdevice_ctx_init().
Definition hwcontext.h:100
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition hwcontext.h:444
enum AVPixelFormat * valid_hw_formats
A list of possible values for format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition hwcontext.h:449
enum AVPixelFormat * valid_sw_formats
A list of possible values for sw_format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition hwcontext.h:456
This struct describes a set or pool of "hardware" frames (i.e.
Definition hwcontext.h:118
PFN_D3D12_GET_DEBUG_INTERFACE get_debug_interface
PFN_CREATE_DXGI_FACTORY2 create_dxgi_factory2
PFN_D3D12_CREATE_DEVICE create_device
AVD3D12VADeviceContext p
The public AVD3D12VADeviceContext.
ID3D12CommandAllocator * command_allocator
AVD3D12VAFramesContext p
The public AVD3D12VAFramesContext.
ID3D12CommandQueue * command_queue
AVD3D12VASyncContext sync_ctx
ID3D12Resource * staging_download_buffer
ID3D12Resource * staging_upload_buffer
ID3D12GraphicsCommandList * command_list
AVBufferPool * pool_internal
#define av_malloc_array(a, b)
#define av_mallocz(s)
#define av_freep(p)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
int size
static enum AVPixelFormat supported_formats[]