[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
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:

View File

@ -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;
{
// 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(nbDirtyRects > ARRAY_LENGTH(frame->damageRects)))
if (unlikely(count > 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
};
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
{
/* 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 */
if (this->nbDirtyRects > 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
};
/* 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));