static void set_swap_chain_size(int width, int height) { ID3D11Texture2D *back_buffer; D3D11_RENDER_TARGET_VIEW_DESC desc; HRESULT hr; if (rt_view) ID3D11RenderTargetView_Release(rt_view); ID3D11DeviceContext_OMSetRenderTargets(context, 0, NULL, NULL); hr = IDXGISwapChain_ResizeBuffers(swap_chain, 0, width, height, DXGI_FORMAT_UNKNOWN, 0); if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DRIVER_INTERNAL_ERROR) { /* to recover from this, you'll need to recreate device and all the resources */ MessageBoxW(NULL, L"DXGI device is removed or reset!", L"Error", 0); exit(0); } assert(SUCCEEDED(hr)); memset(&desc, 0, sizeof(desc)); desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; hr = IDXGISwapChain_GetBuffer(swap_chain, 0, &IID_ID3D11Texture2D, &back_buffer); assert(SUCCEEDED(hr)); hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)back_buffer, &desc, &rt_view); assert(SUCCEEDED(hr)); ID3D11Texture2D_Release(back_buffer); }
static void DestroyPicture(picture_t *picture) { picture_sys_t *p_sys = picture->p_sys; ID3D11Texture2D_Release( p_sys->texture ); free(p_sys); free(picture); }
static void d3d11_wm_destroy( sgui_ctx_wm* super ) { sgui_d3d11_wm* this = (sgui_d3d11_wm*)super; ID3D11SamplerState_Release( this->sampler ); ID3D11ShaderResourceView_Release( this->view ); ID3D11Texture2D_Release( this->skintex ); free( this ); }
static void d3d11va_destroy_decoder(void *arg) { struct d3d11va_decoder *decoder = arg; if (decoder->decoder) ID3D11VideoDecoder_Release(decoder->decoder); if (decoder->staging) ID3D11Texture2D_Release(decoder->staging); }
static void d3d11va_release_img(void *arg) { struct d3d11va_surface *surface = arg; if (surface->surface) ID3D11VideoDecoderOutputView_Release(surface->surface); if (surface->texture) ID3D11Texture2D_Release(surface->texture); talloc_free(surface); }
void D3D11_DestroyTexture (texid_t tex) { if (!tex) return; if (tex->ptr2) ID3D11ShaderResourceView_Release((ID3D11ShaderResourceView*)tex->ptr2); tex->ptr2 = NULL; if (tex->ptr) ID3D11Texture2D_Release((ID3D11Texture2D*)tex->ptr); tex->ptr = NULL; }
static int d3d11va_init_decoder(struct lavc_ctx *s, int w, int h) { HRESULT hr; int ret = -1; struct priv *p = s->hwdec_priv; TA_FREEP(&p->decoder); ID3D11Texture2D *texture = NULL; void *tmp = talloc_new(NULL); UINT n_guids = ID3D11VideoDevice_GetVideoDecoderProfileCount(p->video_dev); GUID *device_guids = talloc_array(tmp, GUID, n_guids); for (UINT i = 0; i < n_guids; i++) { GUID *guid = &device_guids[i]; hr = ID3D11VideoDevice_GetVideoDecoderProfile(p->video_dev, i, guid); if (FAILED(hr)) { MP_ERR(p, "Failed to get VideoDecoderProfile %d: %s\n", i, mp_HRESULT_to_str(hr)); goto done; } dump_decoder_info(s, guid); } struct d3d_decoder_fmt fmt = d3d_select_decoder_mode(s, device_guids, n_guids, d3d11_formats, MP_ARRAY_SIZE(d3d11_formats), d3d11_format_supported); if (!fmt.format) { MP_ERR(p, "Failed to find a suitable decoder\n"); goto done; } struct d3d11va_decoder *decoder = talloc_zero(tmp, struct d3d11va_decoder); talloc_set_destructor(decoder, d3d11va_destroy_decoder); decoder->mpfmt_decoded = fmt.format->mpfmt; int n_surfaces = hwdec_get_max_refs(s) + ADDITIONAL_SURFACES; int w_align = w, h_align = h; d3d_surface_align(s, &w_align, &h_align); D3D11_TEXTURE2D_DESC tex_desc = { .Width = w_align, .Height = h_align, .MipLevels = 1, .Format = fmt.format->dxfmt, .SampleDesc.Count = 1, .MiscFlags = 0, .ArraySize = n_surfaces, .Usage = D3D11_USAGE_DEFAULT, .BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE, .CPUAccessFlags = 0, }; hr = ID3D11Device_CreateTexture2D(p->device, &tex_desc, NULL, &texture); if (FAILED(hr)) { MP_ERR(p, "Failed to create Direct3D11 texture with %d surfaces: %s\n", n_surfaces, mp_HRESULT_to_str(hr)); goto done; } if (s->hwdec->type == HWDEC_D3D11VA_COPY) { // create staging texture shared with the CPU with mostly the same // parameters as the above decoder-bound texture ID3D11Texture2D_GetDesc(texture, &tex_desc); tex_desc.MipLevels = 1; tex_desc.MiscFlags = 0; tex_desc.ArraySize = 1; tex_desc.Usage = D3D11_USAGE_STAGING; tex_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; tex_desc.BindFlags = 0; hr = ID3D11Device_CreateTexture2D(p->device, &tex_desc, NULL, &decoder->staging); if (FAILED(hr)) { MP_ERR(p, "Failed to create staging texture: %s\n", mp_HRESULT_to_str(hr)); goto done; } } // pool to hold the mp_image wrapped surfaces decoder->pool = talloc_steal(decoder, mp_image_pool_new(n_surfaces)); // array of the same surfaces (needed by ffmpeg) ID3D11VideoDecoderOutputView **surfaces = talloc_array_ptrtype(decoder->pool, surfaces, n_surfaces); D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc = { .DecodeProfile = *fmt.guid, .ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D, }; for (int i = 0; i < n_surfaces; i++) { ID3D11VideoDecoderOutputView **surface = &surfaces[i]; view_desc.Texture2D.ArraySlice = i; hr = ID3D11VideoDevice_CreateVideoDecoderOutputView( p->video_dev, (ID3D11Resource *)texture, &view_desc, surface); if (FAILED(hr)) { MP_ERR(p, "Failed getting decoder output view %d: %s\n", i, mp_HRESULT_to_str(hr)); goto done; } struct mp_image *img = d3d11va_new_ref(*surface, w, h); ID3D11VideoDecoderOutputView_Release(*surface); // transferred to img if (!img) { MP_ERR(p, "Failed to create D3D11VA image %d\n", i); goto done; } mp_image_pool_add(decoder->pool, img); // transferred to pool } D3D11_VIDEO_DECODER_DESC decoder_desc = { .Guid = *fmt.guid, .SampleWidth = w, .SampleHeight = h, .OutputFormat = fmt.format->dxfmt, }; UINT n_cfg; hr = ID3D11VideoDevice_GetVideoDecoderConfigCount(p->video_dev, &decoder_desc, &n_cfg); if (FAILED(hr)) { MP_ERR(p, "Failed to get number of decoder configurations: %s)", mp_HRESULT_to_str(hr)); goto done; } // pick the config with the highest score D3D11_VIDEO_DECODER_CONFIG *decoder_config = talloc_zero(decoder, D3D11_VIDEO_DECODER_CONFIG); unsigned max_score = 0; for (UINT i = 0; i < n_cfg; i++) { D3D11_VIDEO_DECODER_CONFIG cfg; hr = ID3D11VideoDevice_GetVideoDecoderConfig(p->video_dev, &decoder_desc, i, &cfg); if (FAILED(hr)) { MP_ERR(p, "Failed to get decoder config %d: %s\n", i, mp_HRESULT_to_str(hr)); goto done; } unsigned score = d3d_decoder_config_score( s, &cfg.guidConfigBitstreamEncryption, cfg.ConfigBitstreamRaw); if (score > max_score) { max_score = score; *decoder_config = cfg; } } if (!max_score) { MP_ERR(p, "Failed to find a suitable decoder configuration\n"); goto done; } hr = ID3D11VideoDevice_CreateVideoDecoder(p->video_dev, &decoder_desc, decoder_config, &decoder->decoder); if (FAILED(hr)) { MP_ERR(p, "Failed to create video decoder: %s\n", mp_HRESULT_to_str(hr)); goto done; } struct AVD3D11VAContext *avd3d11va_ctx = s->avctx->hwaccel_context; avd3d11va_ctx->decoder = decoder->decoder; avd3d11va_ctx->video_context = p->video_ctx; avd3d11va_ctx->cfg = decoder_config; avd3d11va_ctx->surface_count = n_surfaces; avd3d11va_ctx->surface = surfaces; avd3d11va_ctx->workaround = is_clearvideo(fmt.guid) ? FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO : 0; p->decoder = talloc_steal(NULL, decoder); ret = 0; done: // still referenced by pool images / surfaces if (texture) ID3D11Texture2D_Release(texture); talloc_free(tmp); return ret; } static void destroy_device(struct lavc_ctx *s) { struct priv *p = s->hwdec_priv; if (p->device) ID3D11Device_Release(p->device); if (p->device_ctx) ID3D11DeviceContext_Release(p->device_ctx); } static bool create_device(struct lavc_ctx *s, BOOL thread_safe) { HRESULT hr; struct priv *p = s->hwdec_priv; d3d_load_dlls(); if (!d3d11_dll) { MP_ERR(p, "Failed to load D3D11 library\n"); return false; } PFN_D3D11_CREATE_DEVICE CreateDevice = (void *)GetProcAddress(d3d11_dll, "D3D11CreateDevice"); if (!CreateDevice) { MP_ERR(p, "Failed to get D3D11CreateDevice symbol from DLL: %s\n", mp_LastError_to_str()); return false; } hr = CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0, D3D11_SDK_VERSION, &p->device, NULL, &p->device_ctx); if (FAILED(hr)) { MP_ERR(p, "Failed to create D3D11 Device: %s\n", mp_HRESULT_to_str(hr)); return false; } ID3D10Multithread *multithread; hr = ID3D11Device_QueryInterface(p->device, &IID_ID3D10Multithread, (void **)&multithread); if (FAILED(hr)) { MP_ERR(p, "Failed to get Multithread interface: %s\n", mp_HRESULT_to_str(hr)); return false; } ID3D10Multithread_SetMultithreadProtected(multithread, thread_safe); ID3D10Multithread_Release(multithread); return true; } static void d3d11va_uninit(struct lavc_ctx *s) { struct priv *p = s->hwdec_priv; if (!p) return; talloc_free(p->decoder); av_freep(&s->avctx->hwaccel_context); if (p->video_dev) ID3D11VideoDevice_Release(p->video_dev); if (p->video_ctx) ID3D11VideoContext_Release(p->video_ctx); destroy_device(s); TA_FREEP(&s->hwdec_priv); } static int d3d11va_init(struct lavc_ctx *s) { HRESULT hr; struct priv *p = talloc_zero(NULL, struct priv); if (!p) return -1; s->hwdec_priv = p; p->log = mp_log_new(s, s->log, "d3d11va"); if (s->hwdec->type == HWDEC_D3D11VA_COPY) { mp_check_gpu_memcpy(p->log, NULL); p->sw_pool = talloc_steal(p, mp_image_pool_new(17)); } p->device = hwdec_devices_load(s->hwdec_devs, s->hwdec->type); if (p->device) { ID3D11Device_AddRef(p->device); ID3D11Device_GetImmediateContext(p->device, &p->device_ctx); if (!p->device_ctx) goto fail; MP_VERBOSE(p, "Using VO-supplied device %p.\n", p->device); } else if (s->hwdec->type == HWDEC_D3D11VA) { MP_ERR(p, "No Direct3D device provided for native d3d11 decoding\n"); goto fail; } else { if (!create_device(s, FALSE)) goto fail; } hr = ID3D11DeviceContext_QueryInterface(p->device_ctx, &IID_ID3D11VideoContext, (void **)&p->video_ctx); if (FAILED(hr)) { MP_ERR(p, "Failed to get VideoContext interface: %s\n", mp_HRESULT_to_str(hr)); goto fail; } hr = ID3D11Device_QueryInterface(p->device, &IID_ID3D11VideoDevice, (void **)&p->video_dev); if (FAILED(hr)) { MP_ERR(p, "Failed to get VideoDevice interface. %s\n", mp_HRESULT_to_str(hr)); goto fail; } s->avctx->hwaccel_context = av_d3d11va_alloc_context(); if (!s->avctx->hwaccel_context) { MP_ERR(p, "Failed to allocate hwaccel_context\n"); goto fail; } return 0; fail: d3d11va_uninit(s); return -1; } static int d3d11va_probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, const char *codec) { // d3d11va-copy can do without external context; dxva2 requires it. if (hwdec->type != HWDEC_D3D11VA_COPY) { if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_D3D11VA)) return HWDEC_ERR_NO_CTX; } return d3d_probe_codec(codec); } const struct vd_lavc_hwdec mp_vd_lavc_d3d11va = { .type = HWDEC_D3D11VA, .image_format = IMGFMT_D3D11VA, .probe = d3d11va_probe, .init = d3d11va_init, .uninit = d3d11va_uninit, .init_decoder = d3d11va_init_decoder, .allocate_image = d3d11va_allocate_image, .process_image = d3d11va_update_image_attribs, }; const struct vd_lavc_hwdec mp_vd_lavc_d3d11va_copy = { .type = HWDEC_D3D11VA_COPY, .copying = true, .image_format = IMGFMT_D3D11VA, .probe = d3d11va_probe, .init = d3d11va_init, .uninit = d3d11va_uninit, .init_decoder = d3d11va_init_decoder, .allocate_image = d3d11va_allocate_image, .process_image = d3d11va_retrieve_image, .delay_queue = HWDEC_DELAY_QUEUE_COUNT, };
static void release_tex(void *arg) { ID3D11Texture2D *texture = arg; ID3D11Texture2D_Release(texture); }
/** * It creates a Direct3D11 decoder using the given video format */ static int DxCreateDecoderSurfaces(vlc_va_t *va, int codec_id, const video_format_t *fmt, bool b_threading) { vlc_va_sys_t *sys = va->sys; directx_sys_t *dx_sys = &va->sys->dx_sys; HRESULT hr; ID3D10Multithread *pMultithread; hr = ID3D11Device_QueryInterface( (ID3D11Device*) dx_sys->d3ddev, &IID_ID3D10Multithread, (void **)&pMultithread); if (SUCCEEDED(hr)) { ID3D10Multithread_SetMultithreadProtected(pMultithread, b_threading && dx_sys->thread_count > 1); ID3D10Multithread_Release(pMultithread); } D3D11_TEXTURE2D_DESC texDesc; ZeroMemory(&texDesc, sizeof(texDesc)); texDesc.Width = dx_sys->surface_width; texDesc.Height = dx_sys->surface_height; texDesc.MipLevels = 1; texDesc.Format = sys->render; texDesc.SampleDesc.Count = 1; texDesc.MiscFlags = 0; texDesc.ArraySize = dx_sys->surface_count; texDesc.Usage = D3D11_USAGE_DEFAULT; texDesc.BindFlags = D3D11_BIND_DECODER; texDesc.CPUAccessFlags = 0; ID3D11Texture2D *p_texture; hr = ID3D11Device_CreateTexture2D( (ID3D11Device*) dx_sys->d3ddev, &texDesc, NULL, &p_texture ); if (FAILED(hr)) { msg_Err(va, "CreateTexture2D %d failed. (hr=0x%0lx)", dx_sys->surface_count, hr); return VLC_EGENERIC; } D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc; ZeroMemory(&viewDesc, sizeof(viewDesc)); viewDesc.DecodeProfile = dx_sys->input; viewDesc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D; int surface_count = dx_sys->surface_count; for (dx_sys->surface_count = 0; dx_sys->surface_count < surface_count; dx_sys->surface_count++) { viewDesc.Texture2D.ArraySlice = dx_sys->surface_count; hr = ID3D11VideoDevice_CreateVideoDecoderOutputView( (ID3D11VideoDevice*) dx_sys->d3ddec, (ID3D11Resource*) p_texture, &viewDesc, (ID3D11VideoDecoderOutputView**) &dx_sys->hw_surface[dx_sys->surface_count] ); if (FAILED(hr)) { msg_Err(va, "CreateVideoDecoderOutputView %d failed. (hr=0x%0lx)", dx_sys->surface_count, hr); ID3D11Texture2D_Release(p_texture); return VLC_EGENERIC; } } msg_Dbg(va, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d)", dx_sys->surface_count, dx_sys->surface_width, dx_sys->surface_height); D3D11_VIDEO_DECODER_DESC decoderDesc; ZeroMemory(&decoderDesc, sizeof(decoderDesc)); decoderDesc.Guid = dx_sys->input; decoderDesc.SampleWidth = fmt->i_width; decoderDesc.SampleHeight = fmt->i_height; decoderDesc.OutputFormat = sys->render; UINT cfg_count; hr = ID3D11VideoDevice_GetVideoDecoderConfigCount( (ID3D11VideoDevice*) dx_sys->d3ddec, &decoderDesc, &cfg_count ); if (FAILED(hr)) { msg_Err(va, "GetVideoDecoderConfigCount failed. (hr=0x%lX)", hr); return VLC_EGENERIC; } /* List all configurations available for the decoder */ D3D11_VIDEO_DECODER_CONFIG cfg_list[cfg_count]; for (unsigned i = 0; i < cfg_count; i++) { hr = ID3D11VideoDevice_GetVideoDecoderConfig( (ID3D11VideoDevice*) dx_sys->d3ddec, &decoderDesc, i, &cfg_list[i] ); if (FAILED(hr)) { msg_Err(va, "GetVideoDecoderConfig failed. (hr=0x%lX)", hr); return VLC_EGENERIC; } } msg_Dbg(va, "we got %d decoder configurations", cfg_count); /* Select the best decoder configuration */ int cfg_score = 0; for (unsigned i = 0; i < cfg_count; i++) { const D3D11_VIDEO_DECODER_CONFIG *cfg = &cfg_list[i]; /* */ msg_Dbg(va, "configuration[%d] ConfigBitstreamRaw %d", i, cfg->ConfigBitstreamRaw); /* */ int score; if (cfg->ConfigBitstreamRaw == 1) score = 1; else if (codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2) score = 2; else continue; if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA_NoEncrypt)) score += 16; if (cfg_score < score) { sys->cfg = *cfg; cfg_score = score; } } if (cfg_score <= 0) { msg_Err(va, "Failed to find a supported decoder configuration"); return VLC_EGENERIC; } /* Create the decoder */ ID3D11VideoDecoder *decoder; hr = ID3D11VideoDevice_CreateVideoDecoder( (ID3D11VideoDevice*) dx_sys->d3ddec, &decoderDesc, &sys->cfg, &decoder ); if (FAILED(hr)) { msg_Err(va, "ID3D11VideoDevice_CreateVideoDecoder failed. (hr=0x%lX)", hr); dx_sys->decoder = NULL; return VLC_EGENERIC; } dx_sys->decoder = (IUnknown*) decoder; msg_Dbg(va, "DxCreateDecoderSurfaces succeed"); return VLC_SUCCESS; }
sgui_ctx_wm* d3d11_wm_create( sgui_window* wnd ) { D3D11_SHADER_RESOURCE_VIEW_DESC rvdesc; D3D11_SAMPLER_DESC sampdesc; D3D11_SUBRESOURCE_DATA data; unsigned int width, height; D3D11_TEXTURE2D_DESC desc; sgui_d3d11_context* ctx; sgui_subwm_skin* skin; sgui_d3d11_wm* this; sgui_ctx_wm* super; HRESULT status; ctx = (sgui_d3d11_context*)sgui_window_get_context( wnd ); if( !ctx ) return NULL; this = calloc( 1, sizeof(sgui_d3d11_wm) ); super = (sgui_ctx_wm*)this; if( !this ) return NULL; memset( &desc, 0, sizeof(desc) ); memset( &data, 0, sizeof(data) ); memset( &rvdesc, 0, sizeof(rvdesc) ); memset( &sampdesc, 0, sizeof(sampdesc) ); skin = sgui_subwm_skin_get( ); skin->get_ctx_skin_texture_size( skin, &width, &height ); desc.Width = width; desc.Height = height; desc.MipLevels = 1; desc.ArraySize = 1; desc.SampleDesc.Count = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.Usage = D3D11_USAGE_IMMUTABLE; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; data.pSysMem = skin->get_ctx_skin_texture( skin ); data.SysMemPitch = width*4; rvdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; rvdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; rvdesc.Texture2D.MipLevels = 1; sampdesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; sampdesc.ComparisonFunc = D3D11_COMPARISON_NEVER; sampdesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; sampdesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; sampdesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; status = ID3D11Device_CreateTexture2D( ctx->dev, &desc, &data, &this->skintex ); if( status!=S_OK || !this->skintex ) goto fail; status = ID3D11Device_CreateShaderResourceView( ctx->dev, (void*)this->skintex, &rvdesc, &this->view ); if( status!=S_OK || !this->view ) goto failtex; status = ID3D11Device_CreateSamplerState( ctx->dev, &sampdesc, &this->sampler ); if( status!=S_OK || !this->sampler ) goto failview; /* init */ super->wnd = wnd; super->draw_gui = d3d11_wm_draw_gui; super->destroy = d3d11_wm_destroy; return super; failview: ID3D11ShaderResourceView_Release( this->view ); failtex: ID3D11Texture2D_Release( this->skintex ); fail: free( this ); return NULL; }