Skip to content

Commit

Permalink
[host] d12: remove extra copies in damage tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
gnif committed Feb 23, 2024
1 parent 3b43dcb commit dc4d93f
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 41 deletions.
16 changes: 14 additions & 2 deletions host/platform/Windows/capture/D12/backend/dd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -554,6 +565,7 @@ static bool d12_dd_handleFrameUpdate(DDInstance * this, IDXGIResource * res)
}
}

fullDamage:
result = true;

exit:
Expand Down
102 changes: 63 additions & 39 deletions host/platform/Windows/capture/D12/d12.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand All @@ -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));
Expand Down

0 comments on commit dc4d93f

Please sign in to comment.