From dc4d93f50a0ed90a9c8d891a6c9041585e7c8cae Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Fri, 23 Feb 2024 17:24:25 +1100 Subject: [PATCH] [host] d12: remove extra copies in damage tracking --- .../platform/Windows/capture/D12/backend/dd.c | 16 ++- host/platform/Windows/capture/D12/d12.c | 102 +++++++++++------- 2 files changed, 77 insertions(+), 41 deletions(-) diff --git a/host/platform/Windows/capture/D12/backend/dd.c b/host/platform/Windows/capture/D12/backend/dd.c index d7d58f20..a07f107d 100644 --- a/host/platform/Windows/capture/D12/backend/dd.c +++ b/host/platform/Windows/capture/D12/backend/dd.c @@ -506,8 +506,19 @@ static bool d12_dd_handleFrameUpdate(DDInstance * this, IDXGIResource * res) } } else - this->current->nbDirtyRects = - requiredSize / sizeof(*this->current->dirtyRects); + { + unsigned nbDirtyRects = requiredSize / sizeof(*this->current->dirtyRects); + + // if there is only one damage rect and it covers the entire frame + if (nbDirtyRects == 1 && + this->current->dirtyRects[0].left == 0 && + this->current->dirtyRects[0].top == 0 && + this->current->dirtyRects[0].right == this->current->format.Width && + this->current->dirtyRects[0].bottom == this->current->format.Height) + goto fullDamage; + + this->current->nbDirtyRects = nbDirtyRects; + } DXGI_OUTDUPL_MOVE_RECT moveRects[ (ARRAY_LENGTH(this->current->dirtyRects) - this->current->nbDirtyRects) / 2 @@ -554,6 +565,7 @@ static bool d12_dd_handleFrameUpdate(DDInstance * this, IDXGIResource * res) } } +fullDamage: result = true; exit: diff --git a/host/platform/Windows/capture/D12/d12.c b/host/platform/Windows/capture/D12/d12.c index 12d3b50d..767d2c02 100644 --- a/host/platform/Windows/capture/D12/d12.c +++ b/host/platform/Windows/capture/D12/d12.c @@ -26,6 +26,7 @@ #include "common/debug.h" #include "common/windebug.h" #include "common/option.h" +#include "common/rects.h" #include "com_ref.h" #include "backend.h" @@ -489,21 +490,30 @@ static CaptureResult d12_waitFrame(unsigned frameBufferIndex, frame->hdrPQ = false; frame->rotation = CAPTURE_ROT_0; - // if there are too many rects - if (unlikely(nbDirtyRects > ARRAY_LENGTH(frame->damageRects))) - frame->damageRectsCount = 0; - else { - // send the list of dirty rects for this frame - frame->damageRectsCount = nbDirtyRects; - for(unsigned i = 0; i < nbDirtyRects; ++i) - frame->damageRects[i] = (FrameDamageRect) - { - .x = dirtyRects[i].left, - .y = dirtyRects[i].top, - .width = dirtyRects[i].right - dirtyRects[i].left, - .height = dirtyRects[i].bottom - dirtyRects[i].top + // create a clean list of rects + FrameDamageRect allRects[this->nbDirtyRects]; + unsigned count = 0; + for(const RECT * rect = this->dirtyRects; + rect < this->dirtyRects + this->nbDirtyRects; ++rect) + allRects[count++] = (FrameDamageRect){ + .x = rect->left, + .y = rect->top, + .width = rect->right - rect->left, + .height = rect->bottom - rect->top }; + + count = rectsMergeOverlapping(allRects, count); + + // if there are too many rects + if (unlikely(count > ARRAY_LENGTH(frame->damageRects))) + frame->damageRectsCount = 0; + else + { + // send the list of dirty rects for this frame + frame->damageRectsCount = count; + memcpy(frame->damageRects, allRects, sizeof(*allRects) * count); + } } result = CAPTURE_RESULT_OK; @@ -586,22 +596,54 @@ static CaptureResult d12_getFrame(unsigned frameBufferIndex, } else { - /* we must update the rects that were dirty in the prior frame also, - * otherwise the frame in memory will not be consistent when areas need to - * be redrawn by the client, such as under the cursor */ - if (this->nbDirtyRects > 0) + /* if the prior frame was a full update */ + if (this->nbDirtyRects == 0) { + /* the prior frame was fully damaged, we must update everything */ + ID3D12GraphicsCommandList_CopyTextureRegion( + *this->copyCommand.gfxList, &dstLoc, 0, 0, 0, &srcLoc, NULL); + } + else + { + FrameDamageRect allRects[this->nbDirtyRects + nbDirtyRects]; + unsigned count = 0; + + /* we must update the rects that were dirty in the prior frame also, + * otherwise the frame in memory will not be consistent when areas need to + * be redrawn by the client, such as under the cursor */ for(const RECT * rect = this->dirtyRects; rect < this->dirtyRects + this->nbDirtyRects; ++rect) + allRects[count++] = (FrameDamageRect){ + .x = rect->left, + .y = rect->top, + .width = rect->right - rect->left, + .height = rect->bottom - rect->top + }; + + /* add the new dirtyRects to the array */ + for(const RECT * rect = dirtyRects; + rect < dirtyRects + nbDirtyRects; ++rect) + allRects[count++] = (FrameDamageRect){ + .x = rect->left, + .y = rect->top, + .width = rect->right - rect->left, + .height = rect->bottom - rect->top + }; + + /* resolve the rects */ + count = rectsMergeOverlapping(allRects, count); + + /* copy all the rects */ + for(FrameDamageRect * rect = allRects; rect < allRects + count; ++rect) { D3D12_BOX box = { - .left = rect->left, - .top = rect->top, + .left = rect->x, + .top = rect->y, .front = 0, .back = 1, - .right = rect->right, - .bottom = rect->bottom + .right = rect->x + rect->width, + .bottom = rect->y + rect->height }; ID3D12GraphicsCommandList_CopyTextureRegion( @@ -610,24 +652,6 @@ static CaptureResult d12_getFrame(unsigned frameBufferIndex, } } - /* update the frame with the new dirty areas */ - for(const RECT * rect = dirtyRects; rect < dirtyRects + nbDirtyRects; ++rect) - { - D3D12_BOX box = - { - .left = rect->left, - .top = rect->top, - .front = 0, - .back = 1, - .right = rect->right, - .bottom = rect->bottom - }; - - ID3D12GraphicsCommandList_CopyTextureRegion( - *this->copyCommand.gfxList, &dstLoc, - box.left, box.top, 0, &srcLoc, &box); - } - /* store the dirty rects for the next frame */ memcpy(this->dirtyRects, dirtyRects, nbDirtyRects * sizeof(*this->dirtyRects));