0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 13:08:50 +02:00
obs-studio/plugins/obs-qsv11/common_directx9.cpp
jp9000 f53df7da64 clang-format: Apply formatting
Code submissions have continually suffered from formatting
inconsistencies that constantly have to be addressed.  Using
clang-format simplifies this by making code formatting more consistent,
and allows automation of the code formatting so that maintainers can
focus more on the code itself instead of code formatting.
2019-06-23 23:49:10 -07:00

460 lines
12 KiB
C++

#include "common_directx9.h"
#include "device_directx9.h"
#include <objbase.h>
#include <initguid.h>
#include <d3d9.h>
#include <map>
#include <atlbase.h>
#define D3DFMT_NV12 (D3DFORMAT) MAKEFOURCC('N', 'V', '1', '2')
#define D3DFMT_YV12 (D3DFORMAT) MAKEFOURCC('Y', 'V', '1', '2')
#define D3DFMT_P010 (D3DFORMAT) MAKEFOURCC('P', '0', '1', '0')
#define MSDK_SAFE_FREE(X) \
{ \
if (X) { \
free(X); \
X = NULL; \
} \
}
std::map<mfxMemId *, mfxHDL> dx9_allocResponses;
std::map<mfxHDL, mfxFrameAllocResponse> dx9_allocDecodeResponses;
std::map<mfxHDL, int> dx9_allocDecodeRefCount;
CComPtr<IDirect3DDeviceManager9> m_manager;
CComPtr<IDirectXVideoDecoderService> m_decoderService;
CComPtr<IDirectXVideoProcessorService> m_processorService;
HANDLE m_hDecoder;
HANDLE m_hProcessor;
DWORD m_surfaceUsage;
CD3D9Device *g_hwdevice;
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}};
struct mfxAllocatorParams {
virtual ~mfxAllocatorParams(){};
};
struct D3DAllocatorParams : mfxAllocatorParams {
IDirect3DDeviceManager9 *pManager;
DWORD surfaceUsage;
D3DAllocatorParams() : pManager(), surfaceUsage() {}
};
mfxStatus DX9_Alloc_Init(D3DAllocatorParams *pParams)
{
D3DAllocatorParams *pd3dParams = 0;
pd3dParams = dynamic_cast<D3DAllocatorParams *>(pParams);
if (!pd3dParams)
return MFX_ERR_NOT_INITIALIZED;
m_manager = pd3dParams->pManager;
m_surfaceUsage = pd3dParams->surfaceUsage;
return MFX_ERR_NONE;
}
mfxStatus DX9_CreateHWDevice(mfxSession session, mfxHDL *deviceHandle, HWND,
bool)
{
mfxStatus result;
g_hwdevice = new CD3D9Device;
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;
}
}
POINT point = {0, 0};
HWND window = WindowFromPoint(point);
result = g_hwdevice->Init(window, 0, adapterNum);
if (result != MFX_ERR_NONE) {
return result;
}
g_hwdevice->GetHandle(MFX_HANDLE_D3D9_DEVICE_MANAGER, deviceHandle);
D3DAllocatorParams dx9_allocParam;
dx9_allocParam.pManager =
reinterpret_cast<IDirect3DDeviceManager9 *>(*deviceHandle);
DX9_Alloc_Init(&dx9_allocParam);
return MFX_ERR_NONE;
}
void DX9_CleanupHWDevice()
{
if (g_hwdevice) {
// g_hwdevice->Close();
delete g_hwdevice;
g_hwdevice = NULL;
}
if (m_manager && m_hDecoder) {
m_manager->CloseDeviceHandle(m_hDecoder);
m_manager = NULL;
m_hDecoder = NULL;
}
if (m_manager && m_hProcessor) {
m_manager->CloseDeviceHandle(m_hProcessor);
m_manager = NULL;
m_hProcessor = NULL;
}
if (m_decoderService) {
// delete m_decoderService;
m_decoderService = NULL;
}
if (m_processorService) {
// delete m_processorService;
m_processorService = NULL;
}
}
D3DFORMAT ConvertMfxFourccToD3dFormat(mfxU32 fourcc)
{
switch (fourcc) {
case MFX_FOURCC_NV12:
return D3DFMT_NV12;
case MFX_FOURCC_YV12:
return D3DFMT_YV12;
case MFX_FOURCC_YUY2:
return D3DFMT_YUY2;
case MFX_FOURCC_RGB3:
return D3DFMT_R8G8B8;
case MFX_FOURCC_RGB4:
return D3DFMT_A8R8G8B8;
case MFX_FOURCC_P8:
return D3DFMT_P8;
case MFX_FOURCC_P010:
return D3DFMT_P010;
case MFX_FOURCC_A2RGB10:
return D3DFMT_A2R10G10B10;
default:
return D3DFMT_UNKNOWN;
}
}
mfxStatus dx9_simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
{
pthis; // To suppress warning for this unused parameter
if (!ptr || !mid)
return MFX_ERR_NULL_PTR;
mfxHDLPair *dxmid = (mfxHDLPair *)mid;
IDirect3DSurface9 *pSurface =
static_cast<IDirect3DSurface9 *>(dxmid->first);
if (pSurface == 0)
return MFX_ERR_INVALID_HANDLE;
D3DSURFACE_DESC desc;
HRESULT hr = pSurface->GetDesc(&desc);
if (FAILED(hr))
return MFX_ERR_LOCK_MEMORY;
if (desc.Format != D3DFMT_NV12 && desc.Format != D3DFMT_YV12 &&
desc.Format != D3DFMT_YUY2 && desc.Format != D3DFMT_R8G8B8 &&
desc.Format != D3DFMT_A8R8G8B8 && desc.Format != D3DFMT_P8 &&
desc.Format != D3DFMT_P010 && desc.Format != D3DFMT_A2R10G10B10)
return MFX_ERR_LOCK_MEMORY;
D3DLOCKED_RECT locked;
hr = pSurface->LockRect(&locked, 0, D3DLOCK_NOSYSLOCK);
if (FAILED(hr))
return MFX_ERR_LOCK_MEMORY;
switch ((DWORD)desc.Format) {
case D3DFMT_NV12:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = (mfxU8 *)locked.pBits + desc.Height * locked.Pitch;
ptr->V = ptr->U + 1;
break;
case D3DFMT_YV12:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->V = ptr->Y + desc.Height * locked.Pitch;
ptr->U = ptr->V + (desc.Height * locked.Pitch) / 4;
break;
case D3DFMT_YUY2:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = ptr->Y + 1;
ptr->V = ptr->Y + 3;
break;
case D3DFMT_R8G8B8:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->B = (mfxU8 *)locked.pBits;
ptr->G = ptr->B + 1;
ptr->R = ptr->B + 2;
break;
case D3DFMT_A8R8G8B8:
case D3DFMT_A2R10G10B10:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->B = (mfxU8 *)locked.pBits;
ptr->G = ptr->B + 1;
ptr->R = ptr->B + 2;
ptr->A = ptr->B + 3;
break;
case D3DFMT_P8:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = 0;
ptr->V = 0;
break;
case D3DFMT_P010:
ptr->PitchHigh = (mfxU16)(locked.Pitch / (1 << 16));
ptr->PitchLow = (mfxU16)(locked.Pitch % (1 << 16));
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = (mfxU8 *)locked.pBits + desc.Height * locked.Pitch;
ptr->V = ptr->U + 1;
break;
}
return MFX_ERR_NONE;
}
mfxStatus dx9_simple_unlock(mfxHDL, mfxMemId mid, mfxFrameData *ptr)
{
if (!mid)
return MFX_ERR_NULL_PTR;
mfxHDLPair *dxmid = (mfxHDLPair *)mid;
IDirect3DSurface9 *pSurface =
static_cast<IDirect3DSurface9 *>(dxmid->first);
if (pSurface == 0)
return MFX_ERR_INVALID_HANDLE;
pSurface->UnlockRect();
if (NULL != ptr) {
ptr->Pitch = 0;
ptr->Y = 0;
ptr->U = 0;
ptr->V = 0;
}
return MFX_ERR_NONE;
}
mfxStatus dx9_simple_gethdl(mfxHDL, mfxMemId mid, mfxHDL *handle)
{
if (!mid || !handle)
return MFX_ERR_NULL_PTR;
mfxHDLPair *dxMid = (mfxHDLPair *)mid;
*handle = dxMid->first;
return MFX_ERR_NONE;
}
mfxStatus _dx9_simple_free(mfxFrameAllocResponse *response)
{
if (!response)
return MFX_ERR_NULL_PTR;
mfxStatus sts = MFX_ERR_NONE;
if (response->mids) {
for (mfxU32 i = 0; i < response->NumFrameActual; i++) {
if (response->mids[i]) {
mfxHDLPair *dxMids =
(mfxHDLPair *)response->mids[i];
static_cast<IDirect3DSurface9 *>(dxMids->first)
->Release();
}
}
MSDK_SAFE_FREE(response->mids[0]);
}
MSDK_SAFE_FREE(response->mids);
return sts;
}
mfxStatus dx9_simple_free(mfxHDL pthis, mfxFrameAllocResponse *response)
{
if (NULL == response)
return MFX_ERR_NULL_PTR;
if (dx9_allocResponses.find(response->mids) ==
dx9_allocResponses.end()) {
// Decode free response handling
if (--dx9_allocDecodeRefCount[pthis] == 0) {
_dx9_simple_free(response);
dx9_allocDecodeResponses.erase(pthis);
dx9_allocDecodeRefCount.erase(pthis);
}
} else {
// Encode and VPP free response handling
dx9_allocResponses.erase(response->mids);
_dx9_simple_free(response);
}
return MFX_ERR_NONE;
}
mfxStatus _dx9_simple_alloc(mfxFrameAllocRequest *request,
mfxFrameAllocResponse *response)
{
HRESULT hr;
MSDK_CHECK_POINTER(request, MFX_ERR_NULL_PTR);
if (request->NumFrameSuggested == 0)
return MFX_ERR_UNKNOWN;
D3DFORMAT format = ConvertMfxFourccToD3dFormat(request->Info.FourCC);
if (format == D3DFMT_UNKNOWN)
return MFX_ERR_UNSUPPORTED;
DWORD target;
if (MFX_MEMTYPE_DXVA2_DECODER_TARGET & request->Type) {
target = DXVA2_VideoDecoderRenderTarget;
} else if (MFX_MEMTYPE_DXVA2_PROCESSOR_TARGET & request->Type) {
target = DXVA2_VideoProcessorRenderTarget;
} else
return MFX_ERR_UNSUPPORTED;
IDirectXVideoAccelerationService *videoService = NULL;
if (target == DXVA2_VideoProcessorRenderTarget) {
if (!m_hProcessor) {
hr = m_manager->OpenDeviceHandle(&m_hProcessor);
if (FAILED(hr))
return MFX_ERR_MEMORY_ALLOC;
hr = m_manager->GetVideoService(
m_hProcessor, IID_IDirectXVideoProcessorService,
(void **)&m_processorService);
if (FAILED(hr))
return MFX_ERR_MEMORY_ALLOC;
}
videoService = m_processorService;
} else {
if (!m_hDecoder) {
hr = m_manager->OpenDeviceHandle(&m_hDecoder);
if (FAILED(hr))
return MFX_ERR_MEMORY_ALLOC;
hr = m_manager->GetVideoService(
m_hDecoder, IID_IDirectXVideoDecoderService,
(void **)&m_decoderService);
if (FAILED(hr))
return MFX_ERR_MEMORY_ALLOC;
}
videoService = m_decoderService;
}
mfxHDLPair *dxMids = NULL, **dxMidPtrs = NULL;
dxMids = (mfxHDLPair *)calloc(request->NumFrameSuggested,
sizeof(mfxHDLPair));
dxMidPtrs = (mfxHDLPair **)calloc(request->NumFrameSuggested,
sizeof(mfxHDLPair *));
if (!dxMids || !dxMidPtrs) {
MSDK_SAFE_FREE(dxMids);
MSDK_SAFE_FREE(dxMidPtrs);
return MFX_ERR_MEMORY_ALLOC;
}
response->mids = (mfxMemId *)dxMidPtrs;
response->NumFrameActual = request->NumFrameSuggested;
if (request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) {
for (int i = 0; i < request->NumFrameSuggested; i++) {
hr = videoService->CreateSurface(
request->Info.Width, request->Info.Height, 0,
format, D3DPOOL_DEFAULT, m_surfaceUsage, target,
(IDirect3DSurface9 **)&dxMids[i].first,
&dxMids[i].second);
if (FAILED(hr)) {
_dx9_simple_free(response);
MSDK_SAFE_FREE(dxMids);
return MFX_ERR_MEMORY_ALLOC;
}
dxMidPtrs[i] = &dxMids[i];
}
} else {
safe_array<IDirect3DSurface9 *> dxSrf(
new IDirect3DSurface9 *[request->NumFrameSuggested]);
if (!dxSrf.get()) {
MSDK_SAFE_FREE(dxMids);
return MFX_ERR_MEMORY_ALLOC;
}
hr = videoService->CreateSurface(
request->Info.Width, request->Info.Height,
request->NumFrameSuggested - 1, format, D3DPOOL_DEFAULT,
m_surfaceUsage, target, dxSrf.get(), NULL);
if (FAILED(hr)) {
MSDK_SAFE_FREE(dxMids);
return MFX_ERR_MEMORY_ALLOC;
}
for (int i = 0; i < request->NumFrameSuggested; i++) {
dxMids[i].first = dxSrf.get()[i];
dxMidPtrs[i] = &dxMids[i];
}
}
return MFX_ERR_NONE;
}
mfxStatus dx9_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 (dx9_allocDecodeResponses.find(pthis) !=
dx9_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 = dx9_allocDecodeResponses[pthis];
dx9_allocDecodeRefCount[pthis]++;
} else {
sts = _dx9_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
dx9_allocDecodeResponses[pthis] = *response;
dx9_allocDecodeRefCount[pthis]++;
} else {
// Encode and VPP alloc response handling
dx9_allocResponses[response->mids] = pthis;
}
}
}
return sts;
}