[idd] capture: retain frames in linear buffers
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
build / client-tests (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client-tests (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client-tests (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client-tests (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client-tests (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client-tests (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client-tests (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client-tests (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled

Store retained frame candidates in the final linear transport layout.
Prepare texture output in local DEFAULT buffers before cadence holding.
Then publish full frames with a single buffer copy.

Keep partial damage on matching pitched layouts and leave effect-owned
buffer copies unchanged. This moves detiling out of the
deadline-critical IVSHMEM or readback transfer.
This commit is contained in:
Geoffrey McRae
2026-08-05 22:08:38 +10:00
parent ab25601a61
commit 650636ccee
4 changed files with 59 additions and 38 deletions

View File

@@ -351,15 +351,14 @@ bool CPostProcessor::ShouldCopyFully(
m_copyEffect->ShouldCopyFully(dirtyRects, nbDirtyRects); m_copyEffect->ShouldCopyFully(dirtyRects, nbDirtyRects);
} }
void CPostProcessor::CopyFrame( void CPostProcessor::CopyToCandidate(
const ComPtr<ID3D12GraphicsCommandList>& commandList, const ComPtr<ID3D12GraphicsCommandList>& commandList,
ID3D12Resource * dst, ID3D12Resource * src, ID3D12Resource * dst, ID3D12Resource * src) const
const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const
{ {
if (m_copyEffect) if (m_copyEffect)
{ {
m_copyEffect->CopyFrame( m_copyEffect->CopyFrame(
commandList, dst, src, dirtyRects, nbDirtyRects, fullCopy); commandList, dst, src, nullptr, 0, true);
return; return;
} }
@@ -373,10 +372,36 @@ void CPostProcessor::CopyFrame(
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
dstLoc.PlacedFootprint = m_copyLayout; dstLoc.PlacedFootprint = m_copyLayout;
if (fullCopy)
{
commandList->CopyTextureRegion( commandList->CopyTextureRegion(
&dstLoc, 0, 0, 0, &srcLoc, nullptr); &dstLoc, 0, 0, 0, &srcLoc, nullptr);
}
void CPostProcessor::CopyFromCandidate(
const ComPtr<ID3D12GraphicsCommandList>& commandList,
ID3D12Resource * dst, ID3D12Resource * src,
const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const
{
if (m_copyEffect)
{
m_copyEffect->CopyFrame(
commandList, dst, src, dirtyRects, nbDirtyRects, fullCopy);
return;
}
D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
srcLoc.pResource = src;
srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
srcLoc.PlacedFootprint = m_copyLayout;
D3D12_TEXTURE_COPY_LOCATION dstLoc = {};
dstLoc.pResource = dst;
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
dstLoc.PlacedFootprint = m_copyLayout;
if (fullCopy)
{
commandList->CopyBufferRegion(
dst, 0, src, 0, m_frameSize);
return; return;
} }

View File

@@ -183,7 +183,10 @@ public:
size_t GetOutputSize () const { return m_frameSize; } size_t GetOutputSize () const { return m_frameSize; }
bool ShouldCopyFully( bool ShouldCopyFully(
const RECT dirtyRects[], unsigned nbDirtyRects) const; const RECT dirtyRects[], unsigned nbDirtyRects) const;
void CopyFrame( void CopyToCandidate(
const ComPtr<ID3D12GraphicsCommandList>& commandList,
ID3D12Resource * dst, ID3D12Resource * src) const;
void CopyFromCandidate(
const ComPtr<ID3D12GraphicsCommandList>& commandList, const ComPtr<ID3D12GraphicsCommandList>& commandList,
ID3D12Resource * dst, ID3D12Resource * src, ID3D12Resource * dst, ID3D12Resource * src,
const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const; const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const;

View File

@@ -970,14 +970,23 @@ static bool ResourceDescMatches(
} }
bool CSwapChainProcessor::EnsureCandidateResource( bool CSwapChainProcessor::EnsureCandidateResource(
unsigned candidateIndex, ID3D12Resource * source) unsigned candidateIndex, size_t frameSize)
{ {
FrameCandidate& candidate = m_candidates[candidateIndex]; FrameCandidate& candidate = m_candidates[candidateIndex];
D3D12_RESOURCE_DESC desc = source->GetDesc();
desc.Alignment = 0; // Keep the transport layout in local GPU memory so publication does not
desc.Flags = static_cast<D3D12_RESOURCE_FLAGS>( // combine texture detiling with the IVSHMEM or readback transfer.
static_cast<UINT>(desc.Flags) & D3D12_RESOURCE_DESC desc = {};
~static_cast<UINT>(D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER)); desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Width = frameSize;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
if (candidate.resource && if (candidate.resource &&
ResourceDescMatches(candidate.resource->GetDesc(), desc)) ResourceDescMatches(candidate.resource->GetDesc(), desc))
@@ -1178,7 +1187,7 @@ bool CSwapChainProcessor::PublishNewestCandidate(
copySlot->SetCompletionCallback(&CompletionFunction, this, fbRes); copySlot->SetCompletionCallback(&CompletionFunction, this, fbRes);
copySlot->BeginTiming(); copySlot->BeginTiming();
postProcessor.CopyFrame( postProcessor.CopyFromCandidate(
copySlot->GetGfxList(), fbRes->Get().Get(), candidate.resource.Get(), copySlot->GetGfxList(), fbRes->Get().Get(), candidate.resource.Get(),
copyDirtyRects, nbCopyDirtyRects, fullCopy); copyDirtyRects, nbCopyDirtyRects, fullCopy);
copySlot->EndTiming(); copySlot->EndTiming();
@@ -1682,7 +1691,8 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
ClipDirtyRects(currentDirtyRects, &nbDirtyRects, ClipDirtyRects(currentDirtyRects, &nbDirtyRects,
dstFormat.width, dstFormat.height); dstFormat.width, dstFormat.height);
if (!EnsureCandidateResource(candidateIndex, copySrcResource.Get())) const size_t frameSize = postProcessor.GetOutputSize();
if (!EnsureCandidateResource(candidateIndex, frameSize))
{ {
copySlot->Cancel(); copySlot->Cancel();
if (computeSlot) if (computeSlot)
@@ -1696,7 +1706,7 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
candidate.dstFormat = dstFormat; candidate.dstFormat = dstFormat;
candidate.nbDirtyRects = nbDirtyRects; candidate.nbDirtyRects = nbDirtyRects;
candidate.pitch = postProcessor.GetOutputPitch(); candidate.pitch = postProcessor.GetOutputPitch();
candidate.frameSize = postProcessor.GetOutputSize(); candidate.frameSize = frameSize;
candidate.captureTime = captureTime; candidate.captureTime = captureTime;
candidate.postProcessStart = postProcessStart; candidate.postProcessStart = postProcessStart;
candidate.prepareCopyStart = CFrameScheduler::Nanotime(); candidate.prepareCopyStart = CFrameScheduler::Nanotime();
@@ -1714,26 +1724,9 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
copySlot->SetCompletionCallback( copySlot->SetCompletionCallback(
&CandidateCompletionFunction, this, &candidate); &CandidateCompletionFunction, this, &candidate);
copySlot->BeginTiming(); copySlot->BeginTiming();
const D3D12_RESOURCE_DESC copySrcDesc = copySrcResource->GetDesc(); postProcessor.CopyToCandidate(
if (copySrcDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) copySlot->GetGfxList(), candidate.resource.Get(),
copySlot->GetGfxList()->CopyBufferRegion( copySrcResource.Get());
candidate.resource.Get(), 0, copySrcResource.Get(), 0,
copySrcDesc.Width);
else
{
D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
srcLocation.pResource = copySrcResource.Get();
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
srcLocation.SubresourceIndex = 0;
D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
dstLocation.pResource = candidate.resource.Get();
dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dstLocation.SubresourceIndex = 0;
copySlot->GetGfxList()->CopyTextureRegion(
&dstLocation, 0, 0, 0, &srcLocation, nullptr);
}
copySlot->EndTiming(); copySlot->EndTiming();
if (!copySlot->Execute()) if (!copySlot->Execute())

View File

@@ -149,8 +149,8 @@ private:
bool HasReadyCandidate(); bool HasReadyCandidate();
int AcquireCandidate(bool exclusiveSample); int AcquireCandidate(bool exclusiveSample);
void ReleaseCandidate(unsigned candidateIndex); void ReleaseCandidate(unsigned candidateIndex);
bool EnsureCandidateResource(unsigned candidateIndex, bool EnsureCandidateResource(
ID3D12Resource * source); unsigned candidateIndex, size_t frameSize);
void ResetCandidates(); void ResetCandidates();
void SignalCandidateState(); void SignalCandidateState();