You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
786 lines
27 KiB
786 lines
27 KiB
/*****************************************************************************
|
|
* d3d11_fmt.c : D3D11 helper calls
|
|
*****************************************************************************
|
|
* Copyright © 2017 VLC authors, VideoLAN and VideoLabs
|
|
*
|
|
* Authors: Steve Lhomme <robux4@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2.1 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
*****************************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#if _WIN32_WINNT < 0x0601 // _WIN32_WINNT_WIN7
|
|
# undef _WIN32_WINNT
|
|
# define _WIN32_WINNT _WIN32_WINNT_WIN7
|
|
#endif
|
|
|
|
#include <vlc_common.h>
|
|
#include <vlc_picture.h>
|
|
|
|
#define COBJMACROS
|
|
#include <d3d11.h>
|
|
#include <assert.h>
|
|
#if !defined(NDEBUG) && defined(HAVE_DXGIDEBUG_H)
|
|
# include <initguid.h>
|
|
# include <dxgidebug.h>
|
|
#endif
|
|
|
|
#include "d3d11_fmt.h"
|
|
|
|
#include "../codec/avcodec/va_surface.h"
|
|
|
|
picture_sys_t *ActivePictureSys(picture_t *p_pic)
|
|
{
|
|
struct va_pic_context *pic_ctx = (struct va_pic_context*)p_pic->context;
|
|
return pic_ctx ? &pic_ctx->picsys : p_pic->p_sys;
|
|
}
|
|
|
|
void AcquirePictureSys(picture_sys_t *p_sys)
|
|
{
|
|
for (int i=0; i<D3D11_MAX_SHADER_VIEW; i++) {
|
|
if (p_sys->resourceView[i])
|
|
ID3D11ShaderResourceView_AddRef(p_sys->resourceView[i]);
|
|
if (p_sys->texture[i])
|
|
ID3D11Texture2D_AddRef(p_sys->texture[i]);
|
|
}
|
|
if (p_sys->context)
|
|
ID3D11DeviceContext_AddRef(p_sys->context);
|
|
if (p_sys->decoder)
|
|
ID3D11VideoDecoderOutputView_AddRef(p_sys->decoder);
|
|
if (p_sys->processorInput)
|
|
ID3D11VideoProcessorInputView_AddRef(p_sys->processorInput);
|
|
if (p_sys->processorOutput)
|
|
ID3D11VideoProcessorOutputView_AddRef(p_sys->processorOutput);
|
|
}
|
|
|
|
void ReleasePictureSys(picture_sys_t *p_sys)
|
|
{
|
|
for (int i=0; i<D3D11_MAX_SHADER_VIEW; i++) {
|
|
if (p_sys->resourceView[i])
|
|
ID3D11ShaderResourceView_Release(p_sys->resourceView[i]);
|
|
if (p_sys->texture[i])
|
|
ID3D11Texture2D_Release(p_sys->texture[i]);
|
|
}
|
|
if (p_sys->context)
|
|
ID3D11DeviceContext_Release(p_sys->context);
|
|
if (p_sys->decoder)
|
|
ID3D11VideoDecoderOutputView_Release(p_sys->decoder);
|
|
if (p_sys->processorInput)
|
|
ID3D11VideoProcessorInputView_Release(p_sys->processorInput);
|
|
if (p_sys->processorOutput)
|
|
ID3D11VideoProcessorOutputView_Release(p_sys->processorOutput);
|
|
}
|
|
|
|
/* map texture planes to resource views */
|
|
#undef D3D11_AllocateShaderView
|
|
int D3D11_AllocateShaderView(vlc_object_t *obj, ID3D11Device *d3ddevice,
|
|
const d3d_format_t *format,
|
|
ID3D11Texture2D *p_texture[D3D11_MAX_SHADER_VIEW], UINT slice_index,
|
|
ID3D11ShaderResourceView *resourceView[D3D11_MAX_SHADER_VIEW])
|
|
{
|
|
HRESULT hr;
|
|
int i;
|
|
D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc = { 0 };
|
|
D3D11_TEXTURE2D_DESC texDesc;
|
|
ID3D11Texture2D_GetDesc(p_texture[0], &texDesc);
|
|
assert(texDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE);
|
|
|
|
if (texDesc.ArraySize == 1)
|
|
{
|
|
resviewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
|
resviewDesc.Texture2D.MipLevels = 1;
|
|
}
|
|
else
|
|
{
|
|
resviewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
|
|
resviewDesc.Texture2DArray.MipLevels = -1;
|
|
resviewDesc.Texture2DArray.ArraySize = 1;
|
|
resviewDesc.Texture2DArray.FirstArraySlice = slice_index;
|
|
assert(slice_index < texDesc.ArraySize);
|
|
}
|
|
for (i=0; i<D3D11_MAX_SHADER_VIEW; i++)
|
|
{
|
|
resviewDesc.Format = format->resourceFormat[i];
|
|
if (resviewDesc.Format == DXGI_FORMAT_UNKNOWN)
|
|
resourceView[i] = NULL;
|
|
else
|
|
{
|
|
hr = ID3D11Device_CreateShaderResourceView(d3ddevice, (ID3D11Resource*)p_texture[i], &resviewDesc, &resourceView[i]);
|
|
if (FAILED(hr)) {
|
|
msg_Err(obj, "Could not Create the Texture ResourceView %d slice %d. (hr=0x%lX)", i, slice_index, hr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i != D3D11_MAX_SHADER_VIEW)
|
|
{
|
|
while (--i >= 0)
|
|
{
|
|
ID3D11ShaderResourceView_Release(resourceView[i]);
|
|
resourceView[i] = NULL;
|
|
}
|
|
return VLC_EGENERIC;
|
|
}
|
|
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
#undef D3D11_GetDriverVersion
|
|
|
|
#if !VLC_WINSTORE_APP
|
|
static HKEY GetAdapterRegistry(vlc_object_t *obj, DXGI_ADAPTER_DESC *adapterDesc)
|
|
{
|
|
HKEY hKey;
|
|
CHAR key[128];
|
|
CHAR szData[256], lookup[256];
|
|
DWORD len = 256;
|
|
LSTATUS ret;
|
|
|
|
_snprintf(lookup, 256, "pci\\ven_%04x&dev_%04x", adapterDesc->VendorId, adapterDesc->DeviceId);
|
|
for (int i=0;;i++)
|
|
{
|
|
_snprintf(key, 128, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\%04d", i);
|
|
ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey);
|
|
if ( ret != ERROR_SUCCESS )
|
|
{
|
|
msg_Warn(obj, "failed to read the %d Display Adapter registry key (%ld)", i, ret);
|
|
return NULL;
|
|
}
|
|
|
|
len = sizeof(szData);
|
|
ret = RegQueryValueExA( hKey, "MatchingDeviceId", NULL, NULL, (LPBYTE) &szData, &len );
|
|
if ( ret == ERROR_SUCCESS ) {
|
|
if (_strnicmp(lookup, szData, strlen(lookup)) == 0)
|
|
return hKey;
|
|
msg_Dbg(obj, "different %d device %s vs %s", i, lookup, szData);
|
|
}
|
|
else
|
|
msg_Warn(obj, "failed to get the %d MatchingDeviceId (%ld)", i, ret);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void D3D11_GetDriverVersion(vlc_object_t *obj, d3d11_device_t *d3d_dev)
|
|
{
|
|
memset(&d3d_dev->WDDM, 0, sizeof(d3d_dev->WDDM));
|
|
|
|
IDXGIAdapter *pAdapter = D3D11DeviceAdapter(d3d_dev->d3ddevice);
|
|
if (unlikely(!pAdapter))
|
|
{
|
|
msg_Warn(obj, "can't get adapter from device %p", (void*)d3d_dev->d3ddevice);
|
|
return;
|
|
}
|
|
|
|
DXGI_ADAPTER_DESC adapterDesc;
|
|
HRESULT hr = IDXGIAdapter_GetDesc(pAdapter, &adapterDesc);
|
|
IDXGIAdapter_Release(pAdapter);
|
|
if (FAILED(hr))
|
|
{
|
|
msg_Warn(obj, "can't get adapter description");
|
|
return;
|
|
}
|
|
|
|
LONG err = ERROR_ACCESS_DENIED;
|
|
CHAR szData[256];
|
|
DWORD len = 256;
|
|
HKEY hKey = GetAdapterRegistry(obj, &adapterDesc);
|
|
if (hKey == NULL)
|
|
{
|
|
msg_Warn(obj, "can't find adapter in registry");
|
|
return;
|
|
}
|
|
|
|
err = RegQueryValueExA( hKey, "DriverVersion", NULL, NULL, (LPBYTE) &szData, &len );
|
|
RegCloseKey(hKey);
|
|
|
|
if (err != ERROR_SUCCESS )
|
|
{
|
|
msg_Warn(obj, "failed to read the adapter DriverVersion");
|
|
return;
|
|
}
|
|
|
|
int wddm, d3d_features, revision, build;
|
|
/* see https://msdn.microsoft.com/windows/hardware/commercialize/design/compatibility/device-graphics */
|
|
if (sscanf(szData, "%d.%d.%d.%d", &wddm, &d3d_features, &revision, &build) != 4)
|
|
{
|
|
msg_Warn(obj, "the adapter DriverVersion '%s' doesn't match the expected format", szData);
|
|
return;
|
|
}
|
|
d3d_dev->WDDM.wddm = wddm;
|
|
d3d_dev->WDDM.d3d_features = d3d_features;
|
|
d3d_dev->WDDM.revision = revision;
|
|
d3d_dev->WDDM.build = build;
|
|
msg_Dbg(obj, "%s WDDM driver %d.%d.%d.%d", DxgiVendorStr(adapterDesc.VendorId), wddm, d3d_features, revision, build);
|
|
if (adapterDesc.VendorId == GPU_MANUFACTURER_INTEL && revision >= 100)
|
|
{
|
|
/* new Intel driver format */
|
|
d3d_dev->WDDM.build += (revision - 100) * 1000;
|
|
}
|
|
}
|
|
#else /* VLC_WINSTORE_APP */
|
|
void D3D11_GetDriverVersion(vlc_object_t *obj, d3d11_device_t *d3d_dev)
|
|
{
|
|
VLC_UNUSED(obj);
|
|
VLC_UNUSED(d3d_dev);
|
|
return;
|
|
}
|
|
#endif /* VLC_WINSTORE_APP */
|
|
|
|
void D3D11_ReleaseDevice(d3d11_device_t *d3d_dev)
|
|
{
|
|
if (d3d_dev->d3dcontext)
|
|
{
|
|
ID3D11DeviceContext_Flush(d3d_dev->d3dcontext);
|
|
ID3D11DeviceContext_Release(d3d_dev->d3dcontext);
|
|
d3d_dev->d3dcontext = NULL;
|
|
}
|
|
if (d3d_dev->d3ddevice)
|
|
{
|
|
ID3D11Device_Release(d3d_dev->d3ddevice);
|
|
d3d_dev->d3ddevice = NULL;
|
|
}
|
|
#if defined(HAVE_ID3D11VIDEODECODER)
|
|
if( d3d_dev->owner && d3d_dev->context_mutex != INVALID_HANDLE_VALUE )
|
|
{
|
|
CloseHandle( d3d_dev->context_mutex );
|
|
d3d_dev->context_mutex = INVALID_HANDLE_VALUE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#undef D3D11_CreateDevice
|
|
HRESULT D3D11_CreateDevice(vlc_object_t *obj, d3d11_handle_t *hd3d,
|
|
bool hw_decoding, d3d11_device_t *out)
|
|
{
|
|
#if !VLC_WINSTORE_APP
|
|
# define D3D11CreateDevice(args...) pf_CreateDevice(args)
|
|
/* */
|
|
PFN_D3D11_CREATE_DEVICE pf_CreateDevice;
|
|
pf_CreateDevice = (void *)GetProcAddress(hd3d->hdll, "D3D11CreateDevice");
|
|
if (!pf_CreateDevice) {
|
|
msg_Err(obj, "Cannot locate reference to D3D11CreateDevice ABI in DLL");
|
|
return E_NOINTERFACE;
|
|
}
|
|
#endif /* VLC_WINSTORE_APP */
|
|
|
|
HRESULT hr = E_NOTIMPL;
|
|
UINT creationFlags = 0;
|
|
|
|
if (hw_decoding || !obj->obj.force)
|
|
creationFlags |= D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
|
|
|
|
#if !defined(NDEBUG)
|
|
# if !VLC_WINSTORE_APP
|
|
if (IsDebuggerPresent())
|
|
# endif /* VLC_WINSTORE_APP */
|
|
{
|
|
HINSTANCE sdklayer_dll = LoadLibrary(TEXT("d3d11_1sdklayers.dll"));
|
|
if (sdklayer_dll) {
|
|
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
|
FreeLibrary(sdklayer_dll);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static const D3D_DRIVER_TYPE driverAttempts[] = {
|
|
D3D_DRIVER_TYPE_HARDWARE,
|
|
#if 0 /* ifndef NDEBUG */
|
|
D3D_DRIVER_TYPE_REFERENCE,
|
|
#endif
|
|
};
|
|
|
|
static D3D_FEATURE_LEVEL D3D11_features[] = {
|
|
D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0,
|
|
D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0,
|
|
D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1
|
|
};
|
|
|
|
for (UINT driver = 0; driver < ARRAY_SIZE(driverAttempts); driver++) {
|
|
hr = D3D11CreateDevice(NULL, driverAttempts[driver], NULL, creationFlags,
|
|
D3D11_features, ARRAY_SIZE(D3D11_features), D3D11_SDK_VERSION,
|
|
&out->d3ddevice, &out->feature_level, &out->d3dcontext);
|
|
if (SUCCEEDED(hr)) {
|
|
msg_Dbg(obj, "Created the D3D11 device type %d level %x.",
|
|
driverAttempts[driver], out->feature_level);
|
|
D3D11_GetDriverVersion( obj, out );
|
|
/* we can work with legacy levels but only if forced */
|
|
if ( obj->obj.force || out->feature_level >= D3D_FEATURE_LEVEL_11_0 )
|
|
break;
|
|
msg_Dbg(obj, "Incompatible feature level %x", out->feature_level);
|
|
ID3D11DeviceContext_Release(out->d3dcontext);
|
|
ID3D11Device_Release(out->d3ddevice);
|
|
out->d3dcontext = NULL;
|
|
out->d3ddevice = NULL;
|
|
hr = E_NOTIMPL;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
#if defined(HAVE_ID3D11VIDEODECODER)
|
|
out->context_mutex = CreateMutexEx( NULL, NULL, 0, SYNCHRONIZE );
|
|
ID3D11DeviceContext_SetPrivateData( out->d3dcontext, &GUID_CONTEXT_MUTEX,
|
|
sizeof( out->context_mutex ), &out->context_mutex );
|
|
#endif
|
|
|
|
out->owner = true;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
IDXGIAdapter *D3D11DeviceAdapter(ID3D11Device *d3ddev)
|
|
{
|
|
IDXGIDevice *pDXGIDevice = NULL;
|
|
HRESULT hr = ID3D11Device_QueryInterface(d3ddev, &IID_IDXGIDevice, (void **)&pDXGIDevice);
|
|
if (FAILED(hr)) {
|
|
return NULL;
|
|
}
|
|
|
|
IDXGIAdapter *p_adapter;
|
|
hr = IDXGIDevice_GetAdapter(pDXGIDevice, &p_adapter);
|
|
IDXGIDevice_Release(pDXGIDevice);
|
|
if (FAILED(hr)) {
|
|
return NULL;
|
|
}
|
|
return p_adapter;
|
|
}
|
|
|
|
bool isXboxHardware(ID3D11Device *d3ddev)
|
|
{
|
|
IDXGIAdapter *p_adapter = D3D11DeviceAdapter(d3ddev);
|
|
if (!p_adapter)
|
|
return NULL;
|
|
|
|
bool result = false;
|
|
DXGI_ADAPTER_DESC adapterDesc;
|
|
if (SUCCEEDED(IDXGIAdapter_GetDesc(p_adapter, &adapterDesc))) {
|
|
if (adapterDesc.VendorId == 0 &&
|
|
adapterDesc.DeviceId == 0 &&
|
|
!wcscmp(L"ROOT\\SraKmd\\0000", adapterDesc.Description))
|
|
result = true;
|
|
}
|
|
|
|
IDXGIAdapter_Release(p_adapter);
|
|
return result;
|
|
}
|
|
|
|
static bool isNvidiaHardware(ID3D11Device *d3ddev)
|
|
{
|
|
IDXGIAdapter *p_adapter = D3D11DeviceAdapter(d3ddev);
|
|
if (!p_adapter)
|
|
return false;
|
|
|
|
DXGI_ADAPTER_DESC adapterDesc;
|
|
if (FAILED(IDXGIAdapter_GetDesc(p_adapter, &adapterDesc)))
|
|
adapterDesc.VendorId = 0;
|
|
IDXGIAdapter_Release(p_adapter);
|
|
|
|
return adapterDesc.VendorId == GPU_MANUFACTURER_NVIDIA;
|
|
}
|
|
|
|
bool CanUseVoutPool(d3d11_device_t *d3d_dev, UINT slices)
|
|
{
|
|
#if VLC_WINSTORE_APP
|
|
/* Phones and the Xbox are memory constrained, rely on the d3d11va pool
|
|
* which is always smaller, we still get direct rendering from the decoder */
|
|
return false;
|
|
#else
|
|
/* NVIDIA cards crash when calling CreateVideoDecoderOutputView
|
|
* on more than 30 slices */
|
|
return slices <= 30 || !isNvidiaHardware(d3d_dev->d3ddevice);
|
|
#endif
|
|
}
|
|
|
|
int D3D11CheckDriverVersion(d3d11_device_t *d3d_dev, UINT vendorId, const struct wddm_version *min_ver)
|
|
{
|
|
IDXGIAdapter *pAdapter = D3D11DeviceAdapter(d3d_dev->d3ddevice);
|
|
if (!pAdapter)
|
|
return VLC_EGENERIC;
|
|
|
|
DXGI_ADAPTER_DESC adapterDesc;
|
|
HRESULT hr = IDXGIAdapter_GetDesc(pAdapter, &adapterDesc);
|
|
IDXGIAdapter_Release(pAdapter);
|
|
if (FAILED(hr))
|
|
return VLC_EGENERIC;
|
|
|
|
if (vendorId && adapterDesc.VendorId != vendorId)
|
|
return VLC_SUCCESS;
|
|
|
|
if (min_ver->wddm)
|
|
{
|
|
if (d3d_dev->WDDM.wddm > min_ver->wddm)
|
|
return VLC_SUCCESS;
|
|
else if (d3d_dev->WDDM.wddm != min_ver->wddm)
|
|
return VLC_EGENERIC;
|
|
}
|
|
if (min_ver->d3d_features)
|
|
{
|
|
if (d3d_dev->WDDM.d3d_features > min_ver->d3d_features)
|
|
return VLC_SUCCESS;
|
|
else if (d3d_dev->WDDM.d3d_features != min_ver->d3d_features)
|
|
return VLC_EGENERIC;
|
|
}
|
|
if (min_ver->revision)
|
|
{
|
|
if (d3d_dev->WDDM.revision > min_ver->revision)
|
|
return VLC_SUCCESS;
|
|
else if (d3d_dev->WDDM.revision != min_ver->revision)
|
|
return VLC_EGENERIC;
|
|
}
|
|
if (min_ver->build)
|
|
{
|
|
if (d3d_dev->WDDM.build > min_ver->build)
|
|
return VLC_SUCCESS;
|
|
else if (d3d_dev->WDDM.build != min_ver->build)
|
|
return VLC_EGENERIC;
|
|
}
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
/* test formats that should work but sometimes have issues on some platforms */
|
|
static bool CanReallyUseFormat(vlc_object_t *obj, d3d11_device_t *d3d_dev,
|
|
vlc_fourcc_t i_chroma, DXGI_FORMAT dxgi)
|
|
{
|
|
bool result = true;
|
|
if (dxgi == DXGI_FORMAT_UNKNOWN)
|
|
return true;
|
|
|
|
if (is_d3d11_opaque(i_chroma))
|
|
return true;
|
|
|
|
ID3D11Texture2D *texture = NULL;
|
|
D3D11_TEXTURE2D_DESC texDesc;
|
|
ZeroMemory(&texDesc, sizeof(texDesc));
|
|
texDesc.MipLevels = 1;
|
|
texDesc.SampleDesc.Count = 1;
|
|
texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
|
|
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
|
texDesc.Usage = D3D11_USAGE_DYNAMIC;
|
|
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
texDesc.ArraySize = 1;
|
|
texDesc.Format = dxgi;
|
|
texDesc.Height = 144;
|
|
texDesc.Width = 176;
|
|
HRESULT hr = ID3D11Device_CreateTexture2D( d3d_dev->d3ddevice, &texDesc, NULL, &texture );
|
|
if (FAILED(hr))
|
|
{
|
|
msg_Dbg(obj, "cannot allocate a writable texture type %s. (hr=0x%lX)", DxgiFormatToStr(dxgi), hr);
|
|
return false;
|
|
}
|
|
|
|
D3D11_MAPPED_SUBRESOURCE mappedResource;
|
|
hr = ID3D11DeviceContext_Map(d3d_dev->d3dcontext, (ID3D11Resource*)texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
|
|
if (FAILED(hr))
|
|
{
|
|
msg_Err(obj, "The texture type %s cannot be mapped. (hr=0x%lX)", DxgiFormatToStr(dxgi), hr);
|
|
result = false;
|
|
goto done;
|
|
}
|
|
ID3D11DeviceContext_Unmap(d3d_dev->d3dcontext, (ID3D11Resource*)texture, 0);
|
|
|
|
if (dxgi == DXGI_FORMAT_YUY2)
|
|
{
|
|
const vlc_chroma_description_t *p_chroma_desc = vlc_fourcc_GetChromaDescription( i_chroma );
|
|
if( !p_chroma_desc )
|
|
{
|
|
msg_Err(obj, "No pixel format for %4.4s", (const char*)&i_chroma);
|
|
result = false;
|
|
goto done;
|
|
}
|
|
|
|
if (mappedResource.RowPitch >= 2 * (texDesc.Width * p_chroma_desc->p[0].w.num / p_chroma_desc->p[0].w.den * p_chroma_desc->pixel_size))
|
|
{
|
|
msg_Err(obj, "Bogus %4.4s pitch detected type %s. %d should be %d", (const char*)&i_chroma,
|
|
DxgiFormatToStr(dxgi), mappedResource.RowPitch,
|
|
(texDesc.Width * p_chroma_desc->p[0].w.num / p_chroma_desc->p[0].w.den * p_chroma_desc->pixel_size));
|
|
result = false;
|
|
goto done;
|
|
}
|
|
|
|
}
|
|
done:
|
|
ID3D11Texture2D_Release(texture);
|
|
|
|
return result;
|
|
}
|
|
|
|
#undef FindD3D11Format
|
|
const d3d_format_t *FindD3D11Format(vlc_object_t *o,
|
|
d3d11_device_t *d3d_dev,
|
|
vlc_fourcc_t i_src_chroma,
|
|
bool rgb_only,
|
|
uint8_t bits_per_channel,
|
|
uint8_t widthDenominator,
|
|
uint8_t heightDenominator,
|
|
bool allow_opaque,
|
|
UINT supportFlags)
|
|
{
|
|
supportFlags |= D3D11_FORMAT_SUPPORT_TEXTURE2D;
|
|
for (const d3d_format_t *output_format = GetRenderFormatList();
|
|
output_format->name != NULL; ++output_format)
|
|
{
|
|
if (i_src_chroma && i_src_chroma != output_format->fourcc)
|
|
continue;
|
|
if (bits_per_channel && bits_per_channel > output_format->bitsPerChannel)
|
|
continue;
|
|
if (!allow_opaque && is_d3d11_opaque(output_format->fourcc))
|
|
continue;
|
|
if (rgb_only && vlc_fourcc_IsYUV(output_format->fourcc))
|
|
continue;
|
|
if (widthDenominator && widthDenominator < output_format->widthDenominator)
|
|
continue;
|
|
if (heightDenominator && heightDenominator < output_format->heightDenominator)
|
|
continue;
|
|
|
|
DXGI_FORMAT textureFormat;
|
|
if (output_format->formatTexture == DXGI_FORMAT_UNKNOWN)
|
|
textureFormat = output_format->resourceFormat[0];
|
|
else
|
|
textureFormat = output_format->formatTexture;
|
|
|
|
if( DeviceSupportsFormat( d3d_dev->d3ddevice, textureFormat, supportFlags ) &&
|
|
CanReallyUseFormat(o, d3d_dev, output_format->fourcc, output_format->formatTexture) )
|
|
return output_format;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#undef AllocateTextures
|
|
int AllocateTextures( vlc_object_t *obj, d3d11_device_t *d3d_dev,
|
|
const d3d_format_t *cfg, const video_format_t *fmt,
|
|
unsigned pool_size, ID3D11Texture2D *textures[] )
|
|
{
|
|
plane_t planes[PICTURE_PLANE_MAX];
|
|
int plane, plane_count;
|
|
HRESULT hr;
|
|
ID3D11Texture2D *slicedTexture = NULL;
|
|
D3D11_TEXTURE2D_DESC texDesc;
|
|
ZeroMemory(&texDesc, sizeof(texDesc));
|
|
texDesc.MipLevels = 1;
|
|
texDesc.SampleDesc.Count = 1;
|
|
texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
|
|
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
|
if (is_d3d11_opaque(fmt->i_chroma)) {
|
|
texDesc.BindFlags |= D3D11_BIND_DECODER;
|
|
texDesc.Usage = D3D11_USAGE_DEFAULT;
|
|
texDesc.CPUAccessFlags = 0;
|
|
} else {
|
|
texDesc.Usage = D3D11_USAGE_DYNAMIC;
|
|
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
}
|
|
texDesc.ArraySize = pool_size;
|
|
|
|
const vlc_chroma_description_t *p_chroma_desc = vlc_fourcc_GetChromaDescription( fmt->i_chroma );
|
|
if( !p_chroma_desc )
|
|
return VLC_EGENERIC;
|
|
|
|
if (cfg->formatTexture == DXGI_FORMAT_UNKNOWN) {
|
|
if (p_chroma_desc->plane_count == 0)
|
|
{
|
|
msg_Dbg(obj, "failed to get the pixel format planes for %4.4s", (char *)&fmt->i_chroma);
|
|
return VLC_EGENERIC;
|
|
}
|
|
assert(p_chroma_desc->plane_count <= D3D11_MAX_SHADER_VIEW);
|
|
plane_count = p_chroma_desc->plane_count;
|
|
|
|
texDesc.Format = cfg->resourceFormat[0];
|
|
assert(cfg->resourceFormat[1] == cfg->resourceFormat[0]);
|
|
assert(cfg->resourceFormat[2] == cfg->resourceFormat[0]);
|
|
|
|
for( int i = 0; i < plane_count; i++ )
|
|
{
|
|
plane_t *p = &planes[i];
|
|
|
|
p->i_lines = fmt->i_height * p_chroma_desc->p[i].h.num / p_chroma_desc->p[i].h.den;
|
|
p->i_visible_lines = fmt->i_visible_height * p_chroma_desc->p[i].h.num / p_chroma_desc->p[i].h.den;
|
|
p->i_pitch = fmt->i_width * p_chroma_desc->p[i].w.num / p_chroma_desc->p[i].w.den * p_chroma_desc->pixel_size;
|
|
p->i_visible_pitch = fmt->i_visible_width * p_chroma_desc->p[i].w.num / p_chroma_desc->p[i].w.den * p_chroma_desc->pixel_size;
|
|
p->i_pixel_pitch = p_chroma_desc->pixel_size;
|
|
}
|
|
} else {
|
|
plane_count = 1;
|
|
texDesc.Format = cfg->formatTexture;
|
|
texDesc.Height = fmt->i_height;
|
|
texDesc.Width = fmt->i_width;
|
|
|
|
hr = ID3D11Device_CreateTexture2D( d3d_dev->d3ddevice, &texDesc, NULL, &slicedTexture );
|
|
if (FAILED(hr)) {
|
|
msg_Err(obj, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
for (unsigned picture_count = 0; picture_count < pool_size; picture_count++) {
|
|
for (plane = 0; plane < plane_count; plane++)
|
|
{
|
|
if (slicedTexture) {
|
|
textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = slicedTexture;
|
|
ID3D11Texture2D_AddRef(slicedTexture);
|
|
} else {
|
|
texDesc.Height = fmt->i_height * p_chroma_desc->p[plane].h.num / p_chroma_desc->p[plane].h.den;
|
|
texDesc.Width = fmt->i_width * p_chroma_desc->p[plane].w.num / p_chroma_desc->p[plane].w.den;
|
|
hr = ID3D11Device_CreateTexture2D( d3d_dev->d3ddevice, &texDesc, NULL, &textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] );
|
|
if (FAILED(hr)) {
|
|
msg_Err(obj, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
for (; plane < D3D11_MAX_SHADER_VIEW; plane++) {
|
|
if (!cfg->resourceFormat[plane])
|
|
textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = NULL;
|
|
else
|
|
{
|
|
textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = textures[picture_count * D3D11_MAX_SHADER_VIEW];
|
|
ID3D11Texture2D_AddRef(textures[picture_count * D3D11_MAX_SHADER_VIEW + plane]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (slicedTexture)
|
|
ID3D11Texture2D_Release(slicedTexture);
|
|
return VLC_SUCCESS;
|
|
error:
|
|
if (slicedTexture)
|
|
ID3D11Texture2D_Release(slicedTexture);
|
|
return VLC_EGENERIC;
|
|
}
|
|
|
|
#if !VLC_WINSTORE_APP
|
|
static HINSTANCE Direct3D11LoadShaderLibrary(void)
|
|
{
|
|
HINSTANCE instance = NULL;
|
|
/* d3dcompiler_47 is the latest on windows 8.1 */
|
|
for (int i = 47; i > 41; --i) {
|
|
TCHAR filename[19];
|
|
_sntprintf(filename, 19, TEXT("D3DCOMPILER_%d.dll"), i);
|
|
instance = LoadLibrary(filename);
|
|
if (instance) break;
|
|
}
|
|
return instance;
|
|
}
|
|
#endif
|
|
|
|
#undef D3D11_Create
|
|
int D3D11_Create(vlc_object_t *obj, d3d11_handle_t *hd3d, bool with_shaders)
|
|
{
|
|
#if !VLC_WINSTORE_APP
|
|
#if !defined(NDEBUG) && defined(HAVE_DXGIDEBUG_H)
|
|
hd3d->dxgidebug_dll = NULL;
|
|
#endif
|
|
hd3d->hdll = LoadLibrary(TEXT("D3D11.DLL"));
|
|
if (!hd3d->hdll)
|
|
{
|
|
msg_Warn(obj, "cannot load d3d11.dll, aborting");
|
|
return VLC_EGENERIC;
|
|
}
|
|
|
|
if (with_shaders)
|
|
{
|
|
hd3d->compiler_dll = Direct3D11LoadShaderLibrary();
|
|
if (!hd3d->compiler_dll) {
|
|
msg_Err(obj, "cannot load d3dcompiler.dll, aborting");
|
|
FreeLibrary(hd3d->hdll);
|
|
return VLC_EGENERIC;
|
|
}
|
|
|
|
hd3d->OurD3DCompile = (void *)GetProcAddress(hd3d->compiler_dll, "D3DCompile");
|
|
if (!hd3d->OurD3DCompile) {
|
|
msg_Err(obj, "Cannot locate reference to D3DCompile in d3dcompiler DLL");
|
|
FreeLibrary(hd3d->compiler_dll);
|
|
FreeLibrary(hd3d->hdll);
|
|
return VLC_EGENERIC;
|
|
}
|
|
}
|
|
#endif
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
void D3D11_Destroy(d3d11_handle_t *hd3d)
|
|
{
|
|
#if !VLC_WINSTORE_APP
|
|
# if !defined(NDEBUG) && defined(HAVE_DXGIDEBUG_H)
|
|
if (IsDebuggerPresent())
|
|
{
|
|
hd3d->dxgidebug_dll = LoadLibrary(TEXT("DXGIDEBUG.DLL"));
|
|
HRESULT (WINAPI * pf_DXGIGetDebugInterface)(const GUID *riid, void **ppDebug) = NULL;
|
|
if (hd3d->dxgidebug_dll)
|
|
pf_DXGIGetDebugInterface =
|
|
(void *)GetProcAddress(hd3d->dxgidebug_dll, "DXGIGetDebugInterface");
|
|
if (pf_DXGIGetDebugInterface) {
|
|
IDXGIDebug *pDXGIDebug;
|
|
if (SUCCEEDED(pf_DXGIGetDebugInterface(&IID_IDXGIDebug, (void**)&pDXGIDebug)))
|
|
{
|
|
IDXGIDebug_ReportLiveObjects(pDXGIDebug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);
|
|
IDXGIDebug_Release(pDXGIDebug);
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
if (hd3d->hdll)
|
|
FreeLibrary(hd3d->hdll);
|
|
|
|
if (hd3d->compiler_dll)
|
|
{
|
|
FreeLibrary(hd3d->compiler_dll);
|
|
hd3d->compiler_dll = NULL;
|
|
}
|
|
hd3d->OurD3DCompile = NULL;
|
|
|
|
#if !defined(NDEBUG) && defined(HAVE_DXGIDEBUG_H)
|
|
if (hd3d->dxgidebug_dll)
|
|
FreeLibrary(hd3d->dxgidebug_dll);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
#undef D3D11_LogProcessorSupport
|
|
void D3D11_LogProcessorSupport(vlc_object_t *o,
|
|
ID3D11VideoProcessorEnumerator *processorEnumerator)
|
|
{
|
|
UINT flags;
|
|
HRESULT hr;
|
|
for (int format = 0; format < 188; format++) {
|
|
hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, format, &flags);
|
|
if (FAILED(hr))
|
|
continue;
|
|
const char *name = DxgiFormatToStr(format);
|
|
const char *support = NULL;
|
|
if ((flags & (D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT|D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
|
|
== (D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT|D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
|
|
support = "input/output";
|
|
else if (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT)
|
|
support = "input";
|
|
else if (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT)
|
|
support = "output";
|
|
if (support)
|
|
{
|
|
if (name)
|
|
msg_Dbg(o, "processor format %s is supported for %s", name, support);
|
|
else
|
|
msg_Dbg(o, "processor format (%d) is supported for %s", format, support);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|