FFmpeg
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 "pixdesc.h"
31 #include "pixfmt.h"
32 #include "thread.h"
33 #include "compat/w32dlfcn.h"
34 #include <dxgi1_3.h>
35 
36 typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY2)(UINT Flags, REFIID riid, void **ppFactory);
37 
38 typedef struct D3D12VAFramesContext {
39  /**
40  * The public AVD3D12VAFramesContext. See hwcontext_d3d12va.h for it.
41  */
43 
44  ID3D12Resource *staging_download_buffer;
45  ID3D12Resource *staging_upload_buffer;
46  ID3D12CommandQueue *command_queue;
47  ID3D12CommandAllocator *command_allocator;
48  ID3D12GraphicsCommandList *command_list;
52 
53 typedef struct D3D12VADevicePriv {
54  /**
55  * The public AVD3D12VADeviceContext. See hwcontext_d3d12va.h for it.
56  */
58  HANDLE d3d12lib;
59  HANDLE dxgilib;
61  PFN_D3D12_CREATE_DEVICE create_device;
62  PFN_D3D12_GET_DEBUG_INTERFACE get_debug_interface;
64 
65 static const struct {
66  DXGI_FORMAT d3d_format;
68 } supported_formats[] = {
69  { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 },
70  { DXGI_FORMAT_P010, AV_PIX_FMT_P010 },
71 };
72 
73 static void d3d12va_default_lock(void *ctx)
74 {
75  WaitForSingleObjectEx(ctx, INFINITE, FALSE);
76 }
77 
78 static void d3d12va_default_unlock(void *ctx)
79 {
80  ReleaseMutex(ctx);
81 }
82 
84 {
85  uint64_t completion = ID3D12Fence_GetCompletedValue(psync_ctx->fence);
86  if (completion < psync_ctx->fence_value) {
87  if (FAILED(ID3D12Fence_SetEventOnCompletion(psync_ctx->fence, psync_ctx->fence_value, psync_ctx->event)))
88  return AVERROR(EINVAL);
89 
90  WaitForSingleObjectEx(psync_ctx->event, INFINITE, FALSE);
91  }
92 
93  return 0;
94 }
95 
96 static inline int d3d12va_wait_queue_idle(AVD3D12VASyncContext *psync_ctx, ID3D12CommandQueue *command_queue)
97 {
98  DX_CHECK(ID3D12CommandQueue_Signal(command_queue, psync_ctx->fence, ++psync_ctx->fence_value));
99  return d3d12va_fence_completion(psync_ctx);
100 
101 fail:
102  return AVERROR(EINVAL);
103 }
104 
105 static int d3d12va_create_staging_buffer_resource(AVHWFramesContext *ctx, D3D12_RESOURCE_STATES states,
106  ID3D12Resource **ppResource, int download)
107 {
108  AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
109  D3D12VAFramesContext *s = ctx->hwctx;
110  D3D12_HEAP_PROPERTIES props = { .Type = download ? D3D12_HEAP_TYPE_READBACK : D3D12_HEAP_TYPE_UPLOAD };
111  D3D12_RESOURCE_DESC desc = {
112  .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
113  .Alignment = 0,
114  .Width = s->luma_component_size + (s->luma_component_size >> 1),
115  .Height = 1,
116  .DepthOrArraySize = 1,
117  .MipLevels = 1,
118  .Format = DXGI_FORMAT_UNKNOWN,
119  .SampleDesc = { .Count = 1, .Quality = 0 },
120  .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
121  .Flags = D3D12_RESOURCE_FLAG_NONE,
122  };
123 
124  if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->device, &props, D3D12_HEAP_FLAG_NONE, &desc,
125  states, NULL, &IID_ID3D12Resource, (void **)ppResource))) {
126  av_log(ctx, AV_LOG_ERROR, "Could not create the staging buffer resource\n");
127  return AVERROR_UNKNOWN;
128  }
129 
130  return 0;
131 }
132 
134 {
135  AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
136  D3D12VAFramesContext *s = ctx->hwctx;
137  AVD3D12VAFramesContext *frames_hwctx = &s->p;
138 
139  D3D12_COMMAND_QUEUE_DESC queue_desc = {
140  .Type = D3D12_COMMAND_LIST_TYPE_COPY,
141  .Priority = 0,
142  .NodeMask = 0,
143  };
144 
145  s->luma_component_size = FFALIGN(ctx->width * (frames_hwctx->format == DXGI_FORMAT_P010 ? 2 : 1),
146  D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * ctx->height;
147 
148  DX_CHECK(ID3D12Device_CreateFence(device_hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
149  &IID_ID3D12Fence, (void **)&s->sync_ctx.fence));
150 
151  s->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
152  if (!s->sync_ctx.event)
153  goto fail;
154 
155  DX_CHECK(ID3D12Device_CreateCommandQueue(device_hwctx->device, &queue_desc,
156  &IID_ID3D12CommandQueue, (void **)&s->command_queue));
157 
158  DX_CHECK(ID3D12Device_CreateCommandAllocator(device_hwctx->device, queue_desc.Type,
159  &IID_ID3D12CommandAllocator, (void **)&s->command_allocator));
160 
161  DX_CHECK(ID3D12Device_CreateCommandList(device_hwctx->device, 0, queue_desc.Type,
162  s->command_allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)&s->command_list));
163 
164  DX_CHECK(ID3D12GraphicsCommandList_Close(s->command_list));
165 
166  ID3D12CommandQueue_ExecuteCommandLists(s->command_queue, 1, (ID3D12CommandList **)&s->command_list);
167 
168  return d3d12va_wait_queue_idle(&s->sync_ctx, s->command_queue);
169 
170 fail:
171  return AVERROR(EINVAL);
172 }
173 
175 {
176  D3D12VAFramesContext *s = ctx->hwctx;
177 
178  D3D12_OBJECT_RELEASE(s->sync_ctx.fence);
179  if (s->sync_ctx.event)
180  CloseHandle(s->sync_ctx.event);
181 
182  D3D12_OBJECT_RELEASE(s->staging_download_buffer);
183  D3D12_OBJECT_RELEASE(s->staging_upload_buffer);
184  D3D12_OBJECT_RELEASE(s->command_allocator);
185  D3D12_OBJECT_RELEASE(s->command_list);
186  D3D12_OBJECT_RELEASE(s->command_queue);
187 }
188 
189 static int d3d12va_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
190 {
191  HRESULT hr;
192  int nb_sw_formats = 0;
193  AVD3D12VADeviceContext *device_hwctx = ctx->hwctx;
194 
196  sizeof(*constraints->valid_sw_formats));
197  if (!constraints->valid_sw_formats)
198  return AVERROR(ENOMEM);
199 
200  for (int i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
201  D3D12_FEATURE_DATA_FORMAT_SUPPORT format_support = { supported_formats[i].d3d_format };
202  hr = ID3D12Device_CheckFeatureSupport(device_hwctx->device, D3D12_FEATURE_FORMAT_SUPPORT, &format_support, sizeof(format_support));
203  if (SUCCEEDED(hr) && (format_support.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D))
204  constraints->valid_sw_formats[nb_sw_formats++] = supported_formats[i].pix_fmt;
205  }
206  constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE;
207 
208  constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
209  if (!constraints->valid_hw_formats)
210  return AVERROR(ENOMEM);
211 
212  constraints->valid_hw_formats[0] = AV_PIX_FMT_D3D12;
213  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
214 
215  return 0;
216 }
217 
218 static void free_texture(void *opaque, uint8_t *data)
219 {
221 
222  D3D12_OBJECT_RELEASE(frame->texture);
223  D3D12_OBJECT_RELEASE(frame->sync_ctx.fence);
224  if (frame->sync_ctx.event)
225  CloseHandle(frame->sync_ctx.event);
226 
227  av_freep(&data);
228 }
229 
230 static AVBufferRef *d3d12va_pool_alloc(void *opaque, size_t size)
231 {
233  AVD3D12VAFramesContext *hwctx = ctx->hwctx;
234  AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
235 
236  AVBufferRef *buf;
238  D3D12_HEAP_PROPERTIES props = { .Type = D3D12_HEAP_TYPE_DEFAULT };
239  D3D12_RESOURCE_DESC desc = {
240  .Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
241  .Alignment = 0,
242  .Width = ctx->width,
243  .Height = ctx->height,
244  .DepthOrArraySize = 1,
245  .MipLevels = 1,
246  .Format = hwctx->format,
247  .SampleDesc = {.Count = 1, .Quality = 0 },
248  .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
249  .Flags = D3D12_RESOURCE_FLAG_NONE,
250  };
251 
252  frame = av_mallocz(sizeof(AVD3D12VAFrame));
253  if (!frame)
254  return NULL;
255 
256  if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->device, &props, D3D12_HEAP_FLAG_NONE, &desc,
257  D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&frame->texture))) {
258  av_log(ctx, AV_LOG_ERROR, "Could not create the texture\n");
259  goto fail;
260  }
261 
262  DX_CHECK(ID3D12Device_CreateFence(device_hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
263  &IID_ID3D12Fence, (void **)&frame->sync_ctx.fence));
264 
265  frame->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
266  if (!frame->sync_ctx.event)
267  goto fail;
268 
269  buf = av_buffer_create((uint8_t *)frame, sizeof(frame), free_texture, NULL, 0);
270  if (!buf)
271  goto fail;
272 
273  return buf;
274 
275 fail:
276  free_texture(NULL, (uint8_t *)frame);
277  return NULL;
278 }
279 
281 {
282  AVD3D12VAFramesContext *hwctx = ctx->hwctx;
283  int i;
284 
285  for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
286  if (ctx->sw_format == supported_formats[i].pix_fmt) {
287  if (hwctx->format != DXGI_FORMAT_UNKNOWN &&
288  hwctx->format != supported_formats[i].d3d_format)
289  av_log(ctx, AV_LOG_WARNING, "Incompatible DXGI format provided by user, will be overided\n");
290  hwctx->format = supported_formats[i].d3d_format;
291  break;
292  }
293  }
295  av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n",
296  av_get_pix_fmt_name(ctx->sw_format));
297  return AVERROR(EINVAL);
298  }
299 
302 
303  if (!ffhwframesctx(ctx)->pool_internal)
304  return AVERROR(ENOMEM);
305 
306  return 0;
307 }
308 
310 {
311  int ret;
312 
313  frame->buf[0] = av_buffer_pool_get(ctx->pool);
314  if (!frame->buf[0])
315  return AVERROR(ENOMEM);
316 
318  ctx->sw_format, ctx->width, ctx->height,
319  D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
320  if (ret < 0)
321  return ret;
322 
323  frame->data[0] = frame->buf[0]->data;
325  frame->width = ctx->width;
326  frame->height = ctx->height;
327 
328  return 0;
329 }
330 
333  enum AVPixelFormat **formats)
334 {
335  enum AVPixelFormat *fmts;
336 
337  fmts = av_malloc_array(2, sizeof(*fmts));
338  if (!fmts)
339  return AVERROR(ENOMEM);
340 
341  fmts[0] = ctx->sw_format;
342  fmts[1] = AV_PIX_FMT_NONE;
343 
344  *formats = fmts;
345 
346  return 0;
347 }
348 
350  const AVFrame *src)
351 {
352  AVD3D12VADeviceContext *hwctx = ctx->device_ctx->hwctx;
353  D3D12VAFramesContext *s = ctx->hwctx;
354  AVD3D12VAFramesContext *frames_hwctx = &s->p;
355 
356  int ret;
357  int download = src->format == AV_PIX_FMT_D3D12;
358  const AVFrame *frame = download ? src : dst;
359  const AVFrame *other = download ? dst : src;
360 
362  ID3D12Resource *texture = (ID3D12Resource *)f->texture;
363 
364  uint8_t *mapped_data;
365  uint8_t *data[4];
366  int linesizes[4];
367 
368  D3D12_TEXTURE_COPY_LOCATION staging_y_location = { 0 };
369  D3D12_TEXTURE_COPY_LOCATION staging_uv_location = { 0 };
370 
371  D3D12_TEXTURE_COPY_LOCATION texture_y_location = {
372  .pResource = texture,
373  .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
374  .SubresourceIndex = 0,
375  };
376 
377  D3D12_TEXTURE_COPY_LOCATION texture_uv_location = {
378  .pResource = texture,
379  .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
380  .SubresourceIndex = 1,
381  };
382 
383  D3D12_RESOURCE_BARRIER barrier = {
384  .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
385  .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
386  .Transition = {
387  .pResource = texture,
388  .StateBefore = D3D12_RESOURCE_STATE_COMMON,
389  .StateAfter = download ? D3D12_RESOURCE_STATE_COPY_SOURCE : D3D12_RESOURCE_STATE_COPY_DEST,
390  .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
391  },
392  };
393 
394  if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format)
395  return AVERROR(EINVAL);
396 
397  hwctx->lock(hwctx->lock_ctx);
398 
399  if (!s->command_queue) {
401  if (ret < 0)
402  goto fail;
403  }
404 
405  for (int i = 0; i < 4; i++)
406  linesizes[i] = FFALIGN(frame->width * (frames_hwctx->format == DXGI_FORMAT_P010 ? 2 : 1),
407  D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
408 
409  staging_y_location = (D3D12_TEXTURE_COPY_LOCATION) {
410  .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
411  .PlacedFootprint = {
412  .Offset = 0,
413  .Footprint = {
414  .Format = frames_hwctx->format == DXGI_FORMAT_P010 ?
415  DXGI_FORMAT_R16_UNORM : DXGI_FORMAT_R8_UNORM,
416  .Width = ctx->width,
417  .Height = ctx->height,
418  .Depth = 1,
419  .RowPitch = linesizes[0],
420  },
421  },
422  };
423 
424  staging_uv_location = (D3D12_TEXTURE_COPY_LOCATION) {
425  .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
426  .PlacedFootprint = {
427  .Offset = s->luma_component_size,
428  .Footprint = {
429  .Format = frames_hwctx->format == DXGI_FORMAT_P010 ?
430  DXGI_FORMAT_R16G16_UNORM : DXGI_FORMAT_R8G8_UNORM,
431  .Width = ctx->width >> 1,
432  .Height = ctx->height >> 1,
433  .Depth = 1,
434  .RowPitch = linesizes[0],
435  },
436  },
437  };
438 
439  DX_CHECK(ID3D12CommandAllocator_Reset(s->command_allocator));
440 
441  DX_CHECK(ID3D12GraphicsCommandList_Reset(s->command_list, s->command_allocator, NULL));
442 
443  if (download) {
444  if (!s->staging_download_buffer) {
445  ret = d3d12va_create_staging_buffer_resource(ctx, D3D12_RESOURCE_STATE_COPY_DEST,
446  &s->staging_download_buffer, 1);
447  if (ret < 0) {
448  goto fail;
449  }
450  }
451 
452  staging_y_location.pResource = staging_uv_location.pResource = s->staging_download_buffer;
453 
454  ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
455 
456  ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
457  &staging_y_location, 0, 0, 0,
458  &texture_y_location, NULL);
459 
460  ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
461  &staging_uv_location, 0, 0, 0,
462  &texture_uv_location, NULL);
463 
464  barrier.Transition.StateBefore = barrier.Transition.StateAfter;
465  barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
466  ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
467 
468  DX_CHECK(ID3D12GraphicsCommandList_Close(s->command_list));
469 
470  DX_CHECK(ID3D12CommandQueue_Wait(s->command_queue, f->sync_ctx.fence, f->sync_ctx.fence_value));
471 
472  ID3D12CommandQueue_ExecuteCommandLists(s->command_queue, 1, (ID3D12CommandList **)&s->command_list);
473 
474  ret = d3d12va_wait_queue_idle(&s->sync_ctx, s->command_queue);
475  if (ret < 0)
476  goto fail;
477 
478  DX_CHECK(ID3D12Resource_Map(s->staging_download_buffer, 0, NULL, (void **)&mapped_data));
479  av_image_fill_pointers(data, ctx->sw_format, ctx->height, mapped_data, linesizes);
480 
481  av_image_copy2(dst->data, dst->linesize, data, linesizes,
482  ctx->sw_format, ctx->width, ctx->height);
483 
484  ID3D12Resource_Unmap(s->staging_download_buffer, 0, NULL);
485  } else {
486  if (!s->staging_upload_buffer) {
487  ret = d3d12va_create_staging_buffer_resource(ctx, D3D12_RESOURCE_STATE_GENERIC_READ,
488  &s->staging_upload_buffer, 0);
489  if (ret < 0) {
490  goto fail;
491  }
492  }
493 
494  staging_y_location.pResource = staging_uv_location.pResource = s->staging_upload_buffer;
495 
496  DX_CHECK(ID3D12Resource_Map(s->staging_upload_buffer, 0, NULL, (void **)&mapped_data));
497  av_image_fill_pointers(data, ctx->sw_format, ctx->height, mapped_data, linesizes);
498 
499  av_image_copy2(data, linesizes, src->data, src->linesize,
500  ctx->sw_format, ctx->width, ctx->height);
501 
502  ID3D12Resource_Unmap(s->staging_upload_buffer, 0, NULL);
503 
504  ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
505 
506  ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
507  &texture_y_location, 0, 0, 0,
508  &staging_y_location, NULL);
509 
510  ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
511  &texture_uv_location, 0, 0, 0,
512  &staging_uv_location, NULL);
513 
514  barrier.Transition.StateBefore = barrier.Transition.StateAfter;
515  barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
516  ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
517 
518  DX_CHECK(ID3D12GraphicsCommandList_Close(s->command_list));
519 
520  ID3D12CommandQueue_ExecuteCommandLists(s->command_queue, 1, (ID3D12CommandList **)&s->command_list);
521 
522  ret = d3d12va_wait_queue_idle(&s->sync_ctx, s->command_queue);
523  if (ret < 0)
524  goto fail;
525  }
526 
527  hwctx->unlock(hwctx->lock_ctx);
528 
529  return 0;
530 
531 fail:
532  hwctx->unlock(hwctx->lock_ctx);
533  return AVERROR(EINVAL);
534 }
535 
537 {
538  D3D12VADevicePriv *priv = hwdev->hwctx;
539 
540 #if !HAVE_UWP
541  priv->d3d12lib = dlopen("d3d12.dll", 0);
542  priv->dxgilib = dlopen("dxgi.dll", 0);
543 
544  if (!priv->d3d12lib || !priv->dxgilib)
545  goto fail;
546 
547  priv->create_device = (PFN_D3D12_CREATE_DEVICE)GetProcAddress(priv->d3d12lib, "D3D12CreateDevice");
548  if (!priv->create_device)
549  goto fail;
550 
551  priv->create_dxgi_factory2 = (PFN_CREATE_DXGI_FACTORY2)GetProcAddress(priv->dxgilib, "CreateDXGIFactory2");
552  if (!priv->create_dxgi_factory2)
553  goto fail;
554 
555  priv->get_debug_interface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(priv->d3d12lib, "D3D12GetDebugInterface");
556 #else
557  priv->create_device = (PFN_D3D12_CREATE_DEVICE) D3D12CreateDevice;
558  priv->create_dxgi_factory2 = (PFN_CREATE_DXGI_FACTORY2) CreateDXGIFactory2;
559  priv->get_debug_interface = (PFN_D3D12_GET_DEBUG_INTERFACE) D3D12GetDebugInterface;
560 #endif
561  return 0;
562 
563 fail:
564  av_log(hwdev, AV_LOG_ERROR, "Failed to load D3D12 library or its functions\n");
565  return AVERROR_UNKNOWN;
566 }
567 
569 {
570  D3D12VADevicePriv *priv = hwdev->hwctx;
571  AVD3D12VADeviceContext *ctx = &priv->p;
572 
573  D3D12_OBJECT_RELEASE(ctx->device);
574 
575  if (priv->d3d12lib)
576  dlclose(priv->d3d12lib);
577 
578  if (priv->dxgilib)
579  dlclose(priv->dxgilib);
580 }
581 
583 {
584  AVD3D12VADeviceContext *ctx = hwdev->hwctx;
585 
586  if (!ctx->lock) {
587  ctx->lock_ctx = CreateMutex(NULL, 0, NULL);
588  if (ctx->lock_ctx == INVALID_HANDLE_VALUE) {
589  av_log(NULL, AV_LOG_ERROR, "Failed to create a mutex\n");
590  return AVERROR(EINVAL);
591  }
592  ctx->lock = d3d12va_default_lock;
593  ctx->unlock = d3d12va_default_unlock;
594  }
595 
596  if (!ctx->video_device)
597  DX_CHECK(ID3D12Device_QueryInterface(ctx->device, &IID_ID3D12VideoDevice, (void **)&ctx->video_device));
598 
599  return 0;
600 
601 fail:
602  return AVERROR(EINVAL);
603 }
604 
606 {
607  AVD3D12VADeviceContext *device_hwctx = hwdev->hwctx;
608 
609  D3D12_OBJECT_RELEASE(device_hwctx->video_device);
610 
611  if (device_hwctx->lock == d3d12va_default_lock) {
612  CloseHandle(device_hwctx->lock_ctx);
613  device_hwctx->lock_ctx = INVALID_HANDLE_VALUE;
614  device_hwctx->lock = NULL;
615  }
616 }
617 
618 static int d3d12va_device_create(AVHWDeviceContext *hwdev, const char *device,
619  AVDictionary *opts, int flags)
620 {
621  D3D12VADevicePriv *priv = hwdev->hwctx;
622  AVD3D12VADeviceContext *ctx = &priv->p;
623 
624  HRESULT hr;
625  UINT create_flags = 0;
626  IDXGIAdapter *pAdapter = NULL;
627 
628  int ret;
629  int is_debug = !!av_dict_get(opts, "debug", NULL, 0);
630 
631  hwdev->free = d3d12va_device_free;
632 
633  ret = d3d12va_load_functions(hwdev);
634  if (ret < 0)
635  return ret;
636 
637  if (is_debug) {
638  ID3D12Debug *pDebug;
639  if (priv->get_debug_interface && SUCCEEDED(priv->get_debug_interface(&IID_ID3D12Debug, (void **)&pDebug))) {
640  create_flags |= DXGI_CREATE_FACTORY_DEBUG;
641  ID3D12Debug_EnableDebugLayer(pDebug);
642  D3D12_OBJECT_RELEASE(pDebug);
643  av_log(hwdev, AV_LOG_INFO, "D3D12 debug layer is enabled!\n");
644  }
645  }
646 
647  if (!ctx->device) {
648  IDXGIFactory2 *pDXGIFactory = NULL;
649 
650  hr = priv->create_dxgi_factory2(create_flags, &IID_IDXGIFactory2, (void **)&pDXGIFactory);
651  if (SUCCEEDED(hr)) {
652  int adapter = device ? atoi(device) : 0;
653  if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
654  pAdapter = NULL;
655  IDXGIFactory2_Release(pDXGIFactory);
656  }
657 
658  if (pAdapter) {
659  DXGI_ADAPTER_DESC desc;
660  hr = IDXGIAdapter2_GetDesc(pAdapter, &desc);
661  if (!FAILED(hr)) {
662  av_log(ctx, AV_LOG_INFO, "Using device %04x:%04x (%ls).\n",
663  desc.VendorId, desc.DeviceId, desc.Description);
664  }
665  }
666 
667  hr = priv->create_device((IUnknown *)pAdapter, D3D_FEATURE_LEVEL_12_0, &IID_ID3D12Device, (void **)&ctx->device);
668  D3D12_OBJECT_RELEASE(pAdapter);
669  if (FAILED(hr)) {
670  av_log(ctx, AV_LOG_ERROR, "Failed to create Direct 3D 12 device (%lx)\n", (long)hr);
671  return AVERROR_UNKNOWN;
672  }
673  }
674 
675  return 0;
676 }
677 
680  .name = "D3D12VA",
681 
682  .device_hwctx_size = sizeof(D3D12VADevicePriv),
683  .frames_hwctx_size = sizeof(D3D12VAFramesContext),
684 
685  .device_create = d3d12va_device_create,
686  .device_init = d3d12va_device_init,
687  .device_uninit = d3d12va_device_uninit,
688  .frames_get_constraints = d3d12va_frames_get_constraints,
689  .frames_init = d3d12va_frames_init,
690  .frames_uninit = d3d12va_frames_uninit,
691  .frames_get_buffer = d3d12va_get_buffer,
692  .transfer_get_formats = d3d12va_transfer_get_formats,
693  .transfer_data_to = d3d12va_transfer_data,
694  .transfer_data_from = d3d12va_transfer_data,
695 
696  .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_D3D12, AV_PIX_FMT_NONE },
697 };
formats
formats
Definition: signature.h:48
AVHWDeviceContext::hwctx
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:85
FFHWFramesContext::pool_internal
AVBufferPool * pool_internal
Definition: hwcontext_internal.h:101
AVD3D12VADeviceContext::device
ID3D12Device * device
Device used for objects creation and access.
Definition: hwcontext_d3d12va.h:54
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
d3d12va_transfer_data
static int d3d12va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_d3d12va.c:349
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
AVD3D12VADeviceContext::lock_ctx
void * lock_ctx
Definition: hwcontext_d3d12va.h:77
thread.h
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
d3d12va_frames_get_constraints
static int d3d12va_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
Definition: hwcontext_d3d12va.c:189
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:344
pixdesc.h
AVFrame::width
int width
Definition: frame.h:416
D3D12VADevicePriv
Definition: hwcontext_d3d12va.c:53
data
const char data[16]
Definition: mxf.c:148
d3d12va_device_create
static int d3d12va_device_create(AVHWDeviceContext *hwdev, const char *device, AVDictionary *opts, int flags)
Definition: hwcontext_d3d12va.c:618
D3D12VAFramesContext::sync_ctx
AVD3D12VASyncContext sync_ctx
Definition: hwcontext_d3d12va.c:49
AVDictionary
Definition: dict.c:34
AVHWFramesConstraints::valid_hw_formats
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:446
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
D3D12VAFramesContext::staging_download_buffer
ID3D12Resource * staging_download_buffer
Definition: hwcontext_d3d12va.c:44
AVFrame::buf
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:557
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:365
d3d_format
DXGI_FORMAT d3d_format
Definition: hwcontext_d3d12va.c:66
AVHWFramesConstraints
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:441
D3D12VADevicePriv::d3d12lib
HANDLE d3d12lib
Definition: hwcontext_d3d12va.c:58
AVHWDeviceContext::free
void(* free)(struct AVHWDeviceContext *ctx)
This field may be set by the caller before calling av_hwdevice_ctx_init().
Definition: hwcontext.h:97
fail
#define fail()
Definition: checkasm.h:179
av_buffer_pool_init2
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
D3D12VADevicePriv::get_debug_interface
PFN_D3D12_GET_DEBUG_INTERFACE get_debug_interface
Definition: hwcontext_d3d12va.c:62
av_image_fill_pointers
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
d3d12va_default_unlock
static void d3d12va_default_unlock(void *ctx)
Definition: hwcontext_d3d12va.c:78
supported_formats
static const struct @364 supported_formats[]
AVHWDeviceContext
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:60
HWContextType::type
enum AVHWDeviceType type
Definition: hwcontext_internal.h:30
ffhwframesctx
static FFHWFramesContext * ffhwframesctx(AVHWFramesContext *ctx)
Definition: hwcontext_internal.h:115
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
AVHWFramesConstraints::valid_sw_formats
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:453
av_dict_get
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:62
av_buffer_pool_get
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:384
d3d12va_device_init
static int d3d12va_device_init(AVHWDeviceContext *hwdev)
Definition: hwcontext_d3d12va.c:582
s
#define s(width, name)
Definition: cbs_vp9.c:198
D3D12_OBJECT_RELEASE
#define D3D12_OBJECT_RELEASE(pInterface)
A release macro used by D3D12 objects highly frequently.
Definition: hwcontext_d3d12va_internal.h:51
d3d12va_pool_alloc
static AVBufferRef * d3d12va_pool_alloc(void *opaque, size_t size)
Definition: hwcontext_d3d12va.c:230
AVD3D12VADeviceContext::unlock
void(* unlock)(void *lock_ctx)
Definition: hwcontext_d3d12va.h:76
ctx
AVFormatContext * ctx
Definition: movenc.c:48
AVD3D12VASyncContext
This struct is used to sync d3d12 execution.
Definition: hwcontext_d3d12va.h:84
AVD3D12VASyncContext::fence
ID3D12Fence * fence
D3D12 fence object.
Definition: hwcontext_d3d12va.h:88
frame
static AVFrame * frame
Definition: demux_decode.c:54
opts
AVDictionary * opts
Definition: movenc.c:50
D3D12VAFramesContext::staging_upload_buffer
ID3D12Resource * staging_upload_buffer
Definition: hwcontext_d3d12va.c:45
NULL
#define NULL
Definition: coverity.c:32
d3d12va_device_free
static void d3d12va_device_free(AVHWDeviceContext *hwdev)
Definition: hwcontext_d3d12va.c:568
AVD3D12VAFramesContext
This struct is allocated as AVHWFramesContext.hwctx.
Definition: hwcontext_d3d12va.h:126
AV_PIX_FMT_D3D12
@ AV_PIX_FMT_D3D12
Hardware surfaces for Direct3D 12.
Definition: pixfmt.h:440
hwcontext_d3d12va.h
av_buffer_create
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
AVD3D12VADeviceContext::video_device
ID3D12VideoDevice * video_device
If unset, this will be set from the device field on init.
Definition: hwcontext_d3d12va.h:62
f
f
Definition: af_crystalizer.c:121
AV_HWDEVICE_TYPE_D3D12VA
@ AV_HWDEVICE_TYPE_D3D12VA
Definition: hwcontext.h:40
av_image_fill_arrays
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
d3d12va_fence_completion
static int d3d12va_fence_completion(AVD3D12VASyncContext *psync_ctx)
Definition: hwcontext_d3d12va.c:83
size
int size
Definition: twinvq_data.h:10344
free_texture
static void free_texture(void *opaque, uint8_t *data)
Definition: hwcontext_d3d12va.c:218
D3D12VAFramesContext::p
AVD3D12VAFramesContext p
The public AVD3D12VAFramesContext.
Definition: hwcontext_d3d12va.c:42
AVFrame::format
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:431
D3D12VADevicePriv::p
AVD3D12VADeviceContext p
The public AVD3D12VADeviceContext.
Definition: hwcontext_d3d12va.c:57
d3d12va_frames_init
static int d3d12va_frames_init(AVHWFramesContext *ctx)
Definition: hwcontext_d3d12va.c:280
AVD3D12VAFrame
D3D12VA frame descriptor for pool allocation.
Definition: hwcontext_d3d12va.h:106
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
D3D12VADevicePriv::create_dxgi_factory2
PFN_CREATE_DXGI_FACTORY2 create_dxgi_factory2
Definition: hwcontext_d3d12va.c:60
d3d12va_load_functions
static int d3d12va_load_functions(AVHWDeviceContext *hwdev)
Definition: hwcontext_d3d12va.c:536
D3D12VAFramesContext::command_allocator
ID3D12CommandAllocator * command_allocator
Definition: hwcontext_d3d12va.c:47
AVD3D12VADeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_d3d12va.h:43
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:31
common.h
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:254
d3d12va_frames_uninit
static void d3d12va_frames_uninit(AVHWFramesContext *ctx)
Definition: hwcontext_d3d12va.c:174
AVHWFrameTransferDirection
AVHWFrameTransferDirection
Definition: hwcontext.h:403
d3d12va_default_lock
static void d3d12va_default_lock(void *ctx)
Definition: hwcontext_d3d12va.c:73
AVD3D12VAFramesContext::format
DXGI_FORMAT format
DXGI_FORMAT format.
Definition: hwcontext_d3d12va.h:131
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:115
D3D12VADevicePriv::create_device
PFN_D3D12_CREATE_DEVICE create_device
Definition: hwcontext_d3d12va.c:61
ret
ret
Definition: filter_design.txt:187
pixfmt.h
AV_PIX_FMT_NV12
@ 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
D3D12VADevicePriv::dxgilib
HANDLE dxgilib
Definition: hwcontext_d3d12va.c:59
d3d12va_wait_queue_idle
static int d3d12va_wait_queue_idle(AVD3D12VASyncContext *psync_ctx, ID3D12CommandQueue *command_queue)
Definition: hwcontext_d3d12va.c:96
d3d12va_get_buffer
static int d3d12va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
Definition: hwcontext_d3d12va.c:309
AVFrame::hw_frames_ctx
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame.
Definition: frame.h:695
AVFrame::height
int height
Definition: frame.h:416
ff_hwcontext_type_d3d12va
const HWContextType ff_hwcontext_type_d3d12va
Definition: hwcontext_d3d12va.c:678
AVD3D12VASyncContext::event
HANDLE event
A handle to the event object that's raised when the fence reaches a certain value.
Definition: hwcontext_d3d12va.h:94
D3D12VAFramesContext
Definition: hwcontext_d3d12va.c:38
D3D12VAFramesContext::command_list
ID3D12GraphicsCommandList * command_list
Definition: hwcontext_d3d12va.c:48
av_image_copy2
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
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
d3d12va_create_staging_buffer_resource
static int d3d12va_create_staging_buffer_resource(AVHWFramesContext *ctx, D3D12_RESOURCE_STATES states, ID3D12Resource **ppResource, int download)
Definition: hwcontext_d3d12va.c:105
pix_fmt
enum AVPixelFormat pix_fmt
Definition: hwcontext_d3d12va.c:67
AVD3D12VADeviceContext::lock
void(* lock)(void *lock_ctx)
Callbacks for locking.
Definition: hwcontext_d3d12va.h:75
AV_PIX_FMT_P010
#define AV_PIX_FMT_P010
Definition: pixfmt.h:528
D3D12VAFramesContext::luma_component_size
UINT luma_component_size
Definition: hwcontext_d3d12va.c:50
desc
const char * desc
Definition: libsvtav1.c:75
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
hwcontext_internal.h
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
PFN_CREATE_DXGI_FACTORY2
HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY2)(UINT Flags, REFIID riid, void **ppFactory)
Definition: hwcontext_d3d12va.c:36
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
imgutils.h
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
hwcontext.h
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:389
DX_CHECK
#define DX_CHECK(hr)
A check macro used by D3D12 functions highly frequently.
Definition: hwcontext_d3d12va_internal.h:40
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
HWContextType
Definition: hwcontext_internal.h:29
AVD3D12VASyncContext::fence_value
uint64_t fence_value
The fence value used for sync.
Definition: hwcontext_d3d12va.h:99
D3D12VAFramesContext::command_queue
ID3D12CommandQueue * command_queue
Definition: hwcontext_d3d12va.c:46
hwcontext_d3d12va_internal.h
d3d12va_create_helper_objects
static int d3d12va_create_helper_objects(AVHWFramesContext *ctx)
Definition: hwcontext_d3d12va.c:133
d3d12va_transfer_get_formats
static int d3d12va_transfer_get_formats(AVHWFramesContext *ctx, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
Definition: hwcontext_d3d12va.c:331
w32dlfcn.h
d3d12va_device_uninit
static void d3d12va_device_uninit(AVHWDeviceContext *hwdev)
Definition: hwcontext_d3d12va.c:605
av_get_pix_fmt_name
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:2882