From 2eec459b4749fd6818267aa1e255d0d91ef92ad3 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Tue, 3 May 2022 12:15:24 +1000 Subject: [PATCH] [host] dxgi: finish downsample support for d3d11 backend --- .../platform/Windows/capture/DXGI/src/d3d11.c | 39 +++--- host/platform/Windows/capture/DXGI/src/dxgi.c | 114 +++++++++++++++--- .../Windows/capture/DXGI/src/dxgi_capture.h | 1 + 3 files changed, 114 insertions(+), 40 deletions(-) diff --git a/host/platform/Windows/capture/DXGI/src/d3d11.c b/host/platform/Windows/capture/DXGI/src/d3d11.c index e87e7e88..4214815f 100644 --- a/host/platform/Windows/capture/DXGI/src/d3d11.c +++ b/host/platform/Windows/capture/DXGI/src/d3d11.c @@ -61,21 +61,11 @@ static bool d3d11_create(struct DXGIInterface * intf) this->avgMapTime = runningavg_new(10); - const bool downsample = - dxgi->targetWidth == dxgi->width / 2 && - dxgi->targetHeight == dxgi->height / 2; - - if (!downsample) - { - dxgi->targetWidth = dxgi->width; - dxgi->targetHeight = dxgi->height; - } - D3D11_TEXTURE2D_DESC gpuTexDesc = { .Width = dxgi->width, .Height = dxgi->height, - .MipLevels = 2, + .MipLevels = dxgi->downsampleLevel + 1, .ArraySize = 1, .SampleDesc.Count = 1, .SampleDesc.Quality = 0, @@ -121,7 +111,7 @@ static bool d3d11_create(struct DXGIInterface * intf) goto fail; } - if (!downsample) + if (!dxgi->downsampleLevel) continue; status = ID3D11Device_CreateTexture2D(dxgi->device, &gpuTexDesc, NULL, @@ -216,15 +206,15 @@ static bool d3d11_copyFrame(Texture * tex, ID3D11Texture2D * src) FrameDamageRect * rect = tex->texDamageRects + i; D3D11_BOX box = { - .left = rect->x, - .top = rect->y, + .left = rect->x << dxgi->downsampleLevel, + .top = rect->y << dxgi->downsampleLevel, .front = 0, .back = 1, - .right = rect->x + rect->width, - .bottom = rect->y + rect->height, + .right = (rect->x + rect->width ) << dxgi->downsampleLevel, + .bottom = (rect->y + rect->height) << dxgi->downsampleLevel, }; ID3D11DeviceContext_CopySubresourceRegion(dxgi->deviceContext, - (ID3D11Resource *)dst, 0, rect->x, rect->y, 0, + (ID3D11Resource *)dst, 0, box.left, box.top, 0, (ID3D11Resource *)src, 0, &box); } } @@ -232,11 +222,10 @@ static bool d3d11_copyFrame(Texture * tex, ID3D11Texture2D * src) if (teximpl->gpu) { ID3D11DeviceContext_GenerateMips(dxgi->deviceContext, teximpl->srv); - if (tex->texDamageCount < 0) ID3D11DeviceContext_CopySubresourceRegion(dxgi->deviceContext, (ID3D11Resource *)teximpl->cpu, 0, 0, 0, 0, - (ID3D11Resource *)dst , 1, NULL); + (ID3D11Resource *)dst , dxgi->downsampleLevel, NULL); else { for (int i = 0; i < tex->texDamageCount; ++i) @@ -244,17 +233,17 @@ static bool d3d11_copyFrame(Texture * tex, ID3D11Texture2D * src) FrameDamageRect * rect = tex->texDamageRects + i; D3D11_BOX box = { - .left = rect->x / 2, - .top = rect->y / 2, + .left = rect->x, + .top = rect->y, .front = 0, .back = 1, - .right = (rect->x + rect->width ) / 2, - .bottom = (rect->y + rect->height) / 2, + .right = rect->x + rect->width , + .bottom = rect->y + rect->height, }; ID3D11DeviceContext_CopySubresourceRegion(dxgi->deviceContext, - (ID3D11Resource *)teximpl->cpu, 0, rect->x / 2, rect->y / 2, 0, - (ID3D11Resource *)dst , 1, &box); + (ID3D11Resource *)teximpl->cpu, 0, box.left, box.top, 0, + (ID3D11Resource *)dst , dxgi->downsampleLevel, &box); } } } diff --git a/host/platform/Windows/capture/DXGI/src/dxgi.c b/host/platform/Windows/capture/DXGI/src/dxgi.c index 274398bd..d5b25b04 100644 --- a/host/platform/Windows/capture/DXGI/src/dxgi.c +++ b/host/platform/Windows/capture/DXGI/src/dxgi.c @@ -29,6 +29,7 @@ #include "common/rects.h" #include "common/runningavg.h" #include "common/KVMFR.h" +#include "common/vector.h" #include #include @@ -45,6 +46,18 @@ #define LOCKED(...) INTERLOCKED_SECTION(this->deviceContextLock, __VA_ARGS__) +typedef struct +{ + unsigned int id; + bool greater; + unsigned int x; + unsigned int y; + unsigned int level; +} +DownsampleRule; + +static Vector downsampleRules = {0}; + // locals static struct DXGIInterface * this = NULL; @@ -73,6 +86,58 @@ static const char * dxgi_getName(void) return name; } +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:%u", &rule.x, &rule.y, &rule.level) != 3) + return false; + + rule.id = count++; + + DEBUG_INFO( + "Rule %u: %u%% IF X %s %4u %s Y %s %4u", + rule.id, + 100 / (1 << rule.level), + 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 dxgi_initOptions(void) { struct Option options[] = @@ -91,6 +156,14 @@ static void dxgi_initOptions(void) .type = OPTION_TYPE_STRING, .value.x_string = NULL }, + { + .module = "dxgi", + .name = "downsample", //dxgi:downsample=1920x1200:1, + .description = "Downsample conditions and levels, format: [>](width)x(height):level", + .type = OPTION_TYPE_STRING, + .value.x_string = NULL, + .parser = downsampleOptParser + }, { .module = "dxgi", .name = "maxTextures", @@ -390,16 +463,6 @@ static bool dxgi_init(void) break; } - this->targetWidth = this->width; - this->targetHeight = this->height; - - //TODO: add logic here - if (this->width > 1920 && this->height > 1200) - { - this->targetWidth /= 2; - this->targetHeight /= 2; - } - switch(outputDesc.Rotation) { case DXGI_MODE_ROTATION_ROTATE90: @@ -423,7 +486,6 @@ static bool dxgi_init(void) DEBUG_INFO("Feature Level : 0x%x" , this->featureLevel); DEBUG_INFO("Capture Size : %u x %u", this->width, this->height); - DEBUG_INFO("Target Size : %u x %u", this->targetWidth, this->targetHeight); DEBUG_INFO("AcquireLock : %s" , this->useAcquireLock ? "enabled" : "disabled"); DEBUG_INFO("Debug mode : %s" , this->debug ? "enabled" : "disabled"); @@ -536,6 +598,26 @@ static bool dxgi_init(void) goto fail; } + this->targetWidth = this->width; + this->targetHeight = this->height; + + DownsampleRule * rule; + 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))) + { + DEBUG_INFO("Matched downsample rule %d", rule->id); + this->downsampleLevel = rule->level; + this->targetWidth >>= rule->level; + this->targetHeight >>= rule->level; + break; + } + } + + DEBUG_INFO("Request Size : %u x %u", this->targetWidth, this->targetHeight); + const char * copyBackend = option_get_string("dxgi", "copyBackend"); for (int i = 0; i < ARRAY_LENGTH(backends); ++i) { @@ -552,6 +634,8 @@ static bool dxgi_init(void) } } + DEBUG_INFO("Output Size : %u x %u", this->targetWidth, this->targetHeight); + if (!this->backend) { DEBUG_ERROR("Could not find copy backend: %s", copyBackend); @@ -699,10 +783,10 @@ static void rectToFrameDamageRect(RECT * src, FrameDamageRect * dst) { *dst = (FrameDamageRect) { - .x = src->left, - .y = src->top, - .width = src->right - src->left, - .height = src->bottom - src->top + .x = src->left >> this->downsampleLevel, + .y = src->top >> this->downsampleLevel, + .width = (src->right - src->left) >> this->downsampleLevel, + .height = (src->bottom - src->top) >> this->downsampleLevel }; } diff --git a/host/platform/Windows/capture/DXGI/src/dxgi_capture.h b/host/platform/Windows/capture/DXGI/src/dxgi_capture.h index d2549d51..c25886df 100644 --- a/host/platform/Windows/capture/DXGI/src/dxgi_capture.h +++ b/host/platform/Windows/capture/DXGI/src/dxgi_capture.h @@ -95,6 +95,7 @@ struct DXGIInterface unsigned int formatVer; unsigned int width , targetWidth ; unsigned int height, targetHeight; + unsigned int downsampleLevel; unsigned int pitch; unsigned int stride; unsigned int bpp;