diff --git a/app/streaming/video/ffmpeg-renderers/dxva2.cpp b/app/streaming/video/ffmpeg-renderers/dxva2.cpp index b96a719a..d913e459 100644 --- a/app/streaming/video/ffmpeg-renderers/dxva2.cpp +++ b/app/streaming/video/ffmpeg-renderers/dxva2.cpp @@ -26,7 +26,7 @@ DEFINE_GUID(DXVA2_ModeAV1_VLD_Profile0,0xb8be4ccb,0xcf53,0x46ba,0x8d,0x59,0xd6,0 #define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 #endif -#define SAFE_COM_RELEASE(x) if (x) { (x)->Release(); } +using Microsoft::WRL::ComPtr; typedef struct _VERTEX { @@ -36,25 +36,15 @@ typedef struct _VERTEX DXVA2Renderer::DXVA2Renderer(int decoderSelectionPass) : m_DecoderSelectionPass(decoderSelectionPass), - m_DecService(nullptr), - m_Decoder(nullptr), m_SurfacesUsed(0), m_Pool(nullptr), m_OverlayLock(0), - m_Device(nullptr), - m_RenderTarget(nullptr), - m_ProcService(nullptr), - m_Processor(nullptr), m_FrameIndex(0), m_BlockingPresent(false), m_DeviceQuirks(0) { - RtlZeroMemory(m_DecSurfaces, sizeof(m_DecSurfaces)); 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 DwmEnableMMCSS(TRUE); } @@ -63,23 +53,23 @@ DXVA2Renderer::~DXVA2Renderer() { DwmEnableMMCSS(FALSE); - SAFE_COM_RELEASE(m_DecService); - SAFE_COM_RELEASE(m_Decoder); - SAFE_COM_RELEASE(m_Device); - SAFE_COM_RELEASE(m_RenderTarget); - SAFE_COM_RELEASE(m_ProcService); - SAFE_COM_RELEASE(m_Processor); + m_DecService.Reset(); + m_Decoder.Reset(); + m_Device.Reset(); + m_RenderTarget.Reset(); + m_ProcService.Reset(); + m_Processor.Reset(); - for (int i = 0; i < ARRAYSIZE(m_OverlayVertexBuffers); i++) { - SAFE_COM_RELEASE(m_OverlayVertexBuffers[i]); + for (int i = 0; i < m_OverlayVertexBuffers.size(); i++) { + m_OverlayVertexBuffers[i].Reset(); } - for (int i = 0; i < ARRAYSIZE(m_OverlayTextures); i++) { - SAFE_COM_RELEASE(m_OverlayTextures[i]); + for (int i = 0; i < m_OverlayTextures.size(); i++) { + m_OverlayTextures[i].Reset(); } - for (int i = 0; i < ARRAYSIZE(m_DecSurfaces); i++) { - SAFE_COM_RELEASE(m_DecSurfaces[i]); + for (int i = 0; i < m_DecSurfaces.size(); i++) { + m_DecSurfaces[i].Reset(); } if (m_Pool != nullptr) { @@ -96,12 +86,12 @@ AVBufferRef* DXVA2Renderer::ffPoolAlloc(void* opaque, FF_POOL_SIZE_TYPE) { DXVA2Renderer* me = reinterpret_cast(opaque); - if (me->m_SurfacesUsed < ARRAYSIZE(me->m_DecSurfaces)) { + if (me->m_SurfacesUsed < me->m_DecSurfaces.size()) { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "DXVA2 decoder surface high-water mark: %d", me->m_SurfacesUsed); - return av_buffer_create((uint8_t*)me->m_DecSurfaces[me->m_SurfacesUsed++], - sizeof(*me->m_DecSurfaces), ffPoolDummyDelete, 0, 0); + return av_buffer_create((uint8_t*)me->m_DecSurfacesRaw[me->m_SurfacesUsed++], + sizeof(me->m_DecSurfacesRaw[0]), ffPoolDummyDelete, 0, 0); } return NULL; @@ -110,10 +100,10 @@ AVBufferRef* DXVA2Renderer::ffPoolAlloc(void* opaque, FF_POOL_SIZE_TYPE) bool DXVA2Renderer::prepareDecoderContext(AVCodecContext* context, AVDictionary**) { // 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.surface = m_DecSurfaces; - m_DXVAContext.surface_count = ARRAYSIZE(m_DecSurfaces); + m_DXVAContext.surface = m_DecSurfacesRaw.data(); + m_DXVAContext.surface_count = (unsigned int)m_DecSurfacesRaw.size(); context->hwaccel_context = &m_DXVAContext; @@ -124,7 +114,7 @@ bool DXVA2Renderer::prepareDecoderContext(AVCodecContext* context, AVDictionary* ) #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) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed create buffer pool"); @@ -162,8 +152,7 @@ bool DXVA2Renderer::initializeDecoder() return false; } - hr = DXVA2CreateVideoService(m_Device, IID_IDirectXVideoDecoderService, - reinterpret_cast(&m_DecService)); + hr = DXVA2CreateVideoService(m_Device.Get(), IID_IDirectXVideoDecoderService, &m_DecService); if (FAILED(hr)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "DXVA2CreateVideoService(IID_IDirectXVideoDecoderService) failed: %x", @@ -255,12 +244,12 @@ bool DXVA2Renderer::initializeDecoder() SDL_assert(m_Desc.SampleHeight % 16 == 0); hr = m_DecService->CreateSurface(m_Desc.SampleWidth, m_Desc.SampleHeight, - ARRAYSIZE(m_DecSurfaces) - 1, + (UINT)m_DecSurfacesRaw.size() - 1, m_Desc.Format, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, - m_DecSurfaces, + m_DecSurfacesRaw.data(), nullptr); if (FAILED(hr)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, @@ -269,8 +258,14 @@ bool DXVA2Renderer::initializeDecoder() 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, - m_DecSurfaces, ARRAYSIZE(m_DecSurfaces), + m_DecSurfacesRaw.data(), + (UINT)m_DecSurfacesRaw.size(), &m_Decoder); if (FAILED(hr)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, @@ -301,8 +296,7 @@ bool DXVA2Renderer::initializeRenderer() m_DisplayHeight = renderTargetDesc.Height; if (!(m_DeviceQuirks & DXVA2_QUIRK_NO_VP)) { - hr = DXVA2CreateVideoService(m_Device, IID_IDirectXVideoProcessorService, - reinterpret_cast(&m_ProcService)); + hr = DXVA2CreateVideoService(m_Device.Get(), IID_IDirectXVideoProcessorService, &m_ProcService); if (FAILED(hr)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, @@ -386,7 +380,7 @@ bool DXVA2Renderer::initializeQuirksForAdapter(IDirect3D9Ex* d3d9ex, int adapter HRESULT hr; SDL_assert(m_DeviceQuirks == 0); - SDL_assert(m_Device == nullptr); + SDL_assert(!m_Device); { bool ok; @@ -466,7 +460,7 @@ bool DXVA2Renderer::initializeQuirksForAdapter(IDirect3D9Ex* d3d9ex, int adapter bool DXVA2Renderer::isDecoderBlacklisted() { - IDirect3D9* d3d9; + ComPtr d3d9; HRESULT hr; bool result = false; @@ -523,8 +517,6 @@ bool DXVA2Renderer::isDecoderBlacklisted() SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "GetDeviceCaps() failed: %x", hr); } - - d3d9->Release(); } else { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, @@ -547,7 +539,7 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync) SDL_VERSION(&info.version); SDL_GetWindowWMInfo(window, &info); - IDirect3D9Ex* d3d9ex; + ComPtr d3d9ex; HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9ex); if (FAILED(hr)) { 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 // logic to avoid a hang with NahimicOSD.dll's broken full-screen handling. - if (!initializeQuirksForAdapter(d3d9ex, adapterIndex)) { - d3d9ex->Release(); + if (!initializeQuirksForAdapter(d3d9ex.Get(), adapterIndex)) { return false; } @@ -588,7 +579,6 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync) if (FAILED(hr)) { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "GPU/driver doesn't support A2R10G10B10"); - d3d9ex->Release(); return false; } } @@ -685,9 +675,6 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync) &d3dpp, d3dpp.Windowed ? nullptr : ¤tMode, &m_Device); - - d3d9ex->Release(); - if (FAILED(hr)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "CreateDeviceEx() failed: %x", @@ -810,16 +797,10 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type) } SDL_AtomicLock(&m_OverlayLock); - IDirect3DTexture9* oldTexture = m_OverlayTextures[type]; - m_OverlayTextures[type] = nullptr; - - IDirect3DVertexBuffer9* oldVertexBuffer = m_OverlayVertexBuffers[type]; - m_OverlayVertexBuffers[type] = nullptr; + ComPtr oldTexture = std::move(m_OverlayTextures[type]); + ComPtr oldVertexBuffer = std::move(m_OverlayVertexBuffers[type]); SDL_AtomicUnlock(&m_OverlayLock); - SAFE_COM_RELEASE(oldTexture); - SAFE_COM_RELEASE(oldVertexBuffer); - // If the overlay is disabled, we're done if (!overlayEnabled) { SDL_FreeSurface(newSurface); @@ -828,7 +809,7 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type) // Create a dynamic texture to populate with our pixel data SDL_assert(!SDL_MUSTLOCK(newSurface)); - IDirect3DTexture9* newTexture = nullptr; + ComPtr newTexture; hr = m_Device->CreateTexture(newSurface->w, newSurface->h, 1, @@ -849,7 +830,6 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type) hr = newTexture->LockRect(0, &lockedRect, nullptr, D3DLOCK_DISCARD); if (FAILED(hr)) { SDL_FreeSurface(newSurface); - SAFE_COM_RELEASE(newTexture); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "IDirect3DTexture9::LockRect() failed: %x", hr); @@ -890,7 +870,7 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type) {renderRect.x+renderRect.w, renderRect.y, 0, 1, 1, 0} }; - IDirect3DVertexBuffer9* newVertexBuffer = nullptr; + ComPtr newVertexBuffer; hr = m_Device->CreateVertexBuffer(sizeof(verts), D3DUSAGE_WRITEONLY, D3DFVF_XYZRHW | D3DFVF_TEX1, @@ -898,7 +878,6 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type) &newVertexBuffer, nullptr); if (FAILED(hr)) { - SAFE_COM_RELEASE(newTexture); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "CreateVertexBuffer() failed: %x", hr); @@ -908,8 +887,6 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type) PVOID targetVertexBuffer = nullptr; hr = newVertexBuffer->Lock(0, 0, &targetVertexBuffer, 0); if (FAILED(hr)) { - SAFE_COM_RELEASE(newTexture); - SAFE_COM_RELEASE(newVertexBuffer); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "IDirect3DVertexBuffer9::Lock() failed: %x", hr); @@ -921,8 +898,8 @@ void DXVA2Renderer::notifyOverlayUpdated(Overlay::OverlayType type) newVertexBuffer->Unlock(); SDL_AtomicLock(&m_OverlayLock); - m_OverlayVertexBuffers[type] = newVertexBuffer; - m_OverlayTextures[type] = newTexture; + m_OverlayVertexBuffers[type] = std::move(newVertexBuffer); + m_OverlayTextures[type] = std::move(newTexture); SDL_AtomicUnlock(&m_OverlayLock); } @@ -939,36 +916,30 @@ void DXVA2Renderer::renderOverlay(Overlay::OverlayType type) return; } - IDirect3DTexture9* overlayTexture = m_OverlayTextures[type]; - IDirect3DVertexBuffer9* overlayVertexBuffer = m_OverlayVertexBuffers[type]; + // Reference these objects so they don't immediately go away if the + // overlay update thread tries to release them. + ComPtr overlayTexture = m_OverlayTextures[type]; + ComPtr overlayVertexBuffer = m_OverlayVertexBuffers[type]; + SDL_AtomicUnlock(&m_OverlayLock); if (overlayTexture == nullptr) { - SDL_AtomicUnlock(&m_OverlayLock); return; } - // Reference these objects so they don't immediately go away if the - // 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); + hr = m_Device->SetTexture(0, overlayTexture.Get()); if (FAILED(hr)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SetTexture() failed: %x", 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)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SetStreamSource() failed: %x", hr); - goto Exit; + return; } hr = m_Device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2); @@ -976,12 +947,8 @@ void DXVA2Renderer::renderOverlay(Overlay::OverlayType type) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "DrawPrimitive() failed: %x", hr); - goto Exit; + return; } - -Exit: - overlayTexture->Release(); - overlayVertexBuffer->Release(); } int DXVA2Renderer::getDecoderColorspace() @@ -1158,13 +1125,12 @@ void DXVA2Renderer::renderFrame(AVFrame *frame) } 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)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "VideoProcessBlt() failed, falling back to StretchRect(): %x", hr); - m_Processor->Release(); - m_Processor = nullptr; + m_Processor.Reset(); } } @@ -1173,7 +1139,7 @@ void DXVA2Renderer::renderFrame(AVFrame *frame) SDL_assert(m_Desc.SampleFormat.VideoTransferMatrix == DXVA2_VideoTransferMatrix_BT601); // 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)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "StretchRect() failed: %x", diff --git a/app/streaming/video/ffmpeg-renderers/dxva2.h b/app/streaming/video/ffmpeg-renderers/dxva2.h index fcda92bf..a66ca7b8 100644 --- a/app/streaming/video/ffmpeg-renderers/dxva2.h +++ b/app/streaming/video/ffmpeg-renderers/dxva2.h @@ -10,6 +10,8 @@ extern "C" { #include } +#include + class DXVA2Renderer : public IFFmpegRenderer { public: @@ -55,21 +57,22 @@ private: int m_DisplayHeight; struct dxva_context m_DXVAContext; - IDirect3DSurface9* m_DecSurfaces[19]; + std::array, 19> m_DecSurfaces; + std::array m_DecSurfacesRaw; // Referenced by m_DecSurfaces DXVA2_ConfigPictureDecode m_Config; - IDirectXVideoDecoderService* m_DecService; - IDirectXVideoDecoder* m_Decoder; + Microsoft::WRL::ComPtr m_DecService; + Microsoft::WRL::ComPtr m_Decoder; int m_SurfacesUsed; AVBufferPool* m_Pool; SDL_SpinLock m_OverlayLock; - IDirect3DVertexBuffer9* m_OverlayVertexBuffers[Overlay::OverlayMax]; - IDirect3DTexture9* m_OverlayTextures[Overlay::OverlayMax]; + std::array, Overlay::OverlayMax> m_OverlayVertexBuffers; + std::array, Overlay::OverlayMax> m_OverlayTextures; - IDirect3DDevice9Ex* m_Device; - IDirect3DSurface9* m_RenderTarget; - IDirectXVideoProcessorService* m_ProcService; - IDirectXVideoProcessor* m_Processor; + Microsoft::WRL::ComPtr m_Device; + Microsoft::WRL::ComPtr m_RenderTarget; + Microsoft::WRL::ComPtr m_ProcService; + Microsoft::WRL::ComPtr m_Processor; DXVA2_ValueRange m_BrightnessRange; DXVA2_ValueRange m_ContrastRange; DXVA2_ValueRange m_HueRange;