mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-12-25 23:13:39 +00:00
[host] dxgi: implement downsampling to arbitrary sizes
This commit is contained in:
parent
30c577beeb
commit
5f613b09d6
@ -9,6 +9,7 @@ add_library(capture_DXGI STATIC
|
||||
src/util.c
|
||||
src/com_ref.c
|
||||
|
||||
src/pp/downsample.c
|
||||
src/pp/sdrwhitelevel.c
|
||||
src/pp/rgb24.c
|
||||
)
|
||||
|
@ -20,7 +20,6 @@
|
||||
|
||||
#include "interface/capture.h"
|
||||
#include "interface/platform.h"
|
||||
#include "downsample_parser.h"
|
||||
#include "common/array.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/windebug.h"
|
||||
@ -32,6 +31,7 @@
|
||||
#include "common/KVMFR.h"
|
||||
#include "common/vector.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdatomic.h>
|
||||
#include <unistd.h>
|
||||
#include <dxgi.h>
|
||||
@ -51,9 +51,17 @@
|
||||
#define LOCKED(...) INTERLOCKED_SECTION(this->deviceContextLock, __VA_ARGS__)
|
||||
|
||||
//post processers
|
||||
extern const DXGIPostProcess DXGIPP_Downsample;
|
||||
extern const DXGIPostProcess DXGIPP_SDRWhiteLevel;
|
||||
extern const DXGIPostProcess DXGIPP_RGB24;
|
||||
|
||||
const DXGIPostProcess * postProcessors[] =
|
||||
{
|
||||
&DXGIPP_Downsample,
|
||||
&DXGIPP_SDRWhiteLevel,
|
||||
&DXGIPP_RGB24
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ID3D11Texture2D * src;
|
||||
@ -81,6 +89,7 @@ static struct DXGICopyBackend * backends[] = {
|
||||
static bool dxgi_deinit(void);
|
||||
static CaptureResult dxgi_releaseFrame(void);
|
||||
|
||||
static void ppEarlyInit(void);
|
||||
static bool ppInit(const DXGIPostProcess * pp, bool shareable);
|
||||
static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src,
|
||||
int * width, int * height,
|
||||
@ -119,7 +128,6 @@ static void dxgi_initOptions(void)
|
||||
.type = OPTION_TYPE_STRING,
|
||||
.value.x_string = NULL
|
||||
},
|
||||
DOWNSAMPLE_PARSER("dxgi"),
|
||||
{
|
||||
.module = "dxgi",
|
||||
.name = "maxTextures",
|
||||
@ -173,6 +181,7 @@ static void dxgi_initOptions(void)
|
||||
};
|
||||
|
||||
option_register(options);
|
||||
ppEarlyInit();
|
||||
}
|
||||
|
||||
static bool dxgi_create(CaptureGetPointerBuffer getPointerBufferFn, CapturePostPointerBuffer postPointerBufferFn)
|
||||
@ -693,14 +702,6 @@ static bool dxgi_init(void)
|
||||
|
||||
this->outputWidth = this->width;
|
||||
this->outputHeight = this->height;
|
||||
DownsampleRule * rule = downsampleRule_match(this->width, this->height);
|
||||
if (rule)
|
||||
{
|
||||
this->outputWidth = rule->targetX;
|
||||
this->outputHeight = rule->targetY;
|
||||
}
|
||||
|
||||
DEBUG_INFO("Request Size : %u x %u", this->outputWidth, this->outputHeight);
|
||||
|
||||
const char * copyBackend = option_get_string("dxgi", "copyBackend");
|
||||
for (int i = 0; i < ARRAY_LENGTH(backends); ++i)
|
||||
@ -738,6 +739,13 @@ static bool dxgi_init(void)
|
||||
if (!initVertexShader())
|
||||
goto fail;
|
||||
|
||||
if (!ppInit(&DXGIPP_Downsample,
|
||||
this->backend != ©BackendD3D11 && !this->hdr))
|
||||
{
|
||||
DEBUG_ERROR("Failed to intiailize the downsample post processor");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// if HDR add the SDRWhiteLevel post processor to correct the output
|
||||
if (this->hdr)
|
||||
{
|
||||
@ -856,10 +864,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 = floor((double)src->left * this->scaleX),
|
||||
.y = floor((double)src->top * this->scaleY),
|
||||
.width = ceil ((double)(src->right - src->left) * this->scaleX),
|
||||
.height = ceil ((double)(src->bottom - src->top) * this->scaleY)
|
||||
};
|
||||
}
|
||||
|
||||
@ -917,10 +925,12 @@ static void computeFrameDamage(Texture * tex)
|
||||
|
||||
*texDamageRect++ = (FrameDamageRect)
|
||||
{
|
||||
.x = moveRect->SourcePoint.x,
|
||||
.y = moveRect->SourcePoint.y,
|
||||
.width = moveRect->DestinationRect.right - moveRect->DestinationRect.left,
|
||||
.height = moveRect->DestinationRect.bottom - moveRect->DestinationRect.top
|
||||
.x = floor((double)moveRect->SourcePoint.x * this->scaleX),
|
||||
.y = floor((double)moveRect->SourcePoint.y * this->scaleY),
|
||||
.width = ceil((double)(moveRect->DestinationRect.right -
|
||||
moveRect->DestinationRect.left) * this->scaleX),
|
||||
.height = ceil((double)(moveRect->DestinationRect.bottom -
|
||||
moveRect->DestinationRect.top ) * this->scaleY)
|
||||
};
|
||||
|
||||
rectToFrameDamageRect(&moveRect->DestinationRect, texDamageRect++);
|
||||
@ -1038,14 +1048,6 @@ static CaptureResult dxgi_capture(void)
|
||||
{
|
||||
if (copyFrame)
|
||||
{
|
||||
if (this->useAcquireLock)
|
||||
{
|
||||
LOCKED({ computeFrameDamage(tex); });
|
||||
}
|
||||
else
|
||||
computeFrameDamage(tex);
|
||||
computeTexDamage(tex);
|
||||
|
||||
// run any postprocessors
|
||||
int width = this->width;
|
||||
int height = this->height;
|
||||
@ -1114,8 +1116,20 @@ static CaptureResult dxgi_capture(void)
|
||||
this->dataHeight = rows;
|
||||
this->pitch = pitch;
|
||||
this->stride = pitch / this->bpp;
|
||||
|
||||
this->scaleX = (double)width / this->width;
|
||||
this->scaleY = (double)height / this->height;
|
||||
}
|
||||
|
||||
// compute the frame damage
|
||||
if (this->useAcquireLock)
|
||||
{
|
||||
LOCKED({ computeFrameDamage(tex); });
|
||||
}
|
||||
else
|
||||
computeFrameDamage(tex);
|
||||
computeTexDamage(tex);
|
||||
|
||||
if (!this->backend->copyFrame(tex, dst))
|
||||
{
|
||||
result = CAPTURE_RESULT_ERROR;
|
||||
@ -1380,6 +1394,13 @@ static CaptureResult dxgi_releaseFrame(void)
|
||||
return CAPTURE_RESULT_OK;
|
||||
}
|
||||
|
||||
static void ppEarlyInit(void)
|
||||
{
|
||||
for(int i = 0; i < ARRAY_LENGTH(postProcessors); ++i)
|
||||
if (postProcessors[i]->earlyInit)
|
||||
postProcessors[i]->earlyInit();
|
||||
}
|
||||
|
||||
static bool ppInit(const DXGIPostProcess * pp, bool shareable)
|
||||
{
|
||||
if (!pp->setup(this->device, this->deviceContext, this->output, shareable))
|
||||
@ -1448,7 +1469,7 @@ static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src,
|
||||
format))
|
||||
{
|
||||
LG_UNLOCK(this->deviceContextLock);
|
||||
DEBUG_ERROR("setFormat failed on a post processor");
|
||||
DEBUG_ERROR("setFormat failed on a post processor (%s)", inst->pp->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1476,15 +1497,8 @@ static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src,
|
||||
// run the post processor
|
||||
ID3D11Texture2D * out = inst->pp->run(inst->opaque, inst->srv);
|
||||
|
||||
// if the post processor failed
|
||||
// if the post processor does nothing, just continue
|
||||
if (!out)
|
||||
{
|
||||
LG_UNLOCK(this->deviceContextLock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if the post processor did nothing, just continue
|
||||
if (out == src)
|
||||
{
|
||||
LG_UNLOCK(this->deviceContextLock);
|
||||
continue;
|
||||
@ -1495,6 +1509,11 @@ static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src,
|
||||
*this->deviceContext, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
ID3D11DeviceContext_Draw(*this->deviceContext, 4, 0);
|
||||
|
||||
// unset the target render view
|
||||
static ID3D11RenderTargetView * nullTarget = NULL;
|
||||
ID3D11DeviceContext_OMSetRenderTargets(
|
||||
*this->deviceContext, 1, &nullTarget, NULL);
|
||||
|
||||
// the output is now the input
|
||||
src = out;
|
||||
LG_UNLOCK(this->deviceContextLock);
|
||||
|
@ -48,7 +48,7 @@ typedef struct Texture
|
||||
uint64_t copyTime;
|
||||
uint32_t damageRectsCount;
|
||||
FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
int32_t texDamageCount;
|
||||
int texDamageCount;
|
||||
FrameDamageRect texDamageRects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
|
||||
// post processing
|
||||
@ -109,6 +109,7 @@ struct DXGIInterface
|
||||
unsigned int stride;
|
||||
unsigned int padding;
|
||||
unsigned int bpp;
|
||||
double scaleX, scaleY;
|
||||
CaptureFormat format, outputFormat;
|
||||
CaptureRotation rotation;
|
||||
|
||||
|
271
host/platform/Windows/capture/DXGI/src/pp/downsample.c
Normal file
271
host/platform/Windows/capture/DXGI/src/pp/downsample.c
Normal file
@ -0,0 +1,271 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "pp.h"
|
||||
#include "com_ref.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "downsample_parser.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/windebug.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
typedef struct Downsample
|
||||
{
|
||||
ID3D11Device ** device;
|
||||
ID3D11DeviceContext ** context;
|
||||
bool shareable;
|
||||
|
||||
bool disabled;
|
||||
int width , height;
|
||||
ID3D11SamplerState ** sampler;
|
||||
ID3D11PixelShader ** pshader;
|
||||
}
|
||||
Downsample;
|
||||
static Downsample this = {0};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ID3D11Texture2D ** tex;
|
||||
ID3D11RenderTargetView ** target;
|
||||
}
|
||||
DownsampleInst;
|
||||
|
||||
|
||||
static void downsample_earlyInit(void)
|
||||
{
|
||||
struct Option options[] =
|
||||
{
|
||||
DOWNSAMPLE_PARSER("dxgi"),
|
||||
{0}
|
||||
};
|
||||
|
||||
option_register(options);
|
||||
}
|
||||
|
||||
static bool downsample_setup(
|
||||
ID3D11Device ** device,
|
||||
ID3D11DeviceContext ** context,
|
||||
IDXGIOutput ** output,
|
||||
bool shareable
|
||||
)
|
||||
{
|
||||
this.device = device;
|
||||
this.context = context;
|
||||
this.shareable = shareable;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void downsample_finish(void)
|
||||
{
|
||||
memset(&this, 0, sizeof(this));
|
||||
}
|
||||
|
||||
static bool downsample_configure(void * opaque,
|
||||
int * width, int * height,
|
||||
int * cols , int * rows ,
|
||||
CaptureFormat * format)
|
||||
{
|
||||
DownsampleInst * inst = (DownsampleInst *)opaque;
|
||||
if (*format == CAPTURE_FMT_BGR)
|
||||
this.disabled = true;
|
||||
|
||||
if (this.disabled)
|
||||
return true;
|
||||
|
||||
HRESULT status;
|
||||
comRef_scopePush();
|
||||
|
||||
if (!this.pshader)
|
||||
{
|
||||
DownsampleRule * rule = downsampleRule_match(*width, *height);
|
||||
if (!rule || (rule->targetX == *width && rule->targetY == *height))
|
||||
{
|
||||
this.disabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
this.width = rule->targetX;
|
||||
this.height = rule->targetY;
|
||||
|
||||
DEBUG_INFO("Downsampling to: %u x %u", this.width, this.height);
|
||||
|
||||
static const char * pshaderSrc =
|
||||
"Texture2D gInputTexture : register(t0);\n"
|
||||
"SamplerState gSamplerState : register(s0);\n"
|
||||
"\n"
|
||||
"float4 main(\n"
|
||||
" float4 position : SV_POSITION,\n"
|
||||
" float2 texCoord : TEXCOORD0) : SV_TARGET"
|
||||
"{\n"
|
||||
" return gInputTexture.Sample(gSamplerState, texCoord);\n"
|
||||
"}\n";
|
||||
|
||||
comRef_defineLocal(ID3DBlob, byteCode);
|
||||
if (!compileShader(byteCode, "main", "ps_5_0", pshaderSrc, NULL))
|
||||
goto fail;
|
||||
|
||||
comRef_defineLocal(ID3D11PixelShader, pshader);
|
||||
HRESULT status = ID3D11Device_CreatePixelShader(
|
||||
*this.device,
|
||||
ID3D10Blob_GetBufferPointer(*byteCode),
|
||||
ID3D10Blob_GetBufferSize (*byteCode),
|
||||
NULL,
|
||||
pshader);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the pixel shader", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const D3D11_SAMPLER_DESC samplerDesc =
|
||||
{
|
||||
.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR,
|
||||
.AddressU = D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
.AddressV = D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
.AddressW = D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
.ComparisonFunc = D3D11_COMPARISON_NEVER,
|
||||
.MinLOD = 0,
|
||||
.MaxLOD = D3D11_FLOAT32_MAX
|
||||
};
|
||||
|
||||
comRef_defineLocal(ID3D11SamplerState, sampler);
|
||||
status = ID3D11Device_CreateSamplerState(*this.device, &samplerDesc, sampler);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the sampler state", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
comRef_toGlobal(this.pshader, pshader);
|
||||
comRef_toGlobal(this.sampler, sampler);
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC texDesc =
|
||||
{
|
||||
.Width = this.width,
|
||||
.Height = this.height,
|
||||
.MipLevels = 1,
|
||||
.ArraySize = 1,
|
||||
.SampleDesc.Count = 1,
|
||||
.SampleDesc.Quality = 0,
|
||||
.Usage = D3D11_USAGE_DEFAULT,
|
||||
.Format = DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
.BindFlags = D3D11_BIND_RENDER_TARGET |
|
||||
D3D11_BIND_SHADER_RESOURCE,
|
||||
.CPUAccessFlags = 0,
|
||||
.MiscFlags = 0
|
||||
};
|
||||
|
||||
// allow texture sharing with other backends
|
||||
if (this.shareable)
|
||||
texDesc.MiscFlags |=
|
||||
D3D11_RESOURCE_MISC_SHARED |
|
||||
D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
|
||||
|
||||
comRef_defineLocal(ID3D11Texture2D, tex);
|
||||
status = ID3D11Device_CreateTexture2D(
|
||||
*this.device, &texDesc, NULL, tex);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the output texture", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
comRef_defineLocal(ID3D11RenderTargetView, target);
|
||||
status = ID3D11Device_CreateRenderTargetView(
|
||||
*this.device, *(ID3D11Resource **)tex, NULL, target);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the render target view", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*width = *cols = this.width;
|
||||
*height = *rows = this.height;
|
||||
|
||||
comRef_toGlobal(inst->tex , tex );
|
||||
comRef_toGlobal(inst->target , target );
|
||||
|
||||
comRef_scopePop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
comRef_scopePop();
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool downsample_init(void ** opaque)
|
||||
{
|
||||
DownsampleInst * inst = (DownsampleInst *)calloc(1, sizeof(*inst));
|
||||
if (!inst)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
*opaque = inst;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void downsample_free(void * opaque)
|
||||
{
|
||||
DownsampleInst * inst = (DownsampleInst *)opaque;
|
||||
comRef_release(inst->target);
|
||||
comRef_release(inst->tex );
|
||||
free(inst);
|
||||
}
|
||||
|
||||
static ID3D11Texture2D * downsample_run(void * opaque,
|
||||
ID3D11ShaderResourceView * srv)
|
||||
{
|
||||
if (this.disabled)
|
||||
return NULL;
|
||||
|
||||
DownsampleInst * inst = (DownsampleInst *)opaque;
|
||||
|
||||
// set the pixel shader & resources
|
||||
ID3D11DeviceContext_PSSetShader(*this.context, *this.pshader, NULL, 0);
|
||||
ID3D11DeviceContext_PSSetSamplers (*this.context, 0, 1, this.sampler);
|
||||
ID3D11DeviceContext_PSSetShaderResources(*this.context, 0, 1, &srv);
|
||||
|
||||
// set the render target
|
||||
ID3D11DeviceContext_OMSetRenderTargets(*this.context, 1, inst->target, NULL);
|
||||
|
||||
return *inst->tex;
|
||||
}
|
||||
|
||||
DXGIPostProcess DXGIPP_Downsample =
|
||||
{
|
||||
.name = "Downsample",
|
||||
.earlyInit = downsample_earlyInit,
|
||||
.setup = downsample_setup,
|
||||
.init = downsample_init,
|
||||
.free = downsample_free,
|
||||
.configure = downsample_configure,
|
||||
.run = downsample_run,
|
||||
.finish = downsample_finish
|
||||
};
|
Loading…
Reference in New Issue
Block a user