[idd] driver: implement dirty rect tracking
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

This commit is contained in:
Geoffrey McRae
2026-06-03 04:17:23 +10:00
parent f5a0054836
commit 3b0daa6fb1
8 changed files with 140 additions and 34 deletions

View File

@@ -90,8 +90,8 @@ class CD3D12CommandQueue
bool Execute(); bool Execute();
//void Wait(); //void Wait();
bool IsReady () { return !m_pending; } bool IsReady () const { return !m_pending ; }
HANDLE GetEvent() { return m_event.Get(); } HANDLE GetEvent() const { return m_event.Get(); }
ComPtr<ID3D12CommandQueue > GetCmdQueue() { return m_queue; } ComPtr<ID3D12CommandQueue > GetCmdQueue() { return m_queue; }
ComPtr<ID3D12GraphicsCommandList> GetGfxList() { return m_gfxList; } ComPtr<ID3D12GraphicsCommandList> GetGfxList() { return m_gfxList; }

View File

@@ -529,7 +529,7 @@ bool CEdid::WriteDetailedTiming(BYTE* dtd, const CSettings::DisplayMode& mode)
void CEdid::Build(const CSettings::DisplayModes& modes) void CEdid::Build(const CSettings::DisplayModes& modes)
{ {
m_data.assign(EDID_BLOCK_SIZE * 2, 0); m_data.assign(static_cast<std::vector<BYTE, std::allocator<BYTE>>::size_type>(EDID_BLOCK_SIZE) * 2, 0);
EdidBaseBlock baseBlock = {}; EdidBaseBlock baseBlock = {};
InitEdidBaseBlock(baseBlock); InitEdidBaseBlock(baseBlock);

View File

@@ -803,7 +803,7 @@ void CIndirectDeviceContext::LGMPTimer()
} }
CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrameBuffer( CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrameBuffer(
unsigned width, unsigned height, unsigned pitch, DXGI_FORMAT format) unsigned width, unsigned height, unsigned pitch, DXGI_FORMAT format, const RECT * dirtyRects, unsigned nbDirtyRects)
{ {
PreparedFrameBuffer result = {}; PreparedFrameBuffer result = {};
@@ -863,6 +863,17 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
fi->flags = 0; fi->flags = 0;
fi->rotation = FRAME_ROT_0; fi->rotation = FRAME_ROT_0;
fi->damageRectsCount = 0; fi->damageRectsCount = 0;
if (nbDirtyRects <= ARRAYSIZE(fi->damageRects))
{
fi->damageRectsCount = nbDirtyRects;
for (unsigned i = 0; i < nbDirtyRects; ++i)
{
fi->damageRects[i].x = dirtyRects[i].left;
fi->damageRects[i].y = dirtyRects[i].top;
fi->damageRects[i].width = dirtyRects[i].right - dirtyRects[i].left;
fi->damageRects[i].height = dirtyRects[i].bottom - dirtyRects[i].top;
}
}
FrameBuffer* fb = m_frameBuffer[m_frameIndex]; FrameBuffer* fb = m_frameBuffer[m_frameIndex];
fb->wp = 0; fb->wp = 0;
@@ -876,7 +887,7 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
return result; return result;
} }
void CIndirectDeviceContext::WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos) void CIndirectDeviceContext::WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos) const
{ {
FrameBuffer * fb = m_frameBuffer[frameIndex]; FrameBuffer * fb = m_frameBuffer[frameIndex];
@@ -889,7 +900,7 @@ void CIndirectDeviceContext::WriteFrameBuffer(unsigned frameIndex, void* src, si
fb->wp = (uint32_t)(offset + len); fb->wp = (uint32_t)(offset + len);
} }
void CIndirectDeviceContext::FinalizeFrameBuffer(unsigned frameIndex) void CIndirectDeviceContext::FinalizeFrameBuffer(unsigned frameIndex) const
{ {
FrameBuffer * fb = m_frameBuffer[frameIndex]; FrameBuffer * fb = m_frameBuffer[frameIndex];
fb->wp = m_height * m_pitch; fb->wp = m_height * m_pitch;
@@ -965,7 +976,7 @@ void CIndirectDeviceContext::SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, co
} }
} }
void CIndirectDeviceContext::ResendCursor() void CIndirectDeviceContext::ResendCursor() const
{ {
PLGMPMemory mem = m_pointerShape; PLGMPMemory mem = m_pointerShape;
if (!mem) if (!mem)

View File

@@ -93,7 +93,7 @@ private:
void DeInitLGMP(); void DeInitLGMP();
void LGMPTimer(); void LGMPTimer();
void ResendCursor(); void ResendCursor() const;
bool UpdateMonitorModes(); bool UpdateMonitorModes();
CSettings::DisplayModes m_displayModes; CSettings::DisplayModes m_displayModes;
@@ -138,9 +138,9 @@ public:
void SetResolution(int width, int height); void SetResolution(int width, int height);
size_t GetAlignSize() { return m_alignSize; } size_t GetAlignSize () const { return m_alignSize ; }
size_t GetMaxFrameSize() { return m_maxFrameSize; } size_t GetMaxFrameSize() const { return m_maxFrameSize ; }
bool CanProcessFP16() const { return m_canProcessFP16; } bool CanProcessFP16 () const { return m_canProcessFP16; }
struct PreparedFrameBuffer struct PreparedFrameBuffer
{ {
@@ -148,9 +148,9 @@ public:
uint8_t* mem; uint8_t* mem;
}; };
PreparedFrameBuffer PrepareFrameBuffer(unsigned width, unsigned height, unsigned pitch, DXGI_FORMAT format); PreparedFrameBuffer PrepareFrameBuffer(unsigned width, unsigned height, unsigned pitch, DXGI_FORMAT format, const RECT * dirtyRects, unsigned nbDirtyRects);
void WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos); void WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos) const;
void FinalizeFrameBuffer(unsigned frameIndex); void FinalizeFrameBuffer(unsigned frameIndex) const;
void SendCursor(const IDARG_OUT_QUERY_HWCURSOR & info, const BYTE * data); void SendCursor(const IDARG_OUT_QUERY_HWCURSOR & info, const BYTE * data);

View File

@@ -86,24 +86,26 @@ bool CInteropResource::Init(std::shared_ptr<CD3D11Device> dx11Device, std::share
m_dx12Device = dx12Device; m_dx12Device = dx12Device;
memcpy(&m_format, &srcDesc, sizeof(m_format)); memcpy(&m_format, &srcDesc, sizeof(m_format));
m_srcTex = srcTex.Get(); m_srcTex = srcTex.Get();
m_d12Res = dst; m_d12Res = dst;
m_d11Fence = d11Fence; m_d11Fence = d11Fence;
m_d12Fence = d12Fence; m_d12Fence = d12Fence;
m_fenceValue = 0; m_fenceValue = 0;
m_ready = true; m_nbDirtyRects = 0;
m_ready = true;
return true; return true;
} }
void CInteropResource::Reset() void CInteropResource::Reset()
{ {
m_ready = false; m_ready = false;
m_fenceValue = 0; m_fenceValue = 0;
m_d12Fence.Reset(); m_d12Fence.Reset();
m_d11Fence.Reset(); m_d11Fence.Reset();
m_d12Res .Reset(); m_d12Res .Reset();
m_srcTex = NULL; m_srcTex = NULL;
m_nbDirtyRects = 0;
memset(&m_format, 0, sizeof(m_format)); memset(&m_format, 0, sizeof(m_format));
m_dx12Device.reset(); m_dx12Device.reset();
@@ -143,4 +145,15 @@ void CInteropResource::SetFullDamage()
m_dirtyRects[0].right = m_format.Width; m_dirtyRects[0].right = m_format.Width;
m_dirtyRects[0].bottom = m_format.Height; m_dirtyRects[0].bottom = m_format.Height;
m_nbDirtyRects = 1; m_nbDirtyRects = 1;
} }
void CInteropResource::SetDirtyRects(const RECT * dirtyRects, unsigned nbDirtyRects)
{
if (nbDirtyRects > LG_MAX_DIRTY_RECTS)
{
SetFullDamage();
return;
}
memcpy(m_dirtyRects, dirtyRects, nbDirtyRects * sizeof(*m_dirtyRects));
m_nbDirtyRects = nbDirtyRects;
}

View File

@@ -62,7 +62,10 @@ class CInteropResource
void Signal(); void Signal();
void Sync(CD3D12CommandQueue& queue); void Sync(CD3D12CommandQueue& queue);
void SetFullDamage(); void SetFullDamage();
void SetDirtyRects(const RECT * dirtyRects, unsigned nbDirtyRects);
const ComPtr<ID3D12Resource>& GetRes() { return m_d12Res; } const ComPtr<ID3D12Resource>& GetRes() { return m_d12Res; }
const D3D11_TEXTURE2D_DESC& GetFormat() { return m_format; } const D3D11_TEXTURE2D_DESC& GetFormat() { return m_format; }
}; const RECT * GetDirtyRects() { return m_dirtyRects; }
unsigned GetDirtyRectCount() { return m_nbDirtyRects; }
};

View File

@@ -88,7 +88,7 @@ void CSwapChainProcessor::SwapChainThreadCore()
if (IDD_IS_FUNCTION_AVAILABLE(IddCxSetRealtimeGPUPriority)) if (IDD_IS_FUNCTION_AVAILABLE(IddCxSetRealtimeGPUPriority))
{ {
DEBUG_INFO("Using IddCxSetRealtimeGPUPriority"); DEBUG_INFO("Using IddCxSetRealtimeGPUPriority");
IDARG_IN_SETREALTIMEGPUPRIORITY arg; IDARG_IN_SETREALTIMEGPUPRIORITY arg = {0};
arg.pDevice = dxgiDevice.Get(); arg.pDevice = dxgiDevice.Get();
hr = IddCxSetRealtimeGPUPriority(m_hSwapChain, &arg); hr = IddCxSetRealtimeGPUPriority(m_hSwapChain, &arg);
if (FAILED(hr)) if (FAILED(hr))
@@ -134,6 +134,7 @@ void CSwapChainProcessor::SwapChainThreadCore()
break; break;
UINT frameNumber = 0; UINT frameNumber = 0;
UINT dirtyRectCount = 0;
ComPtr<IDXGIResource> surface; ComPtr<IDXGIResource> surface;
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ #if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
@@ -151,6 +152,7 @@ void CSwapChainProcessor::SwapChainThreadCore()
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
frameNumber = buffer.MetaData.PresentationFrameNumber; frameNumber = buffer.MetaData.PresentationFrameNumber;
dirtyRectCount = buffer.MetaData.DirtyRectCount;
surface = buffer.MetaData.pSurface; surface = buffer.MetaData.pSurface;
} }
} }
@@ -163,6 +165,7 @@ void CSwapChainProcessor::SwapChainThreadCore()
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
frameNumber = buffer.MetaData.PresentationFrameNumber; frameNumber = buffer.MetaData.PresentationFrameNumber;
dirtyRectCount = buffer.MetaData.DirtyRectCount;
surface = buffer.MetaData.pSurface; surface = buffer.MetaData.pSurface;
} }
} }
@@ -190,7 +193,7 @@ void CSwapChainProcessor::SwapChainThreadCore()
if (frameNumber != lastFrameNumber) if (frameNumber != lastFrameNumber)
{ {
lastFrameNumber = frameNumber; lastFrameNumber = frameNumber;
SwapChainNewFrame(surface); SwapChainNewFrame(surface, dirtyRectCount);
// report that all GPU processing for this frame has been queued // report that all GPU processing for this frame has been queued
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain); hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
@@ -237,7 +240,35 @@ void CSwapChainProcessor::CompletionFunction(
sc->m_devContext->FinalizeFrameBuffer(fbRes->GetFrameIndex()); sc->m_devContext->FinalizeFrameBuffer(fbRes->GetFrameIndex());
} }
bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer)
static bool IsFullDamage(const RECT * dirtyRects, unsigned nbDirtyRects,
const D3D12_RESOURCE_DESC& desc)
{
return nbDirtyRects == 0 ||
(nbDirtyRects == 1 &&
dirtyRects[0].left == 0 &&
dirtyRects[0].top == 0 &&
dirtyRects[0].right == (LONG)desc.Width &&
dirtyRects[0].bottom == (LONG)desc.Height);
}
static void CopyDirtyRect(ComPtr<ID3D12GraphicsCommandList> list,
D3D12_TEXTURE_COPY_LOCATION * dstLoc,
D3D12_TEXTURE_COPY_LOCATION * srcLoc,
const RECT& rect)
{
D3D12_BOX box = {};
box.left = rect.left;
box.top = rect.top;
box.front = 0;
box.right = rect.right;
box.bottom = rect.bottom;
box.back = 1;
list->CopyTextureRegion(dstLoc, box.left, box.top, 0, srcLoc, &box);
}
bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount)
{ {
ComPtr<ID3D11Texture2D> texture; ComPtr<ID3D11Texture2D> texture;
HRESULT hr = acquiredBuffer.As(&texture); HRESULT hr = acquiredBuffer.As(&texture);
@@ -261,8 +292,27 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
*/ */
srcRes->Signal(); srcRes->Signal();
//FIXME: handle dirty rects RECT dirtyRects[LG_MAX_DIRTY_RECTS] = {0};
srcRes->SetFullDamage(); if (dirtyRectCount > ARRAYSIZE(dirtyRects))
{
srcRes->SetFullDamage();
}
else
{
IDARG_IN_GETDIRTYRECTS dirtyIn = {};
dirtyIn.DirtyRectInCount = dirtyRectCount;
dirtyIn.pDirtyRects = dirtyRects;
IDARG_OUT_GETDIRTYRECTS dirtyOut = {};
hr = IddCxSwapChainGetDirtyRects(m_hSwapChain, &dirtyIn, &dirtyOut);
if (FAILED(hr))
{
DEBUG_ERROR_HR(hr, "IddCxSwapChainGetDirtyRects Failed");
srcRes->SetFullDamage();
}
else
srcRes->SetDirtyRects(dirtyRects, dirtyOut.DirtyRectOutCount);
}
D3D12_RESOURCE_DESC desc = srcRes->GetRes()->GetDesc(); D3D12_RESOURCE_DESC desc = srcRes->GetRes()->GetDesc();
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout; D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
@@ -280,7 +330,9 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
(int)desc.Width, (int)desc.Width,
(int)desc.Height, (int)desc.Height,
(int)layout.Footprint.RowPitch, (int)layout.Footprint.RowPitch,
desc.Format); desc.Format,
srcRes->GetDirtyRects(),
srcRes->GetDirtyRectCount());
if (!buffer.mem) if (!buffer.mem)
return false; return false;
@@ -314,8 +366,32 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
dstLoc.PlacedFootprint = layout; dstLoc.PlacedFootprint = layout;
srcRes->Sync(*copyQueue); srcRes->Sync(*copyQueue);
copyQueue->GetGfxList()->CopyTextureRegion(
&dstLoc, 0, 0, 0, &srcLoc, NULL); const RECT * currentDirtyRects = srcRes->GetDirtyRects();
unsigned nbDirtyRects = srcRes->GetDirtyRectCount();
if (IsFullDamage(currentDirtyRects, nbDirtyRects, desc) ||
nbDirtyRects > KVMFR_MAX_DAMAGE_RECTS || m_nbDirtyRects == 0)
{
copyQueue->GetGfxList()->CopyTextureRegion(
&dstLoc, 0, 0, 0, &srcLoc, NULL);
}
else if (m_nbDirtyRects + nbDirtyRects > LG_MAX_DIRTY_RECTS)
{
copyQueue->GetGfxList()->CopyTextureRegion(
&dstLoc, 0, 0, 0, &srcLoc, NULL);
}
else
{
for (const RECT * rect = m_dirtyRects; rect < m_dirtyRects + m_nbDirtyRects; ++rect)
CopyDirtyRect(copyQueue->GetGfxList(), &dstLoc, &srcLoc, *rect);
for (const RECT * rect = currentDirtyRects; rect < currentDirtyRects + nbDirtyRects; ++rect)
CopyDirtyRect(copyQueue->GetGfxList(), &dstLoc, &srcLoc, *rect);
}
memcpy(m_dirtyRects, currentDirtyRects, nbDirtyRects * sizeof(*m_dirtyRects));
m_nbDirtyRects = nbDirtyRects;
copyQueue->Execute(); copyQueue->Execute();
return true; return true;

View File

@@ -55,6 +55,9 @@ private:
BYTE* m_shapeBuffer; BYTE* m_shapeBuffer;
DWORD m_lastShapeId = 0; DWORD m_lastShapeId = 0;
RECT m_dirtyRects[LG_MAX_DIRTY_RECTS] = {};
unsigned m_nbDirtyRects = 0;
static DWORD CALLBACK _SwapChainThread(LPVOID arg); static DWORD CALLBACK _SwapChainThread(LPVOID arg);
void SwapChainThread(); void SwapChainThread();
void SwapChainThreadCore(); void SwapChainThreadCore();
@@ -65,7 +68,7 @@ private:
static void CompletionFunction( static void CompletionFunction(
CD3D12CommandQueue * queue, bool result, void * param1, void * param2); CD3D12CommandQueue * queue, bool result, void * param1, void * param2);
bool SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer); bool SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount);
public: public:
CSwapChainProcessor(IDDCX_MONITOR monitor, CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain, CSwapChainProcessor(IDDCX_MONITOR monitor, CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,