[host] d12: remove extra copies in damage tracking

This commit is contained in:
Geoffrey McRae 2024-02-23 17:24:25 +11:00
parent 3b43dcb80d
commit dc4d93f50a
2 changed files with 77 additions and 41 deletions

View File

@ -506,8 +506,19 @@ static bool d12_dd_handleFrameUpdate(DDInstance * this, IDXGIResource * res)
} }
} }
else 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[ DXGI_OUTDUPL_MOVE_RECT moveRects[
(ARRAY_LENGTH(this->current->dirtyRects) - this->current->nbDirtyRects) / 2 (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; result = true;
exit: exit:

View File

@ -26,6 +26,7 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/windebug.h" #include "common/windebug.h"
#include "common/option.h" #include "common/option.h"
#include "common/rects.h"
#include "com_ref.h" #include "com_ref.h"
#include "backend.h" #include "backend.h"
@ -489,21 +490,30 @@ static CaptureResult d12_waitFrame(unsigned frameBufferIndex,
frame->hdrPQ = false; frame->hdrPQ = false;
frame->rotation = CAPTURE_ROT_0; 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 // create a clean list of rects
frame->damageRectsCount = nbDirtyRects; FrameDamageRect allRects[this->nbDirtyRects];
for(unsigned i = 0; i < nbDirtyRects; ++i) unsigned count = 0;
frame->damageRects[i] = (FrameDamageRect) for(const RECT * rect = this->dirtyRects;
{ rect < this->dirtyRects + this->nbDirtyRects; ++rect)
.x = dirtyRects[i].left, allRects[count++] = (FrameDamageRect){
.y = dirtyRects[i].top, .x = rect->left,
.width = dirtyRects[i].right - dirtyRects[i].left, .y = rect->top,
.height = dirtyRects[i].bottom - dirtyRects[i].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; result = CAPTURE_RESULT_OK;
@ -586,22 +596,54 @@ static CaptureResult d12_getFrame(unsigned frameBufferIndex,
} }
else else
{ {
/* we must update the rects that were dirty in the prior frame also, /* if the prior frame was a full update */
* otherwise the frame in memory will not be consistent when areas need to if (this->nbDirtyRects == 0)
* be redrawn by the client, such as under the cursor */
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; for(const RECT * rect = this->dirtyRects;
rect < this->dirtyRects + this->nbDirtyRects; ++rect) 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 = D3D12_BOX box =
{ {
.left = rect->left, .left = rect->x,
.top = rect->top, .top = rect->y,
.front = 0, .front = 0,
.back = 1, .back = 1,
.right = rect->right, .right = rect->x + rect->width,
.bottom = rect->bottom .bottom = rect->y + rect->height
}; };
ID3D12GraphicsCommandList_CopyTextureRegion( 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 */ /* store the dirty rects for the next frame */
memcpy(this->dirtyRects, dirtyRects, memcpy(this->dirtyRects, dirtyRects,
nbDirtyRects * sizeof(*this->dirtyRects)); nbDirtyRects * sizeof(*this->dirtyRects));