134ffe924f
Intel committed an NDA disclaimer on each source file. The stated intention was that the NDA "added to OBS doesn't apply to open source code once it's been accepted by the community. You can remove it for your modifications". This quote is from an email chain involving Intel's legal team and developers. The NDA in the source files mistakenly triggers source code scanners that look for license violations. I have removed the comments that contain the NDA.
529 lines
14 KiB
C++
529 lines
14 KiB
C++
#include "common_directx11.h"
|
|
|
|
#include <map>
|
|
|
|
ID3D11Device *g_pD3D11Device;
|
|
ID3D11DeviceContext *g_pD3D11Ctx;
|
|
IDXGIFactory2 *g_pDXGIFactory;
|
|
IDXGIAdapter *g_pAdapter;
|
|
|
|
std::map<mfxMemId *, mfxHDL> allocResponses;
|
|
std::map<mfxHDL, mfxFrameAllocResponse> allocDecodeResponses;
|
|
std::map<mfxHDL, int> allocDecodeRefCount;
|
|
|
|
typedef struct {
|
|
mfxMemId memId;
|
|
mfxMemId memIdStage;
|
|
mfxU16 rw;
|
|
} CustomMemId;
|
|
|
|
const struct {
|
|
mfxIMPL impl; // actual implementation
|
|
mfxU32 adapterID; // device adapter number
|
|
} implTypes[] = {{MFX_IMPL_HARDWARE, 0},
|
|
{MFX_IMPL_HARDWARE2, 1},
|
|
{MFX_IMPL_HARDWARE3, 2},
|
|
{MFX_IMPL_HARDWARE4, 3}};
|
|
|
|
// =================================================================
|
|
// DirectX functionality required to manage DX11 device and surfaces
|
|
//
|
|
|
|
IDXGIAdapter *GetIntelDeviceAdapterHandle(mfxSession session)
|
|
{
|
|
mfxU32 adapterNum = 0;
|
|
mfxIMPL impl;
|
|
|
|
MFXQueryIMPL(session, &impl);
|
|
|
|
mfxIMPL baseImpl = MFX_IMPL_BASETYPE(
|
|
impl); // Extract Media SDK base implementation type
|
|
|
|
// get corresponding adapter number
|
|
for (mfxU8 i = 0; i < sizeof(implTypes) / sizeof(implTypes[0]); i++) {
|
|
if (implTypes[i].impl == baseImpl) {
|
|
adapterNum = implTypes[i].adapterID;
|
|
break;
|
|
}
|
|
}
|
|
|
|
HRESULT hres = CreateDXGIFactory1(__uuidof(IDXGIFactory2),
|
|
(void **)(&g_pDXGIFactory));
|
|
if (FAILED(hres))
|
|
return NULL;
|
|
|
|
IDXGIAdapter *adapter;
|
|
hres = g_pDXGIFactory->EnumAdapters(adapterNum, &adapter);
|
|
if (FAILED(hres))
|
|
return NULL;
|
|
|
|
return adapter;
|
|
}
|
|
|
|
// Create HW device context
|
|
mfxStatus CreateHWDevice(mfxSession session, mfxHDL *deviceHandle, HWND hWnd,
|
|
bool bCreateSharedHandles)
|
|
{
|
|
//Note: not using bCreateSharedHandles for DX11 -- for API consistency only
|
|
hWnd; // Window handle not required by DX11 since we do not showcase rendering.
|
|
bCreateSharedHandles; // For rendering, not used here. Just for consistencies sake.
|
|
|
|
HRESULT hres = S_OK;
|
|
|
|
static D3D_FEATURE_LEVEL FeatureLevels[] = {D3D_FEATURE_LEVEL_11_1,
|
|
D3D_FEATURE_LEVEL_11_0,
|
|
D3D_FEATURE_LEVEL_10_1,
|
|
D3D_FEATURE_LEVEL_10_0};
|
|
D3D_FEATURE_LEVEL pFeatureLevelsOut;
|
|
|
|
g_pAdapter = GetIntelDeviceAdapterHandle(session);
|
|
if (NULL == g_pAdapter)
|
|
return MFX_ERR_DEVICE_FAILED;
|
|
|
|
UINT dxFlags = 0;
|
|
//UINT dxFlags = D3D11_CREATE_DEVICE_DEBUG;
|
|
|
|
hres = D3D11CreateDevice(
|
|
g_pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, dxFlags,
|
|
FeatureLevels,
|
|
(sizeof(FeatureLevels) / sizeof(FeatureLevels[0])),
|
|
D3D11_SDK_VERSION, &g_pD3D11Device, &pFeatureLevelsOut,
|
|
&g_pD3D11Ctx);
|
|
if (FAILED(hres))
|
|
return MFX_ERR_DEVICE_FAILED;
|
|
|
|
// turn on multithreading for the DX11 context
|
|
CComQIPtr<ID3D10Multithread> p_mt(g_pD3D11Ctx);
|
|
if (p_mt)
|
|
p_mt->SetMultithreadProtected(true);
|
|
else
|
|
return MFX_ERR_DEVICE_FAILED;
|
|
|
|
*deviceHandle = (mfxHDL)g_pD3D11Device;
|
|
|
|
return MFX_ERR_NONE;
|
|
}
|
|
|
|
void SetHWDeviceContext(CComPtr<ID3D11DeviceContext> devCtx)
|
|
{
|
|
g_pD3D11Ctx = devCtx;
|
|
devCtx->GetDevice(&g_pD3D11Device);
|
|
}
|
|
|
|
// Free HW device context
|
|
void CleanupHWDevice()
|
|
{
|
|
if (g_pAdapter) {
|
|
g_pAdapter->Release();
|
|
g_pAdapter = NULL;
|
|
}
|
|
if (g_pD3D11Device) {
|
|
g_pD3D11Device->Release();
|
|
g_pD3D11Device = NULL;
|
|
}
|
|
if (g_pD3D11Ctx) {
|
|
g_pD3D11Ctx->Release();
|
|
g_pD3D11Ctx = NULL;
|
|
}
|
|
if (g_pDXGIFactory) {
|
|
g_pDXGIFactory->Release();
|
|
g_pDXGIFactory = NULL;
|
|
}
|
|
}
|
|
|
|
CComPtr<ID3D11DeviceContext> GetHWDeviceContext()
|
|
{
|
|
return g_pD3D11Ctx;
|
|
}
|
|
|
|
/* (Hugh) Functions currently unused */
|
|
#if 0
|
|
void ClearYUVSurfaceD3D(mfxMemId memId)
|
|
{
|
|
// TBD
|
|
}
|
|
|
|
void ClearRGBSurfaceD3D(mfxMemId memId)
|
|
{
|
|
// TBD
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Intel Media SDK memory allocator entrypoints....
|
|
//
|
|
mfxStatus _simple_alloc(mfxFrameAllocRequest *request,
|
|
mfxFrameAllocResponse *response)
|
|
{
|
|
HRESULT hRes;
|
|
|
|
// Determine surface format
|
|
DXGI_FORMAT format;
|
|
if (MFX_FOURCC_NV12 == request->Info.FourCC)
|
|
format = DXGI_FORMAT_NV12;
|
|
else if (MFX_FOURCC_RGB4 == request->Info.FourCC)
|
|
format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
else if (MFX_FOURCC_YUY2 == request->Info.FourCC)
|
|
format = DXGI_FORMAT_YUY2;
|
|
else if (MFX_FOURCC_P8 ==
|
|
request->Info
|
|
.FourCC) //|| MFX_FOURCC_P8_TEXTURE == request->Info.FourCC
|
|
format = DXGI_FORMAT_P8;
|
|
else
|
|
format = DXGI_FORMAT_UNKNOWN;
|
|
|
|
if (DXGI_FORMAT_UNKNOWN == format)
|
|
return MFX_ERR_UNSUPPORTED;
|
|
|
|
// Allocate custom container to keep texture and stage buffers for each surface
|
|
// Container also stores the intended read and/or write operation.
|
|
CustomMemId **mids = (CustomMemId **)calloc(request->NumFrameSuggested,
|
|
sizeof(CustomMemId *));
|
|
if (!mids)
|
|
return MFX_ERR_MEMORY_ALLOC;
|
|
|
|
for (int i = 0; i < request->NumFrameSuggested; i++) {
|
|
mids[i] = (CustomMemId *)calloc(1, sizeof(CustomMemId));
|
|
if (!mids[i]) {
|
|
return MFX_ERR_MEMORY_ALLOC;
|
|
}
|
|
mids[i]->rw = request->Type &
|
|
0xF000; // Set intended read/write operation
|
|
}
|
|
|
|
request->Type = request->Type & 0x0FFF;
|
|
|
|
// because P8 data (bitstream) for h264 encoder should be allocated by CreateBuffer()
|
|
// but P8 data (MBData) for MPEG2 encoder should be allocated by CreateTexture2D()
|
|
if (request->Info.FourCC == MFX_FOURCC_P8) {
|
|
D3D11_BUFFER_DESC desc = {0};
|
|
|
|
if (!request->NumFrameSuggested)
|
|
return MFX_ERR_MEMORY_ALLOC;
|
|
|
|
desc.ByteWidth = request->Info.Width * request->Info.Height;
|
|
desc.Usage = D3D11_USAGE_STAGING;
|
|
desc.BindFlags = 0;
|
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
|
desc.MiscFlags = 0;
|
|
desc.StructureByteStride = 0;
|
|
|
|
ID3D11Buffer *buffer = 0;
|
|
hRes = g_pD3D11Device->CreateBuffer(&desc, 0, &buffer);
|
|
if (FAILED(hRes))
|
|
return MFX_ERR_MEMORY_ALLOC;
|
|
|
|
mids[0]->memId = reinterpret_cast<ID3D11Texture2D *>(buffer);
|
|
} else {
|
|
D3D11_TEXTURE2D_DESC desc = {0};
|
|
|
|
desc.Width = request->Info.Width;
|
|
desc.Height = request->Info.Height;
|
|
desc.MipLevels = 1;
|
|
desc.ArraySize = 1; // number of subresources is 1 in this case
|
|
desc.Format = format;
|
|
desc.SampleDesc.Count = 1;
|
|
desc.Usage = D3D11_USAGE_DEFAULT;
|
|
desc.BindFlags = D3D11_BIND_DECODER;
|
|
desc.MiscFlags = 0;
|
|
//desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
|
|
|
|
if ((MFX_MEMTYPE_FROM_VPPIN & request->Type) &&
|
|
(DXGI_FORMAT_B8G8R8A8_UNORM == desc.Format)) {
|
|
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
|
|
if (desc.ArraySize > 2)
|
|
return MFX_ERR_MEMORY_ALLOC;
|
|
}
|
|
|
|
if ((MFX_MEMTYPE_FROM_VPPOUT & request->Type) ||
|
|
(MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET &
|
|
request->Type)) {
|
|
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
|
|
if (desc.ArraySize > 2)
|
|
return MFX_ERR_MEMORY_ALLOC;
|
|
}
|
|
|
|
if (DXGI_FORMAT_P8 == desc.Format)
|
|
desc.BindFlags = 0;
|
|
|
|
ID3D11Texture2D *pTexture2D;
|
|
|
|
// Create surface textures
|
|
for (size_t i = 0;
|
|
i < request->NumFrameSuggested / desc.ArraySize; i++) {
|
|
hRes = g_pD3D11Device->CreateTexture2D(&desc, NULL,
|
|
&pTexture2D);
|
|
|
|
if (FAILED(hRes))
|
|
return MFX_ERR_MEMORY_ALLOC;
|
|
|
|
mids[i]->memId = pTexture2D;
|
|
}
|
|
|
|
desc.ArraySize = 1;
|
|
desc.Usage = D3D11_USAGE_STAGING;
|
|
desc.CPUAccessFlags =
|
|
D3D11_CPU_ACCESS_READ; // | D3D11_CPU_ACCESS_WRITE;
|
|
desc.BindFlags = 0;
|
|
desc.MiscFlags = 0;
|
|
//desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
|
|
|
|
// Create surface staging textures
|
|
for (size_t i = 0; i < request->NumFrameSuggested; i++) {
|
|
hRes = g_pD3D11Device->CreateTexture2D(&desc, NULL,
|
|
&pTexture2D);
|
|
|
|
if (FAILED(hRes))
|
|
return MFX_ERR_MEMORY_ALLOC;
|
|
|
|
mids[i]->memIdStage = pTexture2D;
|
|
}
|
|
}
|
|
|
|
response->mids = (mfxMemId *)mids;
|
|
response->NumFrameActual = request->NumFrameSuggested;
|
|
|
|
return MFX_ERR_NONE;
|
|
}
|
|
|
|
mfxStatus simple_alloc(mfxHDL pthis, mfxFrameAllocRequest *request,
|
|
mfxFrameAllocResponse *response)
|
|
{
|
|
mfxStatus sts = MFX_ERR_NONE;
|
|
|
|
if (request->Type & MFX_MEMTYPE_SYSTEM_MEMORY)
|
|
return MFX_ERR_UNSUPPORTED;
|
|
|
|
if (allocDecodeResponses.find(pthis) != allocDecodeResponses.end() &&
|
|
MFX_MEMTYPE_EXTERNAL_FRAME & request->Type &&
|
|
MFX_MEMTYPE_FROM_DECODE & request->Type) {
|
|
// Memory for this request was already allocated during manual allocation stage. Return saved response
|
|
// When decode acceleration device (DXVA) is created it requires a list of d3d surfaces to be passed.
|
|
// Therefore Media SDK will ask for the surface info/mids again at Init() stage, thus requiring us to return the saved response
|
|
// (No such restriction applies to Encode or VPP)
|
|
*response = allocDecodeResponses[pthis];
|
|
allocDecodeRefCount[pthis]++;
|
|
} else {
|
|
sts = _simple_alloc(request, response);
|
|
|
|
if (MFX_ERR_NONE == sts) {
|
|
if (MFX_MEMTYPE_EXTERNAL_FRAME & request->Type &&
|
|
MFX_MEMTYPE_FROM_DECODE & request->Type) {
|
|
// Decode alloc response handling
|
|
allocDecodeResponses[pthis] = *response;
|
|
allocDecodeRefCount[pthis]++;
|
|
} else {
|
|
// Encode and VPP alloc response handling
|
|
allocResponses[response->mids] = pthis;
|
|
}
|
|
}
|
|
}
|
|
|
|
return sts;
|
|
}
|
|
|
|
mfxStatus simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
|
|
{
|
|
pthis; // To suppress warning for this unused parameter
|
|
|
|
HRESULT hRes = S_OK;
|
|
|
|
D3D11_TEXTURE2D_DESC desc = {0};
|
|
D3D11_MAPPED_SUBRESOURCE lockedRect = {0};
|
|
|
|
CustomMemId *memId = (CustomMemId *)mid;
|
|
ID3D11Texture2D *pSurface = (ID3D11Texture2D *)memId->memId;
|
|
ID3D11Texture2D *pStage = (ID3D11Texture2D *)memId->memIdStage;
|
|
|
|
D3D11_MAP mapType = D3D11_MAP_READ;
|
|
UINT mapFlags = D3D11_MAP_FLAG_DO_NOT_WAIT;
|
|
|
|
if (NULL == pStage) {
|
|
hRes = g_pD3D11Ctx->Map(pSurface, 0, mapType, mapFlags,
|
|
&lockedRect);
|
|
desc.Format = DXGI_FORMAT_P8;
|
|
} else {
|
|
pSurface->GetDesc(&desc);
|
|
|
|
// copy data only in case of user wants to read from stored surface
|
|
if (memId->rw & WILL_READ)
|
|
g_pD3D11Ctx->CopySubresourceRegion(pStage, 0, 0, 0, 0,
|
|
pSurface, 0, NULL);
|
|
|
|
do {
|
|
hRes = g_pD3D11Ctx->Map(pStage, 0, mapType, mapFlags,
|
|
&lockedRect);
|
|
if (S_OK != hRes &&
|
|
DXGI_ERROR_WAS_STILL_DRAWING != hRes)
|
|
return MFX_ERR_LOCK_MEMORY;
|
|
} while (DXGI_ERROR_WAS_STILL_DRAWING == hRes);
|
|
}
|
|
|
|
if (FAILED(hRes))
|
|
return MFX_ERR_LOCK_MEMORY;
|
|
|
|
switch (desc.Format) {
|
|
case DXGI_FORMAT_NV12:
|
|
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
|
|
ptr->Y = (mfxU8 *)lockedRect.pData;
|
|
ptr->U = (mfxU8 *)lockedRect.pData +
|
|
desc.Height * lockedRect.RowPitch;
|
|
ptr->V = ptr->U + 1;
|
|
break;
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
|
|
ptr->B = (mfxU8 *)lockedRect.pData;
|
|
ptr->G = ptr->B + 1;
|
|
ptr->R = ptr->B + 2;
|
|
ptr->A = ptr->B + 3;
|
|
break;
|
|
case DXGI_FORMAT_YUY2:
|
|
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
|
|
ptr->Y = (mfxU8 *)lockedRect.pData;
|
|
ptr->U = ptr->Y + 1;
|
|
ptr->V = ptr->Y + 3;
|
|
break;
|
|
case DXGI_FORMAT_P8:
|
|
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
|
|
ptr->Y = (mfxU8 *)lockedRect.pData;
|
|
ptr->U = 0;
|
|
ptr->V = 0;
|
|
break;
|
|
default:
|
|
return MFX_ERR_LOCK_MEMORY;
|
|
}
|
|
|
|
return MFX_ERR_NONE;
|
|
}
|
|
|
|
mfxStatus simple_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
|
|
{
|
|
pthis; // To suppress warning for this unused parameter
|
|
|
|
CustomMemId *memId = (CustomMemId *)mid;
|
|
ID3D11Texture2D *pSurface = (ID3D11Texture2D *)memId->memId;
|
|
ID3D11Texture2D *pStage = (ID3D11Texture2D *)memId->memIdStage;
|
|
|
|
if (NULL == pStage) {
|
|
g_pD3D11Ctx->Unmap(pSurface, 0);
|
|
} else {
|
|
g_pD3D11Ctx->Unmap(pStage, 0);
|
|
// copy data only in case of user wants to write to stored surface
|
|
if (memId->rw & WILL_WRITE)
|
|
g_pD3D11Ctx->CopySubresourceRegion(pSurface, 0, 0, 0, 0,
|
|
pStage, 0, NULL);
|
|
}
|
|
|
|
if (ptr) {
|
|
ptr->Pitch = 0;
|
|
ptr->U = ptr->V = ptr->Y = 0;
|
|
ptr->A = ptr->R = ptr->G = ptr->B = 0;
|
|
}
|
|
|
|
return MFX_ERR_NONE;
|
|
}
|
|
|
|
mfxStatus simple_copytex(mfxHDL pthis, mfxMemId mid, mfxU32 tex_handle,
|
|
mfxU64 lock_key, mfxU64 *next_key)
|
|
{
|
|
pthis; // To suppress warning for this unused parameter
|
|
|
|
CustomMemId *memId = (CustomMemId *)mid;
|
|
ID3D11Texture2D *pSurface = (ID3D11Texture2D *)memId->memId;
|
|
|
|
IDXGIKeyedMutex *km;
|
|
ID3D11Texture2D *input_tex;
|
|
HRESULT hr;
|
|
|
|
hr = g_pD3D11Device->OpenSharedResource((HANDLE)(uintptr_t)tex_handle,
|
|
IID_ID3D11Texture2D,
|
|
(void **)&input_tex);
|
|
if (FAILED(hr)) {
|
|
return MFX_ERR_INVALID_HANDLE;
|
|
}
|
|
|
|
hr = input_tex->QueryInterface(IID_IDXGIKeyedMutex, (void **)&km);
|
|
if (FAILED(hr)) {
|
|
input_tex->Release();
|
|
return MFX_ERR_INVALID_HANDLE;
|
|
}
|
|
|
|
input_tex->SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM);
|
|
|
|
km->AcquireSync(lock_key, INFINITE);
|
|
|
|
D3D11_TEXTURE2D_DESC desc = {0};
|
|
input_tex->GetDesc(&desc);
|
|
D3D11_BOX SrcBox = {0, 0, 0, desc.Width, desc.Height, 1};
|
|
g_pD3D11Ctx->CopySubresourceRegion(pSurface, 0, 0, 0, 0, input_tex, 0,
|
|
&SrcBox);
|
|
|
|
km->ReleaseSync(*next_key);
|
|
|
|
return MFX_ERR_NONE;
|
|
}
|
|
|
|
mfxStatus simple_gethdl(mfxHDL pthis, mfxMemId mid, mfxHDL *handle)
|
|
{
|
|
pthis; // To suppress warning for this unused parameter
|
|
|
|
if (NULL == handle)
|
|
return MFX_ERR_INVALID_HANDLE;
|
|
|
|
mfxHDLPair *pPair = (mfxHDLPair *)handle;
|
|
CustomMemId *memId = (CustomMemId *)mid;
|
|
|
|
pPair->first = memId->memId; // surface texture
|
|
pPair->second = 0;
|
|
|
|
return MFX_ERR_NONE;
|
|
}
|
|
|
|
mfxStatus _simple_free(mfxFrameAllocResponse *response)
|
|
{
|
|
if (response->mids) {
|
|
for (mfxU32 i = 0; i < response->NumFrameActual; i++) {
|
|
if (response->mids[i]) {
|
|
CustomMemId *mid =
|
|
(CustomMemId *)response->mids[i];
|
|
ID3D11Texture2D *pSurface =
|
|
(ID3D11Texture2D *)mid->memId;
|
|
ID3D11Texture2D *pStage =
|
|
(ID3D11Texture2D *)mid->memIdStage;
|
|
|
|
if (pSurface)
|
|
pSurface->Release();
|
|
if (pStage)
|
|
pStage->Release();
|
|
|
|
free(mid);
|
|
}
|
|
}
|
|
free(response->mids);
|
|
response->mids = NULL;
|
|
}
|
|
|
|
return MFX_ERR_NONE;
|
|
}
|
|
|
|
mfxStatus simple_free(mfxHDL pthis, mfxFrameAllocResponse *response)
|
|
{
|
|
if (NULL == response)
|
|
return MFX_ERR_NULL_PTR;
|
|
|
|
if (allocResponses.find(response->mids) == allocResponses.end()) {
|
|
// Decode free response handling
|
|
if (--allocDecodeRefCount[pthis] == 0) {
|
|
_simple_free(response);
|
|
allocDecodeResponses.erase(pthis);
|
|
allocDecodeRefCount.erase(pthis);
|
|
}
|
|
} else {
|
|
// Encode and VPP free response handling
|
|
allocResponses.erase(response->mids);
|
|
_simple_free(response);
|
|
}
|
|
|
|
return MFX_ERR_NONE;
|
|
}
|