Use ComPtr for lifetime management in DXVA2

This commit is contained in:
Cameron Gutman 2024-07-30 22:41:29 -05:00
parent 9e811f54f1
commit 99749d4730
2 changed files with 66 additions and 97 deletions

View File

@ -26,7 +26,7 @@ DEFINE_GUID(DXVA2_ModeAV1_VLD_Profile0,0xb8be4ccb,0xcf53,0x46ba,0x8d,0x59,0xd6,0
#define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 #define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2
#endif #endif
#define SAFE_COM_RELEASE(x) if (x) { (x)->Release(); } using Microsoft::WRL::ComPtr;
typedef struct _VERTEX typedef struct _VERTEX
{ {
@ -36,25 +36,15 @@ typedef struct _VERTEX
DXVA2Renderer::DXVA2Renderer(int decoderSelectionPass) : DXVA2Renderer::DXVA2Renderer(int decoderSelectionPass) :
m_DecoderSelectionPass(decoderSelectionPass), m_DecoderSelectionPass(decoderSelectionPass),
m_DecService(nullptr),
m_Decoder(nullptr),
m_SurfacesUsed(0), m_SurfacesUsed(0),
m_Pool(nullptr), m_Pool(nullptr),
m_OverlayLock(0), m_OverlayLock(0),
m_Device(nullptr),
m_RenderTarget(nullptr),
m_ProcService(nullptr),
m_Processor(nullptr),
m_FrameIndex(0), m_FrameIndex(0),
m_BlockingPresent(false), m_BlockingPresent(false),
m_DeviceQuirks(0) m_DeviceQuirks(0)
{ {
RtlZeroMemory(m_DecSurfaces, sizeof(m_DecSurfaces));
RtlZeroMemory(&m_DXVAContext, sizeof(m_DXVAContext)); RtlZeroMemory(&m_DXVAContext, sizeof(m_DXVAContext));
RtlZeroMemory(m_OverlayVertexBuffers, sizeof(m_OverlayVertexBuffers));
RtlZeroMemory(m_OverlayTextures, sizeof(m_OverlayTextures));
// Use MMCSS scheduling for lower scheduling latency while we're streaming // Use MMCSS scheduling for lower scheduling latency while we're streaming
DwmEnableMMCSS(TRUE); DwmEnableMMCSS(TRUE);
} }
@ -63,23 +53,23 @@ DXVA2Renderer::~DXVA2Renderer()
{ {
DwmEnableMMCSS(FALSE); DwmEnableMMCSS(FALSE);
SAFE_COM_RELEASE(m_DecService); m_DecService.Reset();
SAFE_COM_RELEASE(m_Decoder); m_Decoder.Reset();
SAFE_COM_RELEASE(m_Device); m_Device.Reset();
SAFE_COM_RELEASE(m_RenderTarget); m_RenderTarget.Reset();
SAFE_COM_RELEASE(m_ProcService); m_ProcService.Reset();
SAFE_COM_RELEASE(m_Processor); m_Processor.Reset();
for (int i = 0; i < ARRAYSIZE(m_OverlayVertexBuffers); i++) { for (int i = 0; i < m_OverlayVertexBuffers.size(); i++) {
SAFE_COM_RELEASE(m_OverlayVertexBuffers[i]); m_OverlayVertexBuffers[i].Reset();
} }
for (int i = 0; i < ARRAYSIZE(m_OverlayTextures); i++) { for (int i = 0; i < m_OverlayTextures.size(); i++) {
SAFE_COM_RELEASE(m_OverlayTextures[i]); m_OverlayTextures[i].Reset();
} }
for (int i = 0; i < ARRAYSIZE(m_DecSurfaces); i++) { for (int i = 0; i < m_DecSurfaces.size(); i++) {
SAFE_COM_RELEASE(m_DecSurfaces[i]); m_DecSurfaces[i].Reset();
} }
if (m_Pool != nullptr) { if (m_Pool != nullptr) {
@ -96,12 +86,12 @@ AVBufferRef* DXVA2Renderer::ffPoolAlloc(void* opaque, FF_POOL_SIZE_TYPE)
{ {
DXVA2Renderer* me = reinterpret_cast<DXVA2Renderer*>(opaque); DXVA2Renderer* me = reinterpret_cast<DXVA2Renderer*>(opaque);
if (me->m_SurfacesUsed < ARRAYSIZE(me->m_DecSurfaces)) { if (me->m_SurfacesUsed < me->m_DecSurfaces.size()) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"DXVA2 decoder surface high-water mark: %d", "DXVA2 decoder surface high-water mark: %d",
me->m_SurfacesUsed); me->m_SurfacesUsed);
return av_buffer_create((uint8_t*)me->m_DecSurfaces[me->m_SurfacesUsed++], return av_buffer_create((uint8_t*)me->m_DecSurfacesRaw[me->m_SurfacesUsed++],
sizeof(*me->m_DecSurfaces), ffPoolDummyDelete, 0, 0); sizeof(me->m_DecSurfacesRaw[0]), ffPoolDummyDelete, 0, 0);
} }
return NULL; return NULL;
@ -110,10 +100,10 @@ AVBufferRef* DXVA2Renderer::ffPoolAlloc(void* opaque, FF_POOL_SIZE_TYPE)
bool DXVA2Renderer::prepareDecoderContext(AVCodecContext* context, AVDictionary**) bool DXVA2Renderer::prepareDecoderContext(AVCodecContext* context, AVDictionary**)
{ {
// m_DXVAContext.workaround and report_id already initialized elsewhere // m_DXVAContext.workaround and report_id already initialized elsewhere
m_DXVAContext.decoder = m_Decoder; m_DXVAContext.decoder = m_Decoder.Get();
m_DXVAContext.cfg = &m_Config; m_DXVAContext.cfg = &m_Config;
m_DXVAContext.surface = m_DecSurfaces; m_DXVAContext.surface = m_DecSurfacesRaw.data();
m_DXVAContext.surface_count = ARRAYSIZE(m_DecSurfaces); m_DXVAContext.surface_count = (unsigned int)m_DecSurfacesRaw.size();
context->hwaccel_context = &m_DXVAContext; context->hwaccel_context = &m_DXVAContext;
@ -124,7 +114,7 @@ bool DXVA2Renderer::prepareDecoderContext(AVCodecContext* context, AVDictionary*
) )
#endif #endif
m_Pool = av_buffer_pool_init2(ARRAYSIZE(m_DecSurfaces), this, ffPoolAlloc, nullptr); m_Pool = av_buffer_pool_init2(m_DecSurfaces.size(), this, ffPoolAlloc, nullptr);
if (!m_Pool) { if (!m_Pool) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed create buffer pool"); "Failed create buffer pool");
@ -162,8 +152,7 @@ bool DXVA2Renderer::initializeDecoder()
return false; return false;
} }
hr = DXVA2CreateVideoService(m_Device, IID_IDirectXVideoDecoderService, hr = DXVA2CreateVideoService(m_Device.Get(), IID_IDirectXVideoDecoderService, &m_DecService);
reinterpret_cast<void**>(&m_DecService));
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"DXVA2CreateVideoService(IID_IDirectXVideoDecoderService) failed: %x", "DXVA2CreateVideoService(IID_IDirectXVideoDecoderService) failed: %x",
@ -255,12 +244,12 @@ bool DXVA2Renderer::initializeDecoder()
SDL_assert(m_Desc.SampleHeight % 16 == 0); SDL_assert(m_Desc.SampleHeight % 16 == 0);
hr = m_DecService->CreateSurface(m_Desc.SampleWidth, hr = m_DecService->CreateSurface(m_Desc.SampleWidth,
m_Desc.SampleHeight, m_Desc.SampleHeight,
ARRAYSIZE(m_DecSurfaces) - 1, (UINT)m_DecSurfacesRaw.size() - 1,
m_Desc.Format, m_Desc.Format,
D3DPOOL_DEFAULT, D3DPOOL_DEFAULT,
0, 0,
DXVA2_VideoDecoderRenderTarget, DXVA2_VideoDecoderRenderTarget,
m_DecSurfaces, m_DecSurfacesRaw.data(),
nullptr); nullptr);
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
@ -269,8 +258,14 @@ bool DXVA2Renderer::initializeDecoder()
return false; return false;
} }
// Transfer ownership into ComPtrs
for (int i = 0; i < m_DecSurfaces.size(); i++) {
m_DecSurfaces[i].Attach(m_DecSurfacesRaw[i]);
}
hr = m_DecService->CreateVideoDecoder(chosenDeviceGuid, &m_Desc, &m_Config, hr = m_DecService->CreateVideoDecoder(chosenDeviceGuid, &m_Desc, &m_Config,
m_DecSurfaces, ARRAYSIZE(m_DecSurfaces), m_DecSurfacesRaw.data(),
(UINT)m_DecSurfacesRaw.size(),
&m_Decoder); &m_Decoder);
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
@ -301,8 +296,7 @@ bool DXVA2Renderer::initializeRenderer()
m_DisplayHeight = renderTargetDesc.Height; m_DisplayHeight = renderTargetDesc.Height;
if (!(m_DeviceQuirks & DXVA2_QUIRK_NO_VP)) { if (!(m_DeviceQuirks & DXVA2_QUIRK_NO_VP)) {
hr = DXVA2CreateVideoService(m_Device, IID_IDirectXVideoProcessorService, hr = DXVA2CreateVideoService(m_Device.Get(), IID_IDirectXVideoProcessorService, &m_ProcService);
reinterpret_cast<void**>(&m_ProcService));
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
@ -386,7 +380,7 @@ bool DXVA2Renderer::initializeQuirksForAdapter(IDirect3D9Ex* d3d9ex, int adapter
HRESULT hr; HRESULT hr;
SDL_assert(m_DeviceQuirks == 0); SDL_assert(m_DeviceQuirks == 0);
SDL_assert(m_Device == nullptr); SDL_assert(!m_Device);
{ {
bool ok; bool ok;
@ -466,7 +460,7 @@ bool DXVA2Renderer::initializeQuirksForAdapter(IDirect3D9Ex* d3d9ex, int adapter
bool DXVA2Renderer::isDecoderBlacklisted() bool DXVA2Renderer::isDecoderBlacklisted()
{ {
IDirect3D9* d3d9; ComPtr<IDirect3D9> d3d9;
HRESULT hr; HRESULT hr;
bool result = false; bool result = false;
@ -523,8 +517,6 @@ bool DXVA2Renderer::isDecoderBlacklisted()
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"GetDeviceCaps() failed: %x", hr); "GetDeviceCaps() failed: %x", hr);
} }
d3d9->Release();
} }
else { else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
@ -547,7 +539,7 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync)
SDL_VERSION(&info.version); SDL_VERSION(&info.version);
SDL_GetWindowWMInfo(window, &info); SDL_GetWindowWMInfo(window, &info);
IDirect3D9Ex* d3d9ex; ComPtr<IDirect3D9Ex> d3d9ex;
HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9ex); HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9ex);
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
@ -561,8 +553,7 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync)
// Initialize quirks *before* calling CreateDeviceEx() to allow our below // Initialize quirks *before* calling CreateDeviceEx() to allow our below
// logic to avoid a hang with NahimicOSD.dll's broken full-screen handling. // logic to avoid a hang with NahimicOSD.dll's broken full-screen handling.
if (!initializeQuirksForAdapter(d3d9ex, adapterIndex)) { if (!initializeQuirksForAdapter(d3d9ex.Get(), adapterIndex)) {
d3d9ex->Release();
return false; return false;
} }
@ -588,7 +579,6 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync)
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"GPU/driver doesn't support A2R10G10B10"); "GPU/driver doesn't support A2R10G10B10");
d3d9ex->Release();
return false; return false;
} }
} }
@ -685,9 +675,6 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync)
&d3dpp, &d3dpp,
d3dpp.Windowed ? nullptr : &currentMode, d3dpp.Windowed ? nullptr : &currentMode,
&m_Device); &m_Device);
d3d9ex->Release();
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"CreateDeviceEx() failed: %x", "CreateDeviceEx() failed: %x",
@ -810,16 +797,10 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type)
} }
SDL_AtomicLock(&m_OverlayLock); SDL_AtomicLock(&m_OverlayLock);
IDirect3DTexture9* oldTexture = m_OverlayTextures[type]; ComPtr<IDirect3DTexture9> oldTexture = std::move(m_OverlayTextures[type]);
m_OverlayTextures[type] = nullptr; ComPtr<IDirect3DVertexBuffer9> oldVertexBuffer = std::move(m_OverlayVertexBuffers[type]);
IDirect3DVertexBuffer9* oldVertexBuffer = m_OverlayVertexBuffers[type];
m_OverlayVertexBuffers[type] = nullptr;
SDL_AtomicUnlock(&m_OverlayLock); SDL_AtomicUnlock(&m_OverlayLock);
SAFE_COM_RELEASE(oldTexture);
SAFE_COM_RELEASE(oldVertexBuffer);
// If the overlay is disabled, we're done // If the overlay is disabled, we're done
if (!overlayEnabled) { if (!overlayEnabled) {
SDL_FreeSurface(newSurface); SDL_FreeSurface(newSurface);
@ -828,7 +809,7 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type)
// Create a dynamic texture to populate with our pixel data // Create a dynamic texture to populate with our pixel data
SDL_assert(!SDL_MUSTLOCK(newSurface)); SDL_assert(!SDL_MUSTLOCK(newSurface));
IDirect3DTexture9* newTexture = nullptr; ComPtr<IDirect3DTexture9> newTexture;
hr = m_Device->CreateTexture(newSurface->w, hr = m_Device->CreateTexture(newSurface->w,
newSurface->h, newSurface->h,
1, 1,
@ -849,7 +830,6 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type)
hr = newTexture->LockRect(0, &lockedRect, nullptr, D3DLOCK_DISCARD); hr = newTexture->LockRect(0, &lockedRect, nullptr, D3DLOCK_DISCARD);
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_FreeSurface(newSurface); SDL_FreeSurface(newSurface);
SAFE_COM_RELEASE(newTexture);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"IDirect3DTexture9::LockRect() failed: %x", "IDirect3DTexture9::LockRect() failed: %x",
hr); hr);
@ -890,7 +870,7 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type)
{renderRect.x+renderRect.w, renderRect.y, 0, 1, 1, 0} {renderRect.x+renderRect.w, renderRect.y, 0, 1, 1, 0}
}; };
IDirect3DVertexBuffer9* newVertexBuffer = nullptr; ComPtr<IDirect3DVertexBuffer9> newVertexBuffer;
hr = m_Device->CreateVertexBuffer(sizeof(verts), hr = m_Device->CreateVertexBuffer(sizeof(verts),
D3DUSAGE_WRITEONLY, D3DUSAGE_WRITEONLY,
D3DFVF_XYZRHW | D3DFVF_TEX1, D3DFVF_XYZRHW | D3DFVF_TEX1,
@ -898,7 +878,6 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type)
&newVertexBuffer, &newVertexBuffer,
nullptr); nullptr);
if (FAILED(hr)) { if (FAILED(hr)) {
SAFE_COM_RELEASE(newTexture);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"CreateVertexBuffer() failed: %x", "CreateVertexBuffer() failed: %x",
hr); hr);
@ -908,8 +887,6 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type)
PVOID targetVertexBuffer = nullptr; PVOID targetVertexBuffer = nullptr;
hr = newVertexBuffer->Lock(0, 0, &targetVertexBuffer, 0); hr = newVertexBuffer->Lock(0, 0, &targetVertexBuffer, 0);
if (FAILED(hr)) { if (FAILED(hr)) {
SAFE_COM_RELEASE(newTexture);
SAFE_COM_RELEASE(newVertexBuffer);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"IDirect3DVertexBuffer9::Lock() failed: %x", "IDirect3DVertexBuffer9::Lock() failed: %x",
hr); hr);
@ -921,8 +898,8 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type)
newVertexBuffer->Unlock(); newVertexBuffer->Unlock();
SDL_AtomicLock(&m_OverlayLock); SDL_AtomicLock(&m_OverlayLock);
m_OverlayVertexBuffers[type] = newVertexBuffer; m_OverlayVertexBuffers[type] = std::move(newVertexBuffer);
m_OverlayTextures[type] = newTexture; m_OverlayTextures[type] = std::move(newTexture);
SDL_AtomicUnlock(&m_OverlayLock); SDL_AtomicUnlock(&m_OverlayLock);
} }
@ -939,36 +916,30 @@ void DXVA2Renderer::renderOverlay(Overlay::OverlayType type)
return; return;
} }
IDirect3DTexture9* overlayTexture = m_OverlayTextures[type]; // Reference these objects so they don't immediately go away if the
IDirect3DVertexBuffer9* overlayVertexBuffer = m_OverlayVertexBuffers[type]; // overlay update thread tries to release them.
ComPtr<IDirect3DTexture9> overlayTexture = m_OverlayTextures[type];
ComPtr<IDirect3DVertexBuffer9> overlayVertexBuffer = m_OverlayVertexBuffers[type];
SDL_AtomicUnlock(&m_OverlayLock);
if (overlayTexture == nullptr) { if (overlayTexture == nullptr) {
SDL_AtomicUnlock(&m_OverlayLock);
return; return;
} }
// Reference these objects so they don't immediately go away if the hr = m_Device->SetTexture(0, overlayTexture.Get());
// overlay update thread tries to release them.
SDL_assert(overlayVertexBuffer != nullptr);
overlayTexture->AddRef();
overlayVertexBuffer->AddRef();
SDL_AtomicUnlock(&m_OverlayLock);
hr = m_Device->SetTexture(0, overlayTexture);
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SetTexture() failed: %x", "SetTexture() failed: %x",
hr); hr);
goto Exit; return;
} }
hr = m_Device->SetStreamSource(0, overlayVertexBuffer, 0, sizeof(VERTEX)); hr = m_Device->SetStreamSource(0, overlayVertexBuffer.Get(), 0, sizeof(VERTEX));
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SetStreamSource() failed: %x", "SetStreamSource() failed: %x",
hr); hr);
goto Exit; return;
} }
hr = m_Device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2); hr = m_Device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
@ -976,12 +947,8 @@ void DXVA2Renderer::renderOverlay(Overlay::OverlayType type)
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"DrawPrimitive() failed: %x", "DrawPrimitive() failed: %x",
hr); hr);
goto Exit; return;
} }
Exit:
overlayTexture->Release();
overlayVertexBuffer->Release();
} }
int DXVA2Renderer::getDecoderColorspace() int DXVA2Renderer::getDecoderColorspace()
@ -1158,13 +1125,12 @@ void DXVA2Renderer::renderFrame(AVFrame *frame)
} }
if (m_Processor) { if (m_Processor) {
hr = m_Processor->VideoProcessBlt(m_RenderTarget, &bltParams, &sample, 1, nullptr); hr = m_Processor->VideoProcessBlt(m_RenderTarget.Get(), &bltParams, &sample, 1, nullptr);
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"VideoProcessBlt() failed, falling back to StretchRect(): %x", "VideoProcessBlt() failed, falling back to StretchRect(): %x",
hr); hr);
m_Processor->Release(); m_Processor.Reset();
m_Processor = nullptr;
} }
} }
@ -1173,7 +1139,7 @@ void DXVA2Renderer::renderFrame(AVFrame *frame)
SDL_assert(m_Desc.SampleFormat.VideoTransferMatrix == DXVA2_VideoTransferMatrix_BT601); SDL_assert(m_Desc.SampleFormat.VideoTransferMatrix == DXVA2_VideoTransferMatrix_BT601);
// This function doesn't trigger any of Intel's garbage video "enhancements" // This function doesn't trigger any of Intel's garbage video "enhancements"
hr = m_Device->StretchRect(surface, &sample.SrcRect, m_RenderTarget, &sample.DstRect, D3DTEXF_NONE); hr = m_Device->StretchRect(surface, &sample.SrcRect, m_RenderTarget.Get(), &sample.DstRect, D3DTEXF_NONE);
if (FAILED(hr)) { if (FAILED(hr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"StretchRect() failed: %x", "StretchRect() failed: %x",

View File

@ -10,6 +10,8 @@ extern "C" {
#include <libavcodec/dxva2.h> #include <libavcodec/dxva2.h>
} }
#include <wrl/client.h>
class DXVA2Renderer : public IFFmpegRenderer class DXVA2Renderer : public IFFmpegRenderer
{ {
public: public:
@ -55,21 +57,22 @@ private:
int m_DisplayHeight; int m_DisplayHeight;
struct dxva_context m_DXVAContext; struct dxva_context m_DXVAContext;
IDirect3DSurface9* m_DecSurfaces[19]; std::array<Microsoft::WRL::ComPtr<IDirect3DSurface9>, 19> m_DecSurfaces;
std::array<IDirect3DSurface9*, 19> m_DecSurfacesRaw; // Referenced by m_DecSurfaces
DXVA2_ConfigPictureDecode m_Config; DXVA2_ConfigPictureDecode m_Config;
IDirectXVideoDecoderService* m_DecService; Microsoft::WRL::ComPtr<IDirectXVideoDecoderService> m_DecService;
IDirectXVideoDecoder* m_Decoder; Microsoft::WRL::ComPtr<IDirectXVideoDecoder> m_Decoder;
int m_SurfacesUsed; int m_SurfacesUsed;
AVBufferPool* m_Pool; AVBufferPool* m_Pool;
SDL_SpinLock m_OverlayLock; SDL_SpinLock m_OverlayLock;
IDirect3DVertexBuffer9* m_OverlayVertexBuffers[Overlay::OverlayMax]; std::array<Microsoft::WRL::ComPtr<IDirect3DVertexBuffer9>, Overlay::OverlayMax> m_OverlayVertexBuffers;
IDirect3DTexture9* m_OverlayTextures[Overlay::OverlayMax]; std::array<Microsoft::WRL::ComPtr<IDirect3DTexture9>, Overlay::OverlayMax> m_OverlayTextures;
IDirect3DDevice9Ex* m_Device; Microsoft::WRL::ComPtr<IDirect3DDevice9Ex> m_Device;
IDirect3DSurface9* m_RenderTarget; Microsoft::WRL::ComPtr<IDirect3DSurface9> m_RenderTarget;
IDirectXVideoProcessorService* m_ProcService; Microsoft::WRL::ComPtr<IDirectXVideoProcessorService> m_ProcService;
IDirectXVideoProcessor* m_Processor; Microsoft::WRL::ComPtr<IDirectXVideoProcessor> m_Processor;
DXVA2_ValueRange m_BrightnessRange; DXVA2_ValueRange m_BrightnessRange;
DXVA2_ValueRange m_ContrastRange; DXVA2_ValueRange m_ContrastRange;
DXVA2_ValueRange m_HueRange; DXVA2_ValueRange m_HueRange;