[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/thread.h"
#include "common/KVMFR.h"
#include "common/vector.h"
#include <stdlib.h>
#include <stdatomic.h>
#include <windows.h>
@ -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;

View File

@ -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;

View File

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