hwcontext_d3d11va.c (25174B)
1 /* 2 * This file is part of FFmpeg. 3 * 4 * FFmpeg is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * FFmpeg is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with FFmpeg; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 #include "config.h" 20 21 #include <windows.h> 22 23 #define COBJMACROS 24 25 #include <initguid.h> 26 #include <d3d11.h> 27 #include <dxgi1_2.h> 28 29 #if HAVE_DXGIDEBUG_H 30 #include <dxgidebug.h> 31 #endif 32 33 #include "avassert.h" 34 #include "common.h" 35 #include "hwcontext.h" 36 #include "hwcontext_d3d11va.h" 37 #include "hwcontext_internal.h" 38 #include "imgutils.h" 39 #include "mem.h" 40 #include "pixdesc.h" 41 #include "pixfmt.h" 42 #include "thread.h" 43 #include "compat/w32dlfcn.h" 44 45 typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); 46 47 static AVOnce functions_loaded = AV_ONCE_INIT; 48 49 static PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory; 50 static PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice; 51 52 static av_cold void load_functions(void) 53 { 54 #if !HAVE_UWP 55 // We let these "leak" - this is fine, as unloading has no great benefit, and 56 // Windows will mark a DLL as loaded forever if its internal refcount overflows 57 // from too many LoadLibrary calls. 58 HANDLE d3dlib, dxgilib; 59 60 d3dlib = dlopen("d3d11.dll", 0); 61 dxgilib = dlopen("dxgi.dll", 0); 62 if (!d3dlib || !dxgilib) 63 return; 64 65 mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) GetProcAddress(d3dlib, "D3D11CreateDevice"); 66 mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory1"); 67 if (!mCreateDXGIFactory) 68 mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory"); 69 #else 70 // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't available, 71 // only CreateDXGIFactory1 72 mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) D3D11CreateDevice; 73 mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) CreateDXGIFactory1; 74 #endif 75 } 76 77 typedef struct D3D11VAFramesContext { 78 /** 79 * The public AVD3D11VAFramesContext. See hwcontext_d3d11va.h for it. 80 */ 81 AVD3D11VAFramesContext p; 82 83 int nb_surfaces; 84 int nb_surfaces_used; 85 86 DXGI_FORMAT format; 87 88 ID3D11Texture2D *staging_texture; 89 } D3D11VAFramesContext; 90 91 static const struct { 92 DXGI_FORMAT d3d_format; 93 enum AVPixelFormat pix_fmt; 94 } supported_formats[] = { 95 { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 }, 96 { DXGI_FORMAT_P010, AV_PIX_FMT_P010 }, 97 { DXGI_FORMAT_B8G8R8A8_UNORM, AV_PIX_FMT_BGRA }, 98 { DXGI_FORMAT_R10G10B10A2_UNORM, AV_PIX_FMT_X2BGR10 }, 99 { DXGI_FORMAT_R16G16B16A16_FLOAT, AV_PIX_FMT_RGBAF16 }, 100 { DXGI_FORMAT_AYUV, AV_PIX_FMT_VUYX }, 101 { DXGI_FORMAT_YUY2, AV_PIX_FMT_YUYV422 }, 102 { DXGI_FORMAT_Y210, AV_PIX_FMT_Y210 }, 103 { DXGI_FORMAT_Y410, AV_PIX_FMT_XV30 }, 104 { DXGI_FORMAT_P016, AV_PIX_FMT_P012 }, 105 { DXGI_FORMAT_Y216, AV_PIX_FMT_Y216 }, 106 { DXGI_FORMAT_Y416, AV_PIX_FMT_XV48 }, 107 // There is no 12bit pixel format defined in DXGI_FORMAT*, use 16bit to compatible 108 // with 12 bit AV_PIX_FMT* formats. 109 { DXGI_FORMAT_Y216, AV_PIX_FMT_Y212 }, 110 { DXGI_FORMAT_Y416, AV_PIX_FMT_XV36 }, 111 // Special opaque formats. The pix_fmt is merely a place holder, as the 112 // opaque format cannot be accessed directly. 113 { DXGI_FORMAT_420_OPAQUE, AV_PIX_FMT_YUV420P }, 114 }; 115 116 static void d3d11va_default_lock(void *ctx) 117 { 118 WaitForSingleObjectEx(ctx, INFINITE, FALSE); 119 } 120 121 static void d3d11va_default_unlock(void *ctx) 122 { 123 ReleaseMutex(ctx); 124 } 125 126 static void d3d11va_frames_uninit(AVHWFramesContext *ctx) 127 { 128 D3D11VAFramesContext *s = ctx->hwctx; 129 AVD3D11VAFramesContext *frames_hwctx = &s->p; 130 131 if (frames_hwctx->texture) 132 ID3D11Texture2D_Release(frames_hwctx->texture); 133 frames_hwctx->texture = NULL; 134 135 if (s->staging_texture) 136 ID3D11Texture2D_Release(s->staging_texture); 137 s->staging_texture = NULL; 138 139 av_freep(&frames_hwctx->texture_infos); 140 } 141 142 static int d3d11va_frames_get_constraints(AVHWDeviceContext *ctx, 143 const void *hwconfig, 144 AVHWFramesConstraints *constraints) 145 { 146 AVD3D11VADeviceContext *device_hwctx = ctx->hwctx; 147 int nb_sw_formats = 0; 148 HRESULT hr; 149 int i; 150 151 constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1, 152 sizeof(*constraints->valid_sw_formats)); 153 if (!constraints->valid_sw_formats) 154 return AVERROR(ENOMEM); 155 156 for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { 157 UINT format_support = 0; 158 hr = ID3D11Device_CheckFormatSupport(device_hwctx->device, supported_formats[i].d3d_format, &format_support); 159 if (SUCCEEDED(hr) && (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D)) 160 constraints->valid_sw_formats[nb_sw_formats++] = supported_formats[i].pix_fmt; 161 } 162 constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE; 163 164 constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); 165 if (!constraints->valid_hw_formats) 166 return AVERROR(ENOMEM); 167 168 constraints->valid_hw_formats[0] = AV_PIX_FMT_D3D11; 169 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; 170 171 return 0; 172 } 173 174 static void free_texture(void *opaque, uint8_t *data) 175 { 176 ID3D11Texture2D_Release((ID3D11Texture2D *)opaque); 177 av_free(data); 178 } 179 180 static AVBufferRef *wrap_texture_buf(AVHWFramesContext *ctx, ID3D11Texture2D *tex, int index) 181 { 182 AVBufferRef *buf; 183 AVD3D11FrameDescriptor *desc = av_mallocz(sizeof(*desc)); 184 D3D11VAFramesContext *s = ctx->hwctx; 185 AVD3D11VAFramesContext *frames_hwctx = &s->p; 186 if (!desc) { 187 ID3D11Texture2D_Release(tex); 188 return NULL; 189 } 190 191 if (s->nb_surfaces <= s->nb_surfaces_used) { 192 frames_hwctx->texture_infos = av_realloc_f(frames_hwctx->texture_infos, 193 s->nb_surfaces_used + 1, 194 sizeof(*frames_hwctx->texture_infos)); 195 if (!frames_hwctx->texture_infos) { 196 ID3D11Texture2D_Release(tex); 197 av_free(desc); 198 return NULL; 199 } 200 s->nb_surfaces = s->nb_surfaces_used + 1; 201 } 202 203 frames_hwctx->texture_infos[s->nb_surfaces_used].texture = tex; 204 frames_hwctx->texture_infos[s->nb_surfaces_used].index = index; 205 s->nb_surfaces_used++; 206 207 desc->texture = tex; 208 desc->index = index; 209 210 buf = av_buffer_create((uint8_t *)desc, sizeof(*desc), free_texture, tex, 0); 211 if (!buf) { 212 ID3D11Texture2D_Release(tex); 213 av_free(desc); 214 return NULL; 215 } 216 217 return buf; 218 } 219 220 static AVBufferRef *d3d11va_alloc_single(AVHWFramesContext *ctx) 221 { 222 D3D11VAFramesContext *s = ctx->hwctx; 223 AVD3D11VAFramesContext *hwctx = &s->p; 224 AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; 225 HRESULT hr; 226 ID3D11Texture2D *tex; 227 D3D11_TEXTURE2D_DESC texDesc = { 228 .Width = ctx->width, 229 .Height = ctx->height, 230 .MipLevels = 1, 231 .Format = s->format, 232 .SampleDesc = { .Count = 1 }, 233 .ArraySize = 1, 234 .Usage = D3D11_USAGE_DEFAULT, 235 .BindFlags = hwctx->BindFlags, 236 .MiscFlags = hwctx->MiscFlags, 237 }; 238 239 hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &tex); 240 if (FAILED(hr)) { 241 av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr); 242 return NULL; 243 } 244 245 return wrap_texture_buf(ctx, tex, 0); 246 } 247 248 static AVBufferRef *d3d11va_pool_alloc(void *opaque, size_t size) 249 { 250 AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; 251 D3D11VAFramesContext *s = ctx->hwctx; 252 AVD3D11VAFramesContext *hwctx = &s->p; 253 D3D11_TEXTURE2D_DESC texDesc; 254 255 if (!hwctx->texture) 256 return d3d11va_alloc_single(ctx); 257 258 ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc); 259 260 if (s->nb_surfaces_used >= texDesc.ArraySize) { 261 av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n"); 262 return NULL; 263 } 264 265 ID3D11Texture2D_AddRef(hwctx->texture); 266 return wrap_texture_buf(ctx, hwctx->texture, s->nb_surfaces_used); 267 } 268 269 static int d3d11va_frames_init(AVHWFramesContext *ctx) 270 { 271 AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; 272 D3D11VAFramesContext *s = ctx->hwctx; 273 AVD3D11VAFramesContext *hwctx = &s->p; 274 275 int i; 276 HRESULT hr; 277 D3D11_TEXTURE2D_DESC texDesc; 278 279 for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { 280 if (ctx->sw_format == supported_formats[i].pix_fmt) { 281 s->format = supported_formats[i].d3d_format; 282 break; 283 } 284 } 285 if (i == FF_ARRAY_ELEMS(supported_formats)) { 286 av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n", 287 av_get_pix_fmt_name(ctx->sw_format)); 288 return AVERROR(EINVAL); 289 } 290 291 texDesc = (D3D11_TEXTURE2D_DESC){ 292 .Width = ctx->width, 293 .Height = ctx->height, 294 .MipLevels = 1, 295 .Format = s->format, 296 .SampleDesc = { .Count = 1 }, 297 .ArraySize = ctx->initial_pool_size, 298 .Usage = D3D11_USAGE_DEFAULT, 299 .BindFlags = hwctx->BindFlags, 300 .MiscFlags = hwctx->MiscFlags, 301 }; 302 303 if (hwctx->texture) { 304 D3D11_TEXTURE2D_DESC texDesc2; 305 ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc2); 306 307 if (texDesc.Width != texDesc2.Width || 308 texDesc.Height != texDesc2.Height || 309 texDesc.Format != texDesc2.Format) { 310 av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n"); 311 return AVERROR(EINVAL); 312 } 313 314 ctx->initial_pool_size = texDesc2.ArraySize; 315 hwctx->BindFlags = texDesc2.BindFlags; 316 hwctx->MiscFlags = texDesc2.MiscFlags; 317 } else if (!(texDesc.BindFlags & D3D11_BIND_RENDER_TARGET) && texDesc.ArraySize > 0) { 318 hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture); 319 if (FAILED(hr)) { 320 av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr); 321 return AVERROR_UNKNOWN; 322 } 323 } 324 325 hwctx->texture_infos = av_realloc_f(NULL, ctx->initial_pool_size, sizeof(*hwctx->texture_infos)); 326 if (!hwctx->texture_infos) 327 return AVERROR(ENOMEM); 328 s->nb_surfaces = ctx->initial_pool_size; 329 330 ffhwframesctx(ctx)->pool_internal = 331 av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor), 332 ctx, d3d11va_pool_alloc, NULL); 333 if (!ffhwframesctx(ctx)->pool_internal) 334 return AVERROR(ENOMEM); 335 336 return 0; 337 } 338 339 static int d3d11va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) 340 { 341 AVD3D11FrameDescriptor *desc; 342 343 frame->buf[0] = av_buffer_pool_get(ctx->pool); 344 if (!frame->buf[0]) 345 return AVERROR(ENOMEM); 346 347 desc = (AVD3D11FrameDescriptor *)frame->buf[0]->data; 348 349 frame->data[0] = (uint8_t *)desc->texture; 350 frame->data[1] = (uint8_t *)desc->index; 351 frame->format = AV_PIX_FMT_D3D11; 352 frame->width = ctx->width; 353 frame->height = ctx->height; 354 355 return 0; 356 } 357 358 static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx, 359 enum AVHWFrameTransferDirection dir, 360 enum AVPixelFormat **formats) 361 { 362 D3D11VAFramesContext *s = ctx->hwctx; 363 enum AVPixelFormat *fmts; 364 365 fmts = av_malloc_array(2, sizeof(*fmts)); 366 if (!fmts) 367 return AVERROR(ENOMEM); 368 369 fmts[0] = ctx->sw_format; 370 fmts[1] = AV_PIX_FMT_NONE; 371 372 // Don't signal support for opaque formats. Actual access would fail. 373 if (s->format == DXGI_FORMAT_420_OPAQUE) 374 fmts[0] = AV_PIX_FMT_NONE; 375 376 *formats = fmts; 377 378 return 0; 379 } 380 381 static int d3d11va_create_staging_texture(AVHWFramesContext *ctx, DXGI_FORMAT format) 382 { 383 AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; 384 D3D11VAFramesContext *s = ctx->hwctx; 385 HRESULT hr; 386 D3D11_TEXTURE2D_DESC texDesc = { 387 .Width = ctx->width, 388 .Height = ctx->height, 389 .MipLevels = 1, 390 .Format = format, 391 .SampleDesc = { .Count = 1 }, 392 .ArraySize = 1, 393 .Usage = D3D11_USAGE_STAGING, 394 .CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE, 395 }; 396 397 hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &s->staging_texture); 398 if (FAILED(hr)) { 399 av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture (%lx)\n", (long)hr); 400 return AVERROR_UNKNOWN; 401 } 402 403 return 0; 404 } 405 406 static void fill_texture_ptrs(uint8_t *data[4], int linesize[4], 407 AVHWFramesContext *ctx, 408 D3D11_TEXTURE2D_DESC *desc, 409 D3D11_MAPPED_SUBRESOURCE *map) 410 { 411 int i; 412 413 for (i = 0; i < 4; i++) 414 linesize[i] = map->RowPitch; 415 416 av_image_fill_pointers(data, ctx->sw_format, desc->Height, 417 (uint8_t*)map->pData, linesize); 418 } 419 420 static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, 421 const AVFrame *src) 422 { 423 AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; 424 D3D11VAFramesContext *s = ctx->hwctx; 425 int download = src->format == AV_PIX_FMT_D3D11; 426 const AVFrame *frame = download ? src : dst; 427 const AVFrame *other = download ? dst : src; 428 // (The interface types are compatible.) 429 ID3D11Resource *texture = (ID3D11Resource *)(ID3D11Texture2D *)frame->data[0]; 430 int index = (intptr_t)frame->data[1]; 431 ID3D11Resource *staging; 432 int w = FFMIN(dst->width, src->width); 433 int h = FFMIN(dst->height, src->height); 434 uint8_t *map_data[4]; 435 int map_linesize[4]; 436 D3D11_TEXTURE2D_DESC desc; 437 D3D11_MAPPED_SUBRESOURCE map; 438 HRESULT hr; 439 int res; 440 441 if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format) 442 return AVERROR(EINVAL); 443 444 device_hwctx->lock(device_hwctx->lock_ctx); 445 446 if (!s->staging_texture) { 447 ID3D11Texture2D_GetDesc((ID3D11Texture2D *)texture, &desc); 448 res = d3d11va_create_staging_texture(ctx, desc.Format); 449 if (res < 0) 450 return res; 451 } 452 453 staging = (ID3D11Resource *)s->staging_texture; 454 455 ID3D11Texture2D_GetDesc(s->staging_texture, &desc); 456 457 if (download) { 458 ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context, 459 staging, 0, 0, 0, 0, 460 texture, index, NULL); 461 462 hr = ID3D11DeviceContext_Map(device_hwctx->device_context, 463 staging, 0, D3D11_MAP_READ, 0, &map); 464 if (FAILED(hr)) 465 goto map_failed; 466 467 fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map); 468 469 av_image_copy2(dst->data, dst->linesize, map_data, map_linesize, 470 ctx->sw_format, w, h); 471 472 ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0); 473 } else { 474 hr = ID3D11DeviceContext_Map(device_hwctx->device_context, 475 staging, 0, D3D11_MAP_WRITE, 0, &map); 476 if (FAILED(hr)) 477 goto map_failed; 478 479 fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map); 480 481 av_image_copy2(map_data, map_linesize, src->data, src->linesize, 482 ctx->sw_format, w, h); 483 484 ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0); 485 486 ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context, 487 texture, index, 0, 0, 0, 488 staging, 0, NULL); 489 } 490 491 device_hwctx->unlock(device_hwctx->lock_ctx); 492 return 0; 493 494 map_failed: 495 av_log(ctx, AV_LOG_ERROR, "Unable to lock D3D11VA surface (%lx)\n", (long)hr); 496 device_hwctx->unlock(device_hwctx->lock_ctx); 497 return AVERROR_UNKNOWN; 498 } 499 500 static int d3d11va_device_init(AVHWDeviceContext *hwdev) 501 { 502 AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx; 503 HRESULT hr; 504 505 if (!device_hwctx->lock) { 506 device_hwctx->lock_ctx = CreateMutex(NULL, 0, NULL); 507 if (device_hwctx->lock_ctx == INVALID_HANDLE_VALUE) { 508 av_log(NULL, AV_LOG_ERROR, "Failed to create a mutex\n"); 509 return AVERROR(EINVAL); 510 } 511 device_hwctx->lock = d3d11va_default_lock; 512 device_hwctx->unlock = d3d11va_default_unlock; 513 } 514 515 if (!device_hwctx->device_context) { 516 ID3D11Device_GetImmediateContext(device_hwctx->device, &device_hwctx->device_context); 517 if (!device_hwctx->device_context) 518 return AVERROR_UNKNOWN; 519 } 520 521 if (!device_hwctx->video_device) { 522 hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device, &IID_ID3D11VideoDevice, 523 (void **)&device_hwctx->video_device); 524 if (FAILED(hr)) 525 return AVERROR_UNKNOWN; 526 } 527 528 if (!device_hwctx->video_context) { 529 hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device_context, &IID_ID3D11VideoContext, 530 (void **)&device_hwctx->video_context); 531 if (FAILED(hr)) 532 return AVERROR_UNKNOWN; 533 } 534 535 return 0; 536 } 537 538 static void d3d11va_device_uninit(AVHWDeviceContext *hwdev) 539 { 540 AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx; 541 542 if (device_hwctx->device) { 543 ID3D11Device_Release(device_hwctx->device); 544 device_hwctx->device = NULL; 545 } 546 547 if (device_hwctx->device_context) { 548 ID3D11DeviceContext_Release(device_hwctx->device_context); 549 device_hwctx->device_context = NULL; 550 } 551 552 if (device_hwctx->video_device) { 553 ID3D11VideoDevice_Release(device_hwctx->video_device); 554 device_hwctx->video_device = NULL; 555 } 556 557 if (device_hwctx->video_context) { 558 ID3D11VideoContext_Release(device_hwctx->video_context); 559 device_hwctx->video_context = NULL; 560 } 561 562 if (device_hwctx->lock == d3d11va_default_lock) { 563 CloseHandle(device_hwctx->lock_ctx); 564 device_hwctx->lock_ctx = INVALID_HANDLE_VALUE; 565 device_hwctx->lock = NULL; 566 } 567 } 568 569 static int d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext *ctx, uint32_t flags, const char *vendor_id) 570 { 571 HRESULT hr; 572 IDXGIAdapter *adapter = NULL; 573 IDXGIFactory2 *factory; 574 int adapter_id = 0; 575 long int id = strtol(vendor_id, NULL, 0); 576 577 hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&factory); 578 if (FAILED(hr)) { 579 av_log(ctx, AV_LOG_ERROR, "CreateDXGIFactory returned error\n"); 580 return -1; 581 } 582 583 while (IDXGIFactory2_EnumAdapters(factory, adapter_id++, &adapter) != DXGI_ERROR_NOT_FOUND) { 584 ID3D11Device* device = NULL; 585 DXGI_ADAPTER_DESC adapter_desc; 586 587 hr = mD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL); 588 if (FAILED(hr)) { 589 av_log(ctx, AV_LOG_DEBUG, "D3D11CreateDevice returned error, try next adapter\n"); 590 IDXGIAdapter_Release(adapter); 591 continue; 592 } 593 594 hr = IDXGIAdapter2_GetDesc(adapter, &adapter_desc); 595 ID3D11Device_Release(device); 596 IDXGIAdapter_Release(adapter); 597 if (FAILED(hr)) { 598 av_log(ctx, AV_LOG_DEBUG, "IDXGIAdapter2_GetDesc returned error, try next adapter\n"); 599 continue; 600 } else if (adapter_desc.VendorId == id) { 601 IDXGIFactory2_Release(factory); 602 return adapter_id - 1; 603 } 604 } 605 606 IDXGIFactory2_Release(factory); 607 return -1; 608 } 609 610 static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, 611 AVDictionary *opts, int flags) 612 { 613 AVD3D11VADeviceContext *device_hwctx = ctx->hwctx; 614 615 HRESULT hr; 616 IDXGIAdapter *pAdapter = NULL; 617 ID3D10Multithread *pMultithread; 618 UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT; 619 int is_debug = !!av_dict_get(opts, "debug", NULL, 0); 620 int ret; 621 int adapter = -1; 622 623 if (is_debug) { 624 creationFlags |= D3D11_CREATE_DEVICE_DEBUG; 625 av_log(ctx, AV_LOG_INFO, "Enabling d3d11 debugging.\n"); 626 } 627 628 if ((ret = ff_thread_once(&functions_loaded, load_functions)) != 0) 629 return AVERROR_UNKNOWN; 630 if (!mD3D11CreateDevice || !mCreateDXGIFactory) { 631 av_log(ctx, AV_LOG_ERROR, "Failed to load D3D11 library or its functions\n"); 632 return AVERROR_UNKNOWN; 633 } 634 635 if (device) { 636 adapter = atoi(device); 637 } else { 638 AVDictionaryEntry *e = av_dict_get(opts, "vendor_id", NULL, 0); 639 if (e && e->value) { 640 adapter = d3d11va_device_find_adapter_by_vendor_id(ctx, creationFlags, e->value); 641 if (adapter < 0) { 642 av_log(ctx, AV_LOG_ERROR, "Failed to find d3d11va adapter by " 643 "vendor id %s\n", e->value); 644 return AVERROR_UNKNOWN; 645 } 646 } 647 } 648 649 if (adapter >= 0) { 650 IDXGIFactory2 *pDXGIFactory; 651 652 av_log(ctx, AV_LOG_VERBOSE, "Selecting d3d11va adapter %d\n", adapter); 653 hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory); 654 if (SUCCEEDED(hr)) { 655 if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter))) 656 pAdapter = NULL; 657 IDXGIFactory2_Release(pDXGIFactory); 658 } 659 } 660 661 if (pAdapter) { 662 DXGI_ADAPTER_DESC desc; 663 hr = IDXGIAdapter2_GetDesc(pAdapter, &desc); 664 if (!FAILED(hr)) { 665 av_log(ctx, AV_LOG_INFO, "Using device %04x:%04x (%ls).\n", 666 desc.VendorId, desc.DeviceId, desc.Description); 667 } 668 } 669 670 hr = mD3D11CreateDevice(pAdapter, pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, NULL, creationFlags, NULL, 0, 671 D3D11_SDK_VERSION, &device_hwctx->device, NULL, NULL); 672 if (pAdapter) 673 IDXGIAdapter_Release(pAdapter); 674 if (FAILED(hr)) { 675 av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device (%lx)\n", (long)hr); 676 return AVERROR_UNKNOWN; 677 } 678 679 hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread); 680 if (SUCCEEDED(hr)) { 681 ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE); 682 ID3D10Multithread_Release(pMultithread); 683 } 684 685 #if !HAVE_UWP && HAVE_DXGIDEBUG_H 686 if (is_debug) { 687 HANDLE dxgidebug_dll = LoadLibrary("dxgidebug.dll"); 688 if (dxgidebug_dll) { 689 HRESULT (WINAPI * pf_DXGIGetDebugInterface)(const GUID *riid, void **ppDebug) 690 = (void *)GetProcAddress(dxgidebug_dll, "DXGIGetDebugInterface"); 691 if (pf_DXGIGetDebugInterface) { 692 IDXGIDebug *dxgi_debug = NULL; 693 hr = pf_DXGIGetDebugInterface(&IID_IDXGIDebug, (void**)&dxgi_debug); 694 if (SUCCEEDED(hr) && dxgi_debug) { 695 IDXGIDebug_ReportLiveObjects(dxgi_debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL); 696 av_log(ctx, AV_LOG_INFO, "Enabled dxgi debugging.\n"); 697 } else { 698 av_log(ctx, AV_LOG_WARNING, "Failed enabling dxgi debugging.\n"); 699 } 700 } else { 701 av_log(ctx, AV_LOG_WARNING, "Failed getting dxgi debug interface.\n"); 702 } 703 } else { 704 av_log(ctx, AV_LOG_WARNING, "Failed loading dxgi debug library.\n"); 705 } 706 } 707 #endif 708 709 return 0; 710 } 711 712 const HWContextType ff_hwcontext_type_d3d11va = { 713 .type = AV_HWDEVICE_TYPE_D3D11VA, 714 .name = "D3D11VA", 715 716 .device_hwctx_size = sizeof(AVD3D11VADeviceContext), 717 .frames_hwctx_size = sizeof(D3D11VAFramesContext), 718 719 .device_create = d3d11va_device_create, 720 .device_init = d3d11va_device_init, 721 .device_uninit = d3d11va_device_uninit, 722 .frames_get_constraints = d3d11va_frames_get_constraints, 723 .frames_init = d3d11va_frames_init, 724 .frames_uninit = d3d11va_frames_uninit, 725 .frames_get_buffer = d3d11va_get_buffer, 726 .transfer_get_formats = d3d11va_transfer_get_formats, 727 .transfer_data_to = d3d11va_transfer_data, 728 .transfer_data_from = d3d11va_transfer_data, 729 730 .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_D3D11, AV_PIX_FMT_NONE }, 731 };