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"
35 #include <dxgi1_3.h>
36
38
40 /**
41 * The public AVD3D12VAFramesContext. See hwcontext_d3d12va.h for it.
42 */
44
53
55 /**
56 * The public AVD3D12VADeviceContext. See hwcontext_d3d12va.h for it.
57 */
65
66 static const struct {
72 };
73
75 {
76 WaitForSingleObjectEx(
ctx, INFINITE, FALSE);
77 }
78
80 {
82 }
83
85 {
86 uint64_t completion = ID3D12Fence_GetCompletedValue(psync_ctx->
fence);
87 if (completion < psync_ctx->fence_value) {
88 if (FAILED(ID3D12Fence_SetEventOnCompletion(psync_ctx->
fence, psync_ctx->
fence_value, psync_ctx->
event)))
90
91 WaitForSingleObjectEx(psync_ctx->
event, INFINITE, FALSE);
92 }
93
94 return 0;
95 }
96
98 {
101
104 }
105
107 ID3D12Resource **ppResource, int download)
108 {
111 D3D12_HEAP_PROPERTIES props = { .Type = download ? D3D12_HEAP_TYPE_READBACK : D3D12_HEAP_TYPE_UPLOAD };
112 D3D12_RESOURCE_DESC
desc = {
113 .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
114 .Alignment = 0,
115 .Width =
s->luma_component_size + (
s->luma_component_size >> 1),
116 .Height = 1,
117 .DepthOrArraySize = 1,
118 .MipLevels = 1,
119 .Format = DXGI_FORMAT_UNKNOWN,
120 .SampleDesc = { .Count = 1, .Quality = 0 },
121 .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
122 .Flags = D3D12_RESOURCE_FLAG_NONE,
123 };
124
125 if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->
device, &props, D3D12_HEAP_FLAG_NONE, &
desc,
126 states,
NULL, &IID_ID3D12Resource, (
void **)ppResource))) {
129 }
130
131 return 0;
132 }
133
135 {
139
140 D3D12_COMMAND_QUEUE_DESC queue_desc = {
141 .Type = D3D12_COMMAND_LIST_TYPE_COPY,
142 .Priority = 0,
143 .NodeMask = 0,
144 };
145
146 s->luma_component_size =
FFALIGN(
ctx->width * (frames_hwctx->
format == DXGI_FORMAT_P010 ? 2 : 1),
147 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) *
ctx->height;
148
149 DX_CHECK(ID3D12Device_CreateFence(device_hwctx->
device, 0, D3D12_FENCE_FLAG_NONE,
150 &IID_ID3D12Fence, (
void **)&
s->sync_ctx.fence));
151
152 s->sync_ctx.event = CreateEvent(
NULL, FALSE, FALSE,
NULL);
153 if (!
s->sync_ctx.event)
155
156 DX_CHECK(ID3D12Device_CreateCommandQueue(device_hwctx->
device, &queue_desc,
157 &IID_ID3D12CommandQueue, (
void **)&
s->command_queue));
158
159 DX_CHECK(ID3D12Device_CreateCommandAllocator(device_hwctx->
device, queue_desc.Type,
160 &IID_ID3D12CommandAllocator, (
void **)&
s->command_allocator));
161
162 DX_CHECK(ID3D12Device_CreateCommandList(device_hwctx->
device, 0, queue_desc.Type,
163 s->command_allocator,
NULL, &IID_ID3D12GraphicsCommandList, (
void **)&
s->command_list));
164
165 DX_CHECK(ID3D12GraphicsCommandList_Close(
s->command_list));
166
167 ID3D12CommandQueue_ExecuteCommandLists(
s->command_queue, 1, (ID3D12CommandList **)&
s->command_list);
168
170
173 }
174
176 {
178
180 if (
s->sync_ctx.event)
181 CloseHandle(
s->sync_ctx.event);
182
188 }
189
191 {
192 HRESULT hr;
193 int nb_sw_formats = 0;
195
200
202 D3D12_FEATURE_DATA_FORMAT_SUPPORT format_support = {
supported_formats[
i].d3d_format };
203 hr = ID3D12Device_CheckFeatureSupport(device_hwctx->
device, D3D12_FEATURE_FORMAT_SUPPORT, &format_support,
sizeof(format_support));
204 if (SUCCEEDED(hr) && (format_support.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D))
206 }
208
212
215
216 return 0;
217 }
218
220 {
222
225 if (
frame->sync_ctx.event)
226 CloseHandle(
frame->sync_ctx.event);
227
229 }
230
232 {
236
239 D3D12_HEAP_PROPERTIES props = { .Type = D3D12_HEAP_TYPE_DEFAULT };
240 D3D12_RESOURCE_DESC
desc = {
241 .Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
242 .Alignment = 0,
244 .Height =
ctx->height,
245 .DepthOrArraySize = 1,
246 .MipLevels = 1,
248 .SampleDesc = {.Count = 1, .Quality = 0 },
249 .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
250 .Flags = hwctx->
flags,
251 };
252
256
257 if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->
device, &props, D3D12_HEAP_FLAG_NONE, &
desc,
258 D3D12_RESOURCE_STATE_COMMON,
NULL, &IID_ID3D12Resource, (
void **)&
frame->texture))) {
261 }
262
263 DX_CHECK(ID3D12Device_CreateFence(device_hwctx->
device, 0, D3D12_FENCE_FLAG_NONE,
264 &IID_ID3D12Fence, (
void **)&
frame->sync_ctx.fence));
265
266 frame->sync_ctx.event = CreateEvent(
NULL, FALSE, FALSE,
NULL);
267 if (!
frame->sync_ctx.event)
269
271 if (!buf)
273
274 return buf;
275
279 }
280
282 {
285
288 if (hwctx->
format != DXGI_FORMAT_UNKNOWN &&
292 break;
293 }
294 }
299 }
300
303
306
307 return 0;
308 }
309
311 {
313
317
320 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
323
328
329 return 0;
330 }
331
335 {
337
339 if (!fmts)
341
342 fmts[0] =
ctx->sw_format;
344
346
347 return 0;
348 }
349
352 {
356
361
363 ID3D12Resource *texture = (ID3D12Resource *)
f->texture;
364
365 uint8_t *mapped_data;
367 int linesizes[4];
368
369 D3D12_TEXTURE_COPY_LOCATION staging_y_location = { 0 };
370 D3D12_TEXTURE_COPY_LOCATION staging_uv_location = { 0 };
371
372 D3D12_TEXTURE_COPY_LOCATION texture_y_location = {
373 .pResource = texture,
374 .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
375 .SubresourceIndex = 0,
376 };
377
378 D3D12_TEXTURE_COPY_LOCATION texture_uv_location = {
379 .pResource = texture,
380 .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
381 .SubresourceIndex = 1,
382 };
383
384 D3D12_RESOURCE_BARRIER barrier = {
385 .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
386 .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
387 .Transition = {
388 .pResource = texture,
389 .StateBefore = D3D12_RESOURCE_STATE_COMMON,
390 .StateAfter = download ? D3D12_RESOURCE_STATE_COPY_SOURCE : D3D12_RESOURCE_STATE_COPY_DEST,
391 .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
392 },
393 };
394
395 if (
frame->hw_frames_ctx->data != (uint8_t *)
ctx || other->
format !=
ctx->sw_format)
397
399
400 if (!
s->command_queue) {
404 }
405
406 for (
int i = 0;
i < 4;
i++)
408 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
409
410 staging_y_location = (D3D12_TEXTURE_COPY_LOCATION) {
411 .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
412 .PlacedFootprint = {
413 .Offset = 0,
414 .Footprint = {
415 .Format = frames_hwctx->
format == DXGI_FORMAT_P010 ?
416 DXGI_FORMAT_R16_UNORM : DXGI_FORMAT_R8_UNORM,
418 .Height =
ctx->height,
419 .Depth = 1,
420 .RowPitch = linesizes[0],
421 },
422 },
423 };
424
425 staging_uv_location = (D3D12_TEXTURE_COPY_LOCATION) {
426 .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
427 .PlacedFootprint = {
428 .Offset =
s->luma_component_size,
429 .Footprint = {
430 .Format = frames_hwctx->
format == DXGI_FORMAT_P010 ?
431 DXGI_FORMAT_R16G16_UNORM : DXGI_FORMAT_R8G8_UNORM,
432 .Width =
ctx->width >> 1,
433 .Height =
ctx->height >> 1,
434 .Depth = 1,
435 .RowPitch = linesizes[0],
436 },
437 },
438 };
439
440 DX_CHECK(ID3D12CommandAllocator_Reset(
s->command_allocator));
441
442 DX_CHECK(ID3D12GraphicsCommandList_Reset(
s->command_list,
s->command_allocator,
NULL));
443
444 if (download) {
445 if (!
s->staging_download_buffer) {
447 &
s->staging_download_buffer, 1);
450 }
451 }
452
453 staging_y_location.pResource = staging_uv_location.pResource =
s->staging_download_buffer;
454
455 ID3D12GraphicsCommandList_ResourceBarrier(
s->command_list, 1, &barrier);
456
457 ID3D12GraphicsCommandList_CopyTextureRegion(
s->command_list,
458 &staging_y_location, 0, 0, 0,
459 &texture_y_location,
NULL);
460
461 ID3D12GraphicsCommandList_CopyTextureRegion(
s->command_list,
462 &staging_uv_location, 0, 0, 0,
463 &texture_uv_location,
NULL);
464
465 barrier.Transition.StateBefore = barrier.Transition.StateAfter;
466 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
467 ID3D12GraphicsCommandList_ResourceBarrier(
s->command_list, 1, &barrier);
468
469 DX_CHECK(ID3D12GraphicsCommandList_Close(
s->command_list));
470
471 DX_CHECK(ID3D12CommandQueue_Wait(
s->command_queue,
f->sync_ctx.fence,
f->sync_ctx.fence_value));
472
473 ID3D12CommandQueue_ExecuteCommandLists(
s->command_queue, 1, (ID3D12CommandList **)&
s->command_list);
474
478
479 DX_CHECK(ID3D12Resource_Map(
s->staging_download_buffer, 0,
NULL, (
void **)&mapped_data));
481
483 ctx->sw_format,
ctx->width,
ctx->height);
484
485 ID3D12Resource_Unmap(
s->staging_download_buffer, 0,
NULL);
486 } else {
487 if (!
s->staging_upload_buffer) {
489 &
s->staging_upload_buffer, 0);
492 }
493 }
494
495 staging_y_location.pResource = staging_uv_location.pResource =
s->staging_upload_buffer;
496
497 DX_CHECK(ID3D12Resource_Map(
s->staging_upload_buffer, 0,
NULL, (
void **)&mapped_data));
499
501 ctx->sw_format,
ctx->width,
ctx->height);
502
503 ID3D12Resource_Unmap(
s->staging_upload_buffer, 0,
NULL);
504
505 ID3D12GraphicsCommandList_ResourceBarrier(
s->command_list, 1, &barrier);
506
507 ID3D12GraphicsCommandList_CopyTextureRegion(
s->command_list,
508 &texture_y_location, 0, 0, 0,
509 &staging_y_location,
NULL);
510
511 ID3D12GraphicsCommandList_CopyTextureRegion(
s->command_list,
512 &texture_uv_location, 0, 0, 0,
513 &staging_uv_location,
NULL);
514
515 barrier.Transition.StateBefore = barrier.Transition.StateAfter;
516 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
517 ID3D12GraphicsCommandList_ResourceBarrier(
s->command_list, 1, &barrier);
518
519 DX_CHECK(ID3D12GraphicsCommandList_Close(
s->command_list));
520
521 ID3D12CommandQueue_ExecuteCommandLists(
s->command_queue, 1, (ID3D12CommandList **)&
s->command_list);
522
526 }
527
529
530 return 0;
531
535 }
536
538 {
540
541 #if !HAVE_UWP
542 priv->
d3d12lib = dlopen(
"d3d12.dll", 0);
543 priv->
dxgilib = dlopen(
"dxgi.dll", 0);
544
547
551
555
557 #else
558 priv->
create_device = (PFN_D3D12_CREATE_DEVICE) D3D12CreateDevice;
561 #endif
562 return 0;
563
567 }
568
570 {
573
575
578
581 }
582
584 {
586
589 if (
ctx->lock_ctx == INVALID_HANDLE_VALUE) {
592 }
595 }
596
597 if (!
ctx->video_device)
598 DX_CHECK(ID3D12Device_QueryInterface(
ctx->device, &IID_ID3D12VideoDevice, (
void **)&
ctx->video_device));
599
600 return 0;
601
604 }
605
607 {
609
611
613 CloseHandle(device_hwctx->
lock_ctx);
614 device_hwctx->
lock_ctx = INVALID_HANDLE_VALUE;
616 }
617 }
618
621 {
624
625 HRESULT hr;
626 UINT create_flags = 0;
627 IDXGIAdapter *pAdapter =
NULL;
628
631
633
637
638 if (is_debug) {
639 ID3D12Debug *pDebug;
641 create_flags |= DXGI_CREATE_FACTORY_DEBUG;
642 ID3D12Debug_EnableDebugLayer(pDebug);
645 }
646 }
647
649 IDXGIFactory2 *pDXGIFactory =
NULL;
650
652 if (SUCCEEDED(hr)) {
653 int adapter = device ? atoi(device) : 0;
654 if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
656 IDXGIFactory2_Release(pDXGIFactory);
657 }
658
659 if (pAdapter) {
660 DXGI_ADAPTER_DESC
desc;
661 hr = IDXGIAdapter2_GetDesc(pAdapter, &
desc);
662 if (!FAILED(hr)) {
665 }
666 }
667
668 hr = priv->
create_device((IUnknown *)pAdapter, D3D_FEATURE_LEVEL_12_0, &IID_ID3D12Device, (
void **)&
ctx->device);
670 if (FAILED(hr)) {
673 }
674 }
675
676 return 0;
677 }
678
681 .name = "D3D12VA",
682
685
696
698 };