[host] nvfbc: add downscale support

This commit is contained in:
Geoffrey McRae 2022-05-04 13:38:49 +10:00
parent 7ed18e24e2
commit 87077dfe6e
3 changed files with 143 additions and 15 deletions

View File

@ -31,6 +31,7 @@
#include "common/rects.h" #include "common/rects.h"
#include "common/thread.h" #include "common/thread.h"
#include "common/KVMFR.h" #include "common/KVMFR.h"
#include "common/vector.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdatomic.h> #include <stdatomic.h>
#include <windows.h> #include <windows.h>
@ -49,6 +50,17 @@ struct FrameInfo
uint8_t * diffMap; 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 struct iface
{ {
bool stop; bool stop;
@ -62,6 +74,8 @@ struct iface
unsigned int maxWidth , maxHeight; unsigned int maxWidth , maxHeight;
unsigned int width , height; unsigned int width , height;
bool resChanged, scale;
unsigned int targetWidth, targetHeight;
unsigned int formatVer; unsigned int formatVer;
unsigned int grabWidth, grabHeight, grabStride; unsigned int grabWidth, grabHeight, grabStride;
@ -84,6 +98,8 @@ struct iface
struct FrameInfo frameInfo[LGMP_Q_FRAME_LEN]; struct FrameInfo frameInfo[LGMP_Q_FRAME_LEN];
}; };
static Vector downsampleRules = {0};
static struct iface * this = NULL; static struct iface * this = NULL;
static bool nvfbc_deinit(void); static bool nvfbc_deinit(void);
@ -125,10 +141,78 @@ static const char * nvfbc_getName(void)
return "NVFBC"; 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) static void nvfbc_initOptions(void)
{ {
struct Option options[] = 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", .module = "nvfbc",
.name = "decoupleCursor", .name = "decoupleCursor",
@ -180,6 +264,33 @@ static bool nvfbc_create(
return true; 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) static bool nvfbc_init(void)
{ {
int bufferLen = GetEnvironmentVariable("NVFBC_PRIV_DATA", NULL, 0); int bufferLen = GetEnvironmentVariable("NVFBC_PRIV_DATA", NULL, 0);
@ -221,6 +332,7 @@ static bool nvfbc_init(void)
free(privData); free(privData);
getDesktopSize(&this->width, &this->height); getDesktopSize(&this->width, &this->height);
updateScale();
HANDLE event; HANDLE event;
if (!NvFBCToSysSetup( if (!NvFBCToSysSetup(
@ -356,14 +468,24 @@ static CaptureResult nvfbc_capture(void)
if (this->dwmFlush) if (this->dwmFlush)
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; NvFBCFrameGrabInfo grabInfo;
CaptureResult result = NvFBCToSysCapture( CaptureResult result = NvFBCToSysCapture(
this->nvfbc, this->nvfbc,
1000, 1000,
0, 0, 0, 0,
this->width, this->targetWidth,
this->height, this->targetHeight,
this->scale,
&grabInfo &grabInfo
); );
@ -371,8 +493,8 @@ static CaptureResult nvfbc_capture(void)
return result; return result;
bool changed = false; bool changed = false;
const unsigned int h = DIFF_MAP_DIM(this->height, this->diffShift); const unsigned int h = DIFF_MAP_DIM(grabInfo.dwWidth , this->diffShift);
const unsigned int w = DIFF_MAP_DIM(this->width, this->diffShift); const unsigned int w = DIFF_MAP_DIM(grabInfo.dwHeight, this->diffShift);
for (unsigned int y = 0; y < h; ++y) for (unsigned int y = 0; y < h; ++y)
for (unsigned int x = 0; x < w; ++x) for (unsigned int x = 0; x < w; ++x)
if (this->diffMap[(y*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) static void updateDamageRects(CaptureFrame * frame)
{ {
const unsigned int h = DIFF_MAP_DIM(this->height, this->diffShift); const unsigned int h = DIFF_MAP_DIM(this->grabHeight, this->diffShift);
const unsigned int w = DIFF_MAP_DIM(this->width, this->diffShift); const unsigned int w = DIFF_MAP_DIM(this->grabWidth, this->diffShift);
struct DisjointSet ds[w * h]; struct DisjointSet ds[w * h];
@ -521,8 +643,8 @@ static void updateDamageRects(CaptureFrame * frame)
int x1 = ds[c].x1 << this->diffShift; int x1 = ds[c].x1 << this->diffShift;
int y1 = ds[c].y1 << this->diffShift; int y1 = ds[c].y1 << this->diffShift;
int x2 = min((ds[c].x2 + 1) << this->diffShift, this->width); int x2 = min((ds[c].x2 + 1) << this->diffShift, this->grabWidth);
int y2 = min((ds[c].y2 + 1) << this->diffShift, this->height); int y2 = min((ds[c].y2 + 1) << this->diffShift, this->grabHeight);
frame->damageRects[rectId++] = (FrameDamageRect) { frame->damageRects[rectId++] = (FrameDamageRect) {
.x = x1, .x = x1,
.y = y1, .y = y1,
@ -545,21 +667,24 @@ static CaptureResult nvfbc_waitFrame(CaptureFrame * frame,
if ( if (
this->grabInfo.dwWidth != this->grabWidth || this->grabInfo.dwWidth != this->grabWidth ||
this->grabInfo.dwHeight != this->grabHeight || this->grabInfo.dwHeight != this->grabHeight ||
this->grabInfo.dwBufferWidth != this->grabStride) this->grabInfo.dwBufferWidth != this->grabStride ||
this->resChanged)
{ {
this->grabWidth = this->grabInfo.dwWidth; this->grabWidth = this->grabInfo.dwWidth;
this->grabHeight = this->grabInfo.dwHeight; this->grabHeight = this->grabInfo.dwHeight;
this->grabStride = this->grabInfo.dwBufferWidth; this->grabStride = this->grabInfo.dwBufferWidth;
// Round up stride in IVSHMEM to avoid issues with dmabuf import. // Round up stride in IVSHMEM to avoid issues with dmabuf import.
this->shmStride = ALIGN_PAD(this->grabStride, 32); this->shmStride = ALIGN_PAD(this->grabStride, 32);
this->resChanged = false;
++this->formatVer; ++this->formatVer;
} }
const unsigned int maxHeight = maxFrameSize / (this->shmStride * 4); const unsigned int maxHeight = maxFrameSize / (this->shmStride * 4);
frame->formatVer = this->formatVer; frame->formatVer = this->formatVer;
frame->screenWidth = this->grabWidth; frame->screenWidth = this->width;
frame->screenHeight = this->grabHeight; frame->screenHeight = this->height;
frame->frameWidth = this->grabWidth; frame->frameWidth = this->grabWidth;
frame->frameHeight = min(maxHeight, this->grabHeight); frame->frameHeight = min(maxHeight, this->grabHeight);
frame->truncated = maxHeight < this->grabHeight; frame->truncated = maxHeight < this->grabHeight;
@ -592,8 +717,8 @@ static CaptureResult nvfbc_waitFrame(CaptureFrame * frame,
static CaptureResult nvfbc_getFrame(FrameBuffer * frame, static CaptureResult nvfbc_getFrame(FrameBuffer * frame,
const unsigned int height, int frameIndex) const unsigned int height, int frameIndex)
{ {
const unsigned int h = DIFF_MAP_DIM(this->height, this->diffShift); const unsigned int h = DIFF_MAP_DIM(this->grabHeight, this->diffShift);
const unsigned int w = DIFF_MAP_DIM(this->width, this->diffShift); const unsigned int w = DIFF_MAP_DIM(this->grabWidth, this->diffShift);
uint8_t * frameData = framebuffer_get_data(frame); uint8_t * frameData = framebuffer_get_data(frame);
struct FrameInfo * info = this->frameInfo + frameIndex; struct FrameInfo * info = this->frameInfo + frameIndex;

View File

@ -276,6 +276,7 @@ CaptureResult NvFBCToSysCapture(
const unsigned int y, const unsigned int y,
const unsigned int width, const unsigned int width,
const unsigned int height, const unsigned int height,
bool scale,
NvFBCFrameGrabInfo * grabInfo NvFBCFrameGrabInfo * grabInfo
) )
{ {
@ -284,7 +285,8 @@ CaptureResult NvFBCToSysCapture(
params.dwVersion = NVFBC_TOSYS_GRAB_FRAME_PARAMS_VER; params.dwVersion = NVFBC_TOSYS_GRAB_FRAME_PARAMS_VER;
params.dwFlags = NVFBC_TOSYS_WAIT_WITH_TIMEOUT; params.dwFlags = NVFBC_TOSYS_WAIT_WITH_TIMEOUT;
params.dwWaitTime = waitTime; params.dwWaitTime = waitTime;
params.eGMode = NVFBC_TOSYS_SOURCEMODE_CROP; params.eGMode = scale ?
NVFBC_TOSYS_SOURCEMODE_SCALE : NVFBC_TOSYS_SOURCEMODE_CROP;
params.dwStartX = x; params.dwStartX = x;
params.dwStartY = y; params.dwStartY = y;
params.dwTargetWidth = width; params.dwTargetWidth = width;

View File

@ -88,6 +88,7 @@ CaptureResult NvFBCToSysCapture(
const unsigned int y, const unsigned int y,
const unsigned int width, const unsigned int width,
const unsigned int height, const unsigned int height,
bool scale,
NvFBCFrameGrabInfo * grabInfo NvFBCFrameGrabInfo * grabInfo
); );