From 5ed3301cf54ae202cffda9ddd477593cd7f8289a Mon Sep 17 00:00:00 2001 From: Quantum Date: Sun, 11 Jul 2021 00:19:43 -0400 Subject: [PATCH] [host] nvfbc: merge adjacent changed regions For adjacent changed regions, we actually use the bounding box for the entire polygon. This may result in more area being damaged than strictly necessary, but is nevertheless desirable since it reduces the number of rectangles. --- .../Windows/capture/NVFBC/src/nvfbc.c | 87 +++++++++++++------ 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/host/platform/Windows/capture/NVFBC/src/nvfbc.c b/host/platform/Windows/capture/NVFBC/src/nvfbc.c index 5621495e..2c901de9 100644 --- a/host/platform/Windows/capture/NVFBC/src/nvfbc.c +++ b/host/platform/Windows/capture/NVFBC/src/nvfbc.c @@ -67,6 +67,13 @@ struct iface bool forceCompositionCreated; }; +struct Bounds { + int x1; + int y1; + int x2; + int y2; +}; + static struct iface * this = NULL; static bool nvfbc_deinit(void); @@ -304,6 +311,60 @@ done: return CAPTURE_RESULT_OK; } +static void updateDamageRects(CaptureFrame * frame) +{ + const unsigned int h = (this->height + 127) / 128; + const unsigned int w = (this->width + 127) / 128; + + struct Bounds rects[KVMFR_MAX_DAMAGE_RECTS]; + struct Bounds *links[w * h]; + int rectId = 0; + + for (unsigned int y = 0; y < h; ++y) + for (unsigned int x = 0; x < w; ++x) + if (this->diffMap[(y*w)+x]) + { + struct Bounds *join = NULL; + if (y > 0 && this->diffMap[(y-1) * w + x]) + join = links[(y-1) * w + x]; + if (x > 0 && this->diffMap[y * w + x - 1]) + join = links[y * w + x - 1]; + + if (join) + { + join->x1 = min(join->x1, x); + join->x2 = max(join->x2, x); + join->y1 = min(join->y1, y); + join->y2 = max(join->y2, y); + } + else + { + if (rectId >= KVMFR_MAX_DAMAGE_RECTS) + { + rectId = 0; + goto done; + } + join = &rects[rectId++]; + join->x1 = join->x2 = x; + join->y1 = join->y2 = y; + } + + links[y * w + x] = join; + } + +done: + frame->damageRectsCount = rectId; + for (int i = 0; i < rectId; ++i) + { + frame->damageRects[i] = (FrameDamageRect) { + .x = rects[i].x1 * 128, + .y = rects[i].y1 * 128, + .width = (rects[i].x2 - rects[i].x1 + 1) * 128, + .height = (rects[i].y2 - rects[i].y1 + 1) * 128, + }; + } +} + static CaptureResult nvfbc_waitFrame(CaptureFrame * frame, const size_t maxFrameSize) { @@ -331,31 +392,7 @@ static CaptureResult nvfbc_waitFrame(CaptureFrame * frame, frame->stride = this->grabStride; frame->rotation = CAPTURE_ROT_0; - const unsigned int h = (this->height + 127) / 128; - const unsigned int w = (this->width + 127) / 128; - - // TODO: use some algorithm to merge large regions - int rectId = 0; - for (unsigned int y = 0; y < h; ++y) - for (unsigned int x = 0; x < w; ++x) - if (this->diffMap[(y*w)+x]) - { - if (rectId >= KVMFR_MAX_DAMAGE_RECTS) - { - rectId = 0; - goto done; - } - - frame->damageRects[rectId++] = (FrameDamageRect) { - .x = x * 128, - .y = y * 128, - .width = 128, - .height = 128, - }; - } - -done: - frame->damageRectsCount = rectId; + updateDamageRects(frame); #if 0 //NvFBC never sets bIsHDR so instead we check for any data in the alpha channel