[idd] resend the last captured frame if a new client connects

This commit is contained in:
Geoffrey McRae 2023-04-14 14:07:30 +10:00
parent fd0cc6aa10
commit d6b26b0eb1
5 changed files with 59 additions and 8 deletions

View File

@ -165,11 +165,12 @@ void CIndirectDeviceContext::FinishInit(UINT connectorIndex)
return; return;
} }
auto * wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(createOut.MonitorObject); m_monitor = createOut.MonitorObject;
wrapper->context = new CIndirectMonitorContext(createOut.MonitorObject, this); auto * wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(m_monitor);
wrapper->context = new CIndirectMonitorContext(m_monitor, this);
IDARG_OUT_MONITORARRIVAL out; IDARG_OUT_MONITORARRIVAL out;
status = IddCxMonitorArrival(createOut.MonitorObject, &out); status = IddCxMonitorArrival(m_monitor, &out);
} }
bool CIndirectDeviceContext::SetupLGMP() bool CIndirectDeviceContext::SetupLGMP()
@ -366,6 +367,13 @@ void CIndirectDeviceContext::LGMPTimer()
lgmpHostAckData(m_pointerQueue); lgmpHostAckData(m_pointerQueue);
} }
if (lgmpHostQueueNewSubs(m_frameQueue) && m_monitor)
{
auto* wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(m_monitor);
if (wrapper)
wrapper->context->ResendLastFrame();
}
} }
void CIndirectDeviceContext::SendFrame(int width, int height, int pitch, DXGI_FORMAT format, void* data) void CIndirectDeviceContext::SendFrame(int width, int height, int pitch, DXGI_FORMAT format, void* data)
@ -373,11 +381,12 @@ void CIndirectDeviceContext::SendFrame(int width, int height, int pitch, DXGI_FO
if (!m_lgmp || !m_frameQueue) if (!m_lgmp || !m_frameQueue)
return; return;
if (m_width != width || m_height != height || m_format != format) if (m_width != width || m_height != height || m_pitch != pitch || m_format != format)
{ {
m_width = width; m_width = width;
m_height = height; m_height = height;
m_format = format; m_format = format;
m_pitch = pitch;
++m_formatVer; ++m_formatVer;
} }

View File

@ -19,6 +19,8 @@ class CIndirectDeviceContext
private: private:
WDFDEVICE m_wdfDevice; WDFDEVICE m_wdfDevice;
IDDCX_ADAPTER m_adapter = nullptr; IDDCX_ADAPTER m_adapter = nullptr;
IDDCX_MONITOR m_monitor = nullptr;
CIVSHMEM m_ivshmem; CIVSHMEM m_ivshmem;
PLGMPHost m_lgmp = nullptr; PLGMPHost m_lgmp = nullptr;
@ -36,7 +38,9 @@ private:
int m_width = 0; int m_width = 0;
int m_height = 0; int m_height = 0;
int m_pitch = 0;
DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN; DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN;
void * m_data = nullptr;
bool SetupLGMP(); bool SetupLGMP();

View File

@ -22,6 +22,12 @@ public:
void AssignSwapChain(IDDCX_SWAPCHAIN swapChain, LUID renderAdapter, HANDLE newFrameEvent); void AssignSwapChain(IDDCX_SWAPCHAIN swapChain, LUID renderAdapter, HANDLE newFrameEvent);
void UnassignSwapChain(); void UnassignSwapChain();
inline void ResendLastFrame()
{
if (m_thread)
m_thread->ResendLastFrame();
}
}; };
struct CIndirectMonitorContextWrapper struct CIndirectMonitorContextWrapper

View File

@ -3,11 +3,16 @@
#include <avrt.h> #include <avrt.h>
#include "Debug.h" #include "Debug.h"
#define LOCK_CONTEXT() \ #define LOCK(lock) \
while (InterlockedCompareExchange((volatile LONG*)&m_contextLock, 1, 0) != 0) {}; while (InterlockedCompareExchange((volatile LONG*)&(lock), 1, 0) != 0) {};
#define UNLOCK_CONTEXT() \ #define UNLOCK(lock) \
InterlockedExchange((volatile LONG*)&m_contextLock, 0); InterlockedExchange((volatile LONG*)&(lock), 0);
#define LOCK_CONTEXT() LOCK(m_contextLock);
#define UNLOCK_CONTEXT() UNLOCK(m_contextLock);
#define LOCK_ST(st) LOCK((st).lock);
#define UNLOCK_ST(st) UNLOCK((st).lock);
CSwapChainProcessor::CSwapChainProcessor(CIndirectDeviceContext* devContext, IDDCX_SWAPCHAIN hSwapChain, CSwapChainProcessor::CSwapChainProcessor(CIndirectDeviceContext* devContext, IDDCX_SWAPCHAIN hSwapChain,
std::shared_ptr<Direct3DDevice> device, HANDLE newFrameEvent) : std::shared_ptr<Direct3DDevice> device, HANDLE newFrameEvent) :
@ -197,6 +202,7 @@ void CSwapChainProcessor::FrameThread()
} }
StagingTexture & st = m_cpuTex[m_texRIndex]; StagingTexture & st = m_cpuTex[m_texRIndex];
LOCK(st);
LOCK_CONTEXT(); LOCK_CONTEXT();
HRESULT status = m_device->m_context->Map(st.tex.Get(), 0, D3D11_MAP_READ, HRESULT status = m_device->m_context->Map(st.tex.Get(), 0, D3D11_MAP_READ,
@ -205,6 +211,7 @@ void CSwapChainProcessor::FrameThread()
if (FAILED(status)) if (FAILED(status))
{ {
UNLOCK(st);
if (status == DXGI_ERROR_WAS_STILL_DRAWING) if (status == DXGI_ERROR_WAS_STILL_DRAWING)
continue; continue;
@ -219,8 +226,11 @@ void CSwapChainProcessor::FrameThread()
m_devContext->SendFrame(st.width, st.height, st.map.RowPitch, st.format, st.map.pData); m_devContext->SendFrame(st.width, st.height, st.map.RowPitch, st.format, st.map.pData);
InterlockedAdd(&m_copyCount, -1); InterlockedAdd(&m_copyCount, -1);
m_lastIndex = m_texRIndex;
if (++m_texRIndex == STAGING_TEXTURES) if (++m_texRIndex == STAGING_TEXTURES)
m_texRIndex = 0; m_texRIndex = 0;
UNLOCK(st);
} }
} }
@ -255,3 +265,20 @@ bool CSwapChainProcessor::SetupStagingTexture(StagingTexture & st, int width, in
return true; return true;
} }
void CSwapChainProcessor::ResendLastFrame()
{
LOCK_CONTEXT()
StagingTexture & st = m_cpuTex[m_lastIndex];
LOCK_ST(st);
UNLOCK_CONTEXT();
if (!st.map.pData)
{
UNLOCK_ST(st);
return;
}
m_devContext->SendFrame(st.width, st.height, st.map.RowPitch, st.format, st.map.pData);
UNLOCK_ST(st);
}

View File

@ -34,6 +34,8 @@ private:
struct StagingTexture struct StagingTexture
{ {
volatile LONG lock = 0;
int width = 0; int width = 0;
int height = 0; int height = 0;
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
@ -46,6 +48,7 @@ private:
volatile LONG m_contextLock = 0; volatile LONG m_contextLock = 0;
int m_texRIndex = 0; int m_texRIndex = 0;
int m_texWIndex = 0; int m_texWIndex = 0;
int m_lastIndex = 0;
bool SetupStagingTexture(StagingTexture & st, int width, int height, DXGI_FORMAT format); bool SetupStagingTexture(StagingTexture & st, int width, int height, DXGI_FORMAT format);
@ -53,4 +56,6 @@ public:
CSwapChainProcessor(CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain, CSwapChainProcessor(CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,
std::shared_ptr<Direct3DDevice> device, HANDLE newFrameEvent); std::shared_ptr<Direct3DDevice> device, HANDLE newFrameEvent);
~CSwapChainProcessor(); ~CSwapChainProcessor();
void ResendLastFrame();
}; };