diff --git a/host/platform/Windows/capture/NVFBC/src/nvfbc.c b/host/platform/Windows/capture/NVFBC/src/nvfbc.c index 904637e2..ce5a2b61 100644 --- a/host/platform/Windows/capture/NVFBC/src/nvfbc.c +++ b/host/platform/Windows/capture/NVFBC/src/nvfbc.c @@ -31,6 +31,7 @@ #include "common/rects.h" #include "common/thread.h" #include "common/KVMFR.h" +#include "common/vector.h" #include #include #include @@ -49,6 +50,17 @@ struct FrameInfo uint8_t * diffMap; }; +typedef struct +{ + unsigned int id; + bool greater; + unsigned int x; + unsigned int y; + unsigned int targetX; + unsigned int targetY; +} +DownsampleRule; + struct iface { bool stop; @@ -62,6 +74,8 @@ struct iface unsigned int maxWidth , maxHeight; unsigned int width , height; + bool resChanged, scale; + unsigned int targetWidth, targetHeight; unsigned int formatVer; unsigned int grabWidth, grabHeight, grabStride; @@ -84,6 +98,8 @@ struct iface struct FrameInfo frameInfo[LGMP_Q_FRAME_LEN]; }; +static Vector downsampleRules = {0}; + static struct iface * this = NULL; static bool nvfbc_deinit(void); @@ -125,10 +141,78 @@ static const char * nvfbc_getName(void) return "NVFBC"; }; +static bool downsampleOptParser(struct Option * opt, const char * str) +{ + if (!str) + return false; + + opt->value.x_string = strdup(str); + + if (downsampleRules.data) + vector_destroy(&downsampleRules); + + if (!vector_create(&downsampleRules, sizeof(DownsampleRule), 10)) + { + DEBUG_ERROR("Failed to allocate ram"); + return false; + } + + char * tmp = strdup(str); + char * token = strtok(tmp, ","); + int count = 0; + while(token) + { + DownsampleRule rule = {0}; + if (token[0] == '>') + { + rule.greater = true; + ++token; + } + + if (sscanf(token, "%ux%u:%ux%u", + &rule.x, + &rule.y, + &rule.targetX, + &rule.targetY) != 4) + { + DEBUG_INFO("Unable to parse NvFBC downsample rules"); + return false; + } + + rule.id = count++; + + DEBUG_INFO( + "Rule %u: %ux%u IF X %s %4u %s Y %s %4u", + rule.id, + rule.targetX, + rule.targetY, + rule.greater ? "> " : "==", + rule.x, + rule.greater ? "OR " : "AND", + rule.greater ? "> " : "==", + rule.y + ); + vector_push(&downsampleRules, &rule); + + token = strtok(NULL, ","); + } + free(tmp); + + return true; +} + static void nvfbc_initOptions(void) { struct Option options[] = { + { + .module = "nvfbc", + .name = "downsample", //dxgi:downsample=>1920x1080:1920x1080 + .description = "Downsample rules, format: [>](width)x(height):(toWidth)x(toHeight)", + .type = OPTION_TYPE_STRING, + .value.x_string = NULL, + .parser = downsampleOptParser + }, { .module = "nvfbc", .name = "decoupleCursor", @@ -180,6 +264,33 @@ static bool nvfbc_create( return true; } +static void updateScale(void) +{ + DownsampleRule * rule, * match = NULL; + vector_forEachRef(rule, &downsampleRules) + { + if ( + ( rule->greater && (this->width > rule->x || this->height > rule->y)) || + (!rule->greater && (this->width == rule->x && this->height == rule->y))) + { + match = rule; + } + } + + if (match) + { + DEBUG_INFO("Matched downsample rule %d", rule->id); + this->scale = true; + this->targetWidth = match->targetX; + this->targetHeight = match->targetY; + return; + } + + this->scale = false; + this->targetWidth = this->width; + this->targetHeight = this->height; +} + static bool nvfbc_init(void) { int bufferLen = GetEnvironmentVariable("NVFBC_PRIV_DATA", NULL, 0); @@ -221,6 +332,7 @@ static bool nvfbc_init(void) free(privData); getDesktopSize(&this->width, &this->height); + updateScale(); HANDLE event; if (!NvFBCToSysSetup( @@ -356,14 +468,24 @@ static CaptureResult nvfbc_capture(void) if (this->dwmFlush) DwmFlush(); - getDesktopSize(&this->width, &this->height); + unsigned int width, height; + getDesktopSize(&width, &height); + if (this->width != width || this->height != height) + { + this->resChanged = true; + this->width = width; + this->height = height; + updateScale(); + } + NvFBCFrameGrabInfo grabInfo; CaptureResult result = NvFBCToSysCapture( this->nvfbc, 1000, 0, 0, - this->width, - this->height, + this->targetWidth, + this->targetHeight, + this->scale, &grabInfo ); @@ -371,8 +493,8 @@ static CaptureResult nvfbc_capture(void) return result; bool changed = false; - const unsigned int h = DIFF_MAP_DIM(this->height, this->diffShift); - const unsigned int w = DIFF_MAP_DIM(this->width, this->diffShift); + const unsigned int h = DIFF_MAP_DIM(grabInfo.dwWidth , this->diffShift); + const unsigned int w = DIFF_MAP_DIM(grabInfo.dwHeight, this->diffShift); for (unsigned int y = 0; y < h; ++y) for (unsigned int x = 0; x < w; ++x) if (this->diffMap[(y*w)+x]) @@ -420,8 +542,8 @@ static void dsUnion(struct DisjointSet * ds, int a, int b) static void updateDamageRects(CaptureFrame * frame) { - const unsigned int h = DIFF_MAP_DIM(this->height, this->diffShift); - const unsigned int w = DIFF_MAP_DIM(this->width, this->diffShift); + const unsigned int h = DIFF_MAP_DIM(this->grabHeight, this->diffShift); + const unsigned int w = DIFF_MAP_DIM(this->grabWidth, this->diffShift); struct DisjointSet ds[w * h]; @@ -521,8 +643,8 @@ static void updateDamageRects(CaptureFrame * frame) int x1 = ds[c].x1 << this->diffShift; int y1 = ds[c].y1 << this->diffShift; - int x2 = min((ds[c].x2 + 1) << this->diffShift, this->width); - int y2 = min((ds[c].y2 + 1) << this->diffShift, this->height); + int x2 = min((ds[c].x2 + 1) << this->diffShift, this->grabWidth); + int y2 = min((ds[c].y2 + 1) << this->diffShift, this->grabHeight); frame->damageRects[rectId++] = (FrameDamageRect) { .x = x1, .y = y1, @@ -545,21 +667,24 @@ static CaptureResult nvfbc_waitFrame(CaptureFrame * frame, if ( this->grabInfo.dwWidth != this->grabWidth || this->grabInfo.dwHeight != this->grabHeight || - this->grabInfo.dwBufferWidth != this->grabStride) + this->grabInfo.dwBufferWidth != this->grabStride || + this->resChanged) { this->grabWidth = this->grabInfo.dwWidth; this->grabHeight = this->grabInfo.dwHeight; this->grabStride = this->grabInfo.dwBufferWidth; // Round up stride in IVSHMEM to avoid issues with dmabuf import. this->shmStride = ALIGN_PAD(this->grabStride, 32); + + this->resChanged = false; ++this->formatVer; } const unsigned int maxHeight = maxFrameSize / (this->shmStride * 4); frame->formatVer = this->formatVer; - frame->screenWidth = this->grabWidth; - frame->screenHeight = this->grabHeight; + frame->screenWidth = this->width; + frame->screenHeight = this->height; frame->frameWidth = this->grabWidth; frame->frameHeight = min(maxHeight, this->grabHeight); frame->truncated = maxHeight < this->grabHeight; @@ -592,8 +717,8 @@ static CaptureResult nvfbc_waitFrame(CaptureFrame * frame, static CaptureResult nvfbc_getFrame(FrameBuffer * frame, const unsigned int height, int frameIndex) { - const unsigned int h = DIFF_MAP_DIM(this->height, this->diffShift); - const unsigned int w = DIFF_MAP_DIM(this->width, this->diffShift); + const unsigned int h = DIFF_MAP_DIM(this->grabHeight, this->diffShift); + const unsigned int w = DIFF_MAP_DIM(this->grabWidth, this->diffShift); uint8_t * frameData = framebuffer_get_data(frame); struct FrameInfo * info = this->frameInfo + frameIndex; diff --git a/host/platform/Windows/capture/NVFBC/src/wrapper.cpp b/host/platform/Windows/capture/NVFBC/src/wrapper.cpp index 55beb577..03263433 100644 --- a/host/platform/Windows/capture/NVFBC/src/wrapper.cpp +++ b/host/platform/Windows/capture/NVFBC/src/wrapper.cpp @@ -276,6 +276,7 @@ CaptureResult NvFBCToSysCapture( const unsigned int y, const unsigned int width, const unsigned int height, + bool scale, NvFBCFrameGrabInfo * grabInfo ) { @@ -284,7 +285,8 @@ CaptureResult NvFBCToSysCapture( params.dwVersion = NVFBC_TOSYS_GRAB_FRAME_PARAMS_VER; params.dwFlags = NVFBC_TOSYS_WAIT_WITH_TIMEOUT; params.dwWaitTime = waitTime; - params.eGMode = NVFBC_TOSYS_SOURCEMODE_CROP; + params.eGMode = scale ? + NVFBC_TOSYS_SOURCEMODE_SCALE : NVFBC_TOSYS_SOURCEMODE_CROP; params.dwStartX = x; params.dwStartY = y; params.dwTargetWidth = width; diff --git a/host/platform/Windows/capture/NVFBC/src/wrapper.h b/host/platform/Windows/capture/NVFBC/src/wrapper.h index d5605a84..cd43482d 100644 --- a/host/platform/Windows/capture/NVFBC/src/wrapper.h +++ b/host/platform/Windows/capture/NVFBC/src/wrapper.h @@ -88,6 +88,7 @@ CaptureResult NvFBCToSysCapture( const unsigned int y, const unsigned int width, const unsigned int height, + bool scale, NvFBCFrameGrabInfo * grabInfo );