[idd] capture: split software and hardware frame processors

Move cadence-aware hardware capture and immediate software capture
behind a common frame processor interface.

Keep shared damage tracking and frame-buffer ownership in the base
processor, and move stateless format, resource, and rectangle helpers
into CFrameProcessorUtil.

Decouple frame-buffer resources from CSwapChainProcessor by passing the
device dependencies they use directly.
This commit is contained in:
Geoffrey McRae
2026-08-07 13:23:19 +10:00
parent d7c90e4693
commit 3ddc199bec
18 changed files with 2051 additions and 1662 deletions

View File

@@ -24,7 +24,7 @@
#include "CD3D12Device.h"
#include "CIndirectDeviceContext.h"
#include "CInteropResourcePool.h"
#include "CFrameBufferPool.h"
#include "CFrameProcessor.h"
#include "CPostProcessor.h"
#include <Windows.h>
@@ -35,8 +35,6 @@
using namespace Microsoft::WRL;
#define STAGING_TEXTURES 3
class CIndirectMonitorContext;
class CSwapChainProcessor
@@ -52,69 +50,14 @@ private:
std::shared_ptr<CD3D12Device> m_dx12Device;
HANDLE m_newFrameEvent;
CInteropResourcePool m_resPool;
CFrameBufferPool m_fbPool;
CPostProcessor m_postProcessors[LGMP_Q_FRAME_LEN];
enum CandidateState
{
CANDIDATE_FREE,
CANDIDATE_PREPARING,
CANDIDATE_READY,
CANDIDATE_PUBLISHING,
};
struct FrameCandidate
{
CandidateState state = CANDIDATE_FREE;
ComPtr<ID3D12Resource> resource;
D12FrameFormat srcFormat = {};
D12FrameFormat dstFormat = {};
RECT dirtyRects[LG_MAX_DIRTY_RECTS] = {};
unsigned nbDirtyRects = 0;
unsigned pitch = 0;
size_t frameSize = 0;
uint64_t sequence = 0;
uint64_t captureTime = 0;
uint64_t postProcessStart = 0;
uint64_t prepareCopyStart = 0;
uint64_t prepareReady = 0;
uint64_t prepareGPUStart = 0;
uint64_t prepareGPUEnd = 0;
uint64_t timingStart = 0;
unsigned timingEffectIndex = 0;
uint64_t timingToken = 0;
bool prepareTimingValid = false;
};
struct CandidateDamageTail
{
uint64_t ownerSequence = 0;
RECT dirtyRects[LG_MAX_DIRTY_RECTS] = {};
unsigned nbDirtyRects = 0;
bool hasDamage = false;
bool active = false;
};
// An active tail records only damage received after its candidate snapshot.
FrameCandidate m_candidates[LGMP_Q_FRAME_LEN];
CandidateDamageTail m_candidateDamageTail[LGMP_Q_FRAME_LEN];
SRWLOCK m_candidateLock = SRWLOCK_INIT;
SRWLOCK m_damageLock = SRWLOCK_INIT;
CInteropResourcePool m_resPool;
CPostProcessor m_postProcessors[LGMP_Q_FRAME_LEN];
std::unique_ptr<CFrameProcessor> m_frameProcessor;
// Reconfiguration is exclusive while per-candidate recording is shared.
SRWLOCK m_pipelineLock = SRWLOCK_INIT;
// Capture holds this only across submission; the publisher uses it to
// close the gate before recording deadline work.
SRWLOCK m_copySubmitLock = SRWLOCK_INIT;
uint64_t m_candidateSequence = 0;
bool m_publishPending = false;
bool m_directSoftwareTexture = false;
SRWLOCK m_pipelineLock = SRWLOCK_INIT;
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread[3];
Wrappers::Event m_terminateEvent;
Wrappers::Event m_candidateEvent;
Wrappers::Event m_candidateAvailableEvent;
Wrappers::Event m_copySubmitEvent;
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_publishTimer;
Wrappers::Event m_cursorDataEvent;
@@ -122,20 +65,6 @@ private:
DWORD m_lastShapeId = 0;
std::atomic<UINT> m_sdrWhiteLevel { KVMFR_SDR_WHITE_LEVEL_DEFAULT };
// Logical output-space damage from the previous published frame. The
// shared-memory frame buffers alternate, so this must be copied along with
// the current damage to bring the older target buffer up to date.
RECT m_dirtyRects[LG_MAX_DIRTY_RECTS] = {};
unsigned m_nbDirtyRects = 0;
// Source-space damage accumulated since the last published frame. Frames
// can be dropped while the LGMP queue is full, but their damage must be
// included in the next frame sent to the client. A count of zero represents
// full-frame damage when m_hasPendingDamage is set.
RECT m_pendingDirtyRects[LG_MAX_DIRTY_RECTS] = {};
unsigned m_nbPendingDirtyRects = 0;
bool m_hasPendingDamage = true;
#ifdef HAS_IDDCX_110
// The per-frame metadata stream can select the monitor default, provide a
// replacement block, or retain the selection from the previous frame.
@@ -151,43 +80,14 @@ private:
static DWORD CALLBACK _PublisherThread(LPVOID arg);
void PublisherThread();
bool PublishNewestCandidate(
const CFrameScheduler::Schedule& schedule, bool periodic,
uint64_t publishStart);
bool HasReadyCandidate();
int AcquireCandidate(bool exclusiveSample, bool allowSupersede);
void ReleaseCandidate(unsigned candidateIndex);
bool EnsureCandidateResource(
unsigned candidateIndex, size_t frameSize);
void ResetCandidates();
void SignalCandidateState();
bool ExecuteCandidateCopy(CD3D12CommandSlot * copySlot);
static DWORD CALLBACK _CursorThread(LPVOID arg);
bool QueryHWCursor();
void CursorThread();
static void CompletionFunction(
CD3D12CommandSlot * slot, bool result, void * param1, void * param2);
static void CandidateCompletionFunction(
CD3D12CommandSlot * slot, bool result, void * param1, void * param2);
static void SoftwareCompletionFunction(
CD3D12CommandSlot * slot, bool result, void * param1, void * param2);
void AccumulateFrameDamage(const RECT * dirtyRects, unsigned nbDirtyRects);
bool HasPendingDamage();
bool TakePendingDamage(RECT dirtyRects[], unsigned * nbDirtyRects);
void RestorePendingDamage(const RECT dirtyRects[],
unsigned nbDirtyRects, bool hasDamage);
void CommitFrameDamage(
const RECT dirtyRects[], unsigned nbDirtyRects);
void SetFullPendingDamage();
#ifdef HAS_IDDCX_110
void UpdateHDRMetadata(const IDDCX_METADATA2& metadata);
#endif
bool GetContentHDRMetadata(D12FrameFormat& format) const;
bool PublishSoftwareFrame(CInteropResource * srcRes,
const D12FrameFormat& srcFormat, uint64_t captureTime,
uint64_t postProcessStart, bool noImageUpdate);
bool SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer,
unsigned dirtyRectCount, unsigned moveRegionCount,
DXGI_COLOR_SPACE_TYPE colorSpace, UINT sdrWhiteLevel,
@@ -200,7 +100,4 @@ public:
HANDLE newFrameEvent);
~CSwapChainProcessor();
bool Start();
CIndirectDeviceContext * GetDevice() { return m_devContext; }
std::shared_ptr<CD3D12Device> GetD3D12Device() { return m_dx12Device; }
};