mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-12-22 21:43:40 +00:00
[host] dxgi: seperate out and implement a post processor chain
This commit is contained in:
parent
e225f66cee
commit
21cd380cad
@ -8,6 +8,8 @@ add_library(capture_DXGI STATIC
|
||||
src/ods_capture.c
|
||||
src/util.c
|
||||
src/com_ref.c
|
||||
|
||||
src/pp/sdrwhitelevel.c
|
||||
)
|
||||
|
||||
add_definitions("-DCOBJMACROS -DINITGUID")
|
||||
|
@ -49,6 +49,16 @@
|
||||
|
||||
#define LOCKED(...) INTERLOCKED_SECTION(this->deviceContextLock, __VA_ARGS__)
|
||||
|
||||
//post processers
|
||||
extern const DXGIPostProcess DXGIPP_SDRWhiteLevel;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const DXGIPostProcess * pp;
|
||||
void * opaque;
|
||||
}
|
||||
PostProcessInstance;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int id;
|
||||
@ -61,12 +71,6 @@ DownsampleRule;
|
||||
|
||||
static Vector downsampleRules = {0};
|
||||
|
||||
struct ShaderConsts
|
||||
{
|
||||
float sdrWhiteLevel;
|
||||
}
|
||||
__attribute__((aligned(16)));
|
||||
|
||||
// locals
|
||||
static struct DXGIInterface * this = NULL;
|
||||
|
||||
@ -82,6 +86,10 @@ static struct DXGICopyBackend * backends[] = {
|
||||
static bool dxgi_deinit(void);
|
||||
static CaptureResult dxgi_releaseFrame(void);
|
||||
|
||||
static bool ppInit(const DXGIPostProcess * pp, bool shareable);
|
||||
static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src);
|
||||
static void ppFreeAll(void);
|
||||
|
||||
// implementation
|
||||
|
||||
static const char * dxgi_getName(void)
|
||||
@ -626,18 +634,10 @@ static bool dxgi_init(void)
|
||||
IDXGIOutput6_GetDesc1(*output6, &desc1);
|
||||
this->dxgiColorSpace = desc1.ColorSpace;
|
||||
|
||||
if (!getDisplayPathInfo(desc1.Monitor, &this->displayPathInfo))
|
||||
{
|
||||
DEBUG_ERROR("Failed to get the display path info");
|
||||
goto fail;
|
||||
}
|
||||
this->sdrWhiteLevel = getSDRWhiteLevel(&this->displayPathInfo);
|
||||
|
||||
DEBUG_INFO("Bits Per Color : %u" , desc1.BitsPerColor);
|
||||
DEBUG_INFO("Color Space : %s" , getDXGIColorSpaceTypeStr(this->dxgiColorSpace));
|
||||
DEBUG_INFO("Min/Max Luminance : %f/%f", desc1.MinLuminance, desc1.MaxLuminance);
|
||||
DEBUG_INFO("Frame Luminance : %f" , desc1.MaxFullFrameLuminance);
|
||||
DEBUG_INFO("SDR White Level : %f" , this->sdrWhiteLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@ -753,185 +753,26 @@ static bool dxgi_init(void)
|
||||
for (int i = 0; i < this->maxTextures; ++i)
|
||||
{
|
||||
this->texture[i].texDamageCount = -1;
|
||||
if (!this->hdr)
|
||||
continue;
|
||||
|
||||
D3D11_TEXTURE2D_DESC hdrTexDesc =
|
||||
{
|
||||
.Width = this->width,
|
||||
.Height = this->height,
|
||||
.MipLevels = 1,
|
||||
.ArraySize = 1,
|
||||
.SampleDesc.Count = 1,
|
||||
.SampleDesc.Quality = 0,
|
||||
.Usage = D3D11_USAGE_DEFAULT,
|
||||
.Format = DXGI_FORMAT_R10G10B10A2_UNORM,
|
||||
.BindFlags = D3D11_BIND_RENDER_TARGET |
|
||||
D3D11_BIND_SHADER_RESOURCE,
|
||||
.CPUAccessFlags = 0,
|
||||
.MiscFlags = 0
|
||||
};
|
||||
|
||||
// allow texture sharing with other backends
|
||||
if (this->backend != ©BackendD3D11)
|
||||
hdrTexDesc.MiscFlags |=
|
||||
D3D11_RESOURCE_MISC_SHARED |
|
||||
D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
|
||||
|
||||
status = ID3D11Device_CreateTexture2D(*this->device, &hdrTexDesc, NULL,
|
||||
(ID3D11Texture2D **)comRef_newGlobal(&this->texture[i].hdrTex));
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create HDR texture", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = ID3D11Device_CreateRenderTargetView(*this->device,
|
||||
(ID3D11Resource *)*this->texture[i].hdrTex, NULL,
|
||||
(ID3D11RenderTargetView **)comRef_newGlobal(
|
||||
&this->texture[i].renderTarget));
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create HDR target view", status);
|
||||
goto fail;
|
||||
}
|
||||
vector_create(&this->texture[i].pp, sizeof(PostProcessInstance), 0);
|
||||
}
|
||||
|
||||
if (this->hdr)
|
||||
const D3D11_VIEWPORT vp =
|
||||
{
|
||||
const D3D11_VIEWPORT vp =
|
||||
{
|
||||
.TopLeftX = 0.0f,
|
||||
.TopLeftY = 0.0f,
|
||||
.Width = this->width,
|
||||
.Height = this->height,
|
||||
.MinDepth = 0.0f,
|
||||
.MaxDepth = 1.0f,
|
||||
};
|
||||
ID3D11DeviceContext_RSSetViewports(*this->deviceContext, 1, &vp);
|
||||
.TopLeftX = 0.0f,
|
||||
.TopLeftY = 0.0f,
|
||||
.Width = this->width,
|
||||
.Height = this->height,
|
||||
.MinDepth = 0.0f,
|
||||
.MaxDepth = 1.0f,
|
||||
};
|
||||
ID3D11DeviceContext_RSSetViewports(*this->deviceContext, 1, &vp);
|
||||
|
||||
static const char * vshader =
|
||||
"void main(\n"
|
||||
" in uint vertexID : SV_VERTEXID,\n"
|
||||
" out float4 position : SV_POSITION,\n"
|
||||
" out float2 texCoord : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" float2 positions[4] =\n"
|
||||
" {\n"
|
||||
" float2(-1.0, 1.0),\n"
|
||||
" float2( 1.0, 1.0),\n"
|
||||
" float2(-1.0, -1.0),\n"
|
||||
" float2( 1.0, -1.0)\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" float2 texCoords[4] =\n"
|
||||
" {\n"
|
||||
" float2(0.0, 0.0),\n"
|
||||
" float2(1.0, 0.0),\n"
|
||||
" float2(0.0, 1.0),\n"
|
||||
" float2(1.0, 1.0)\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" position = float4(positions[vertexID], 0.0, 1.0);\n"
|
||||
" texCoord = texCoords[vertexID];\n"
|
||||
"}";
|
||||
|
||||
static const char * pshader =
|
||||
"Texture2D gInputTexture : register(t0);\n"
|
||||
"SamplerState gSamplerState : register(s0);\n"
|
||||
"cbuffer gConsts : register(b0)\n"
|
||||
"{\n"
|
||||
" float SDRWhiteLevel;"
|
||||
"};\n"
|
||||
"\n"
|
||||
"float4 main(\n"
|
||||
" float4 position : SV_POSITION,\n"
|
||||
" float2 texCoord : TEXCOORD0) : SV_TARGET"
|
||||
"{\n"
|
||||
" float4 color = gInputTexture.Sample(gSamplerState, texCoord);\n"
|
||||
" color.rgb *= SDRWhiteLevel;\n"
|
||||
" return color;\n"
|
||||
"}\n";
|
||||
|
||||
comRef_defineLocal(ID3DBlob, byteCode);
|
||||
if (!compileShader(byteCode, "main", "vs_5_0", vshader))
|
||||
goto fail;
|
||||
|
||||
status = ID3D11Device_CreateVertexShader(
|
||||
*this->device,
|
||||
ID3D10Blob_GetBufferPointer(*byteCode),
|
||||
ID3D10Blob_GetBufferSize (*byteCode),
|
||||
NULL,
|
||||
(ID3D11VertexShader **)comRef_newGlobal(&this->vertexShader));
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the vertex shader", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
comRef_release(byteCode);
|
||||
if (!compileShader(byteCode, "main", "ps_5_0", pshader))
|
||||
goto fail;
|
||||
|
||||
status = ID3D11Device_CreatePixelShader(
|
||||
*this->device,
|
||||
ID3D10Blob_GetBufferPointer(*byteCode),
|
||||
ID3D10Blob_GetBufferSize (*byteCode),
|
||||
NULL,
|
||||
(ID3D11PixelShader **)comRef_newGlobal(&this->pixelShader));
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
status = ID3D11Device_CreateSamplerState(
|
||||
*this->device, &samplerDesc,
|
||||
(ID3D11SamplerState **)comRef_newGlobal(&this->samplerState));
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the sampler state", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
struct ShaderConsts consts =
|
||||
{
|
||||
.sdrWhiteLevel = 80.0f / this->sdrWhiteLevel
|
||||
};
|
||||
|
||||
D3D11_BUFFER_DESC bufferDesc =
|
||||
{
|
||||
.ByteWidth = sizeof(consts),
|
||||
.Usage = D3D11_USAGE_DEFAULT,
|
||||
.BindFlags = D3D11_BIND_CONSTANT_BUFFER,
|
||||
};
|
||||
|
||||
D3D11_SUBRESOURCE_DATA initData = { .pSysMem = &consts };
|
||||
status = ID3D11Device_CreateBuffer(
|
||||
*this->device, &bufferDesc, &initData,
|
||||
(ID3D11Buffer **)comRef_newGlobal(&this->constBuffer));
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the constant buffer", status);
|
||||
goto fail;
|
||||
}
|
||||
// if HDR add the SDRWhiteLevel post processor to correct the output
|
||||
if (this->hdr && !ppInit(&DXGIPP_SDRWhiteLevel,
|
||||
this->backend != ©BackendD3D11))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the SDRWhiteLevel post processor");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
|
||||
@ -961,19 +802,20 @@ static bool dxgi_deinit(void)
|
||||
|
||||
for (int i = 0; i < this->maxTextures; ++i)
|
||||
{
|
||||
if (this->texture[i].map)
|
||||
{
|
||||
this->backend->unmapTexture(this->texture + i);
|
||||
this->texture[i].map = NULL;
|
||||
}
|
||||
Texture * tex = &this->texture[i];
|
||||
if (!tex->map)
|
||||
continue;
|
||||
this->backend->unmapTexture(tex);
|
||||
tex->map = NULL;
|
||||
}
|
||||
|
||||
if (this->dup && *this->dup)
|
||||
dxgi_releaseFrame();
|
||||
|
||||
// this MUST run before backend->free().
|
||||
// this MUST run before backend->free() & ppFreeAll.
|
||||
comRef_free();
|
||||
|
||||
ppFreeAll();
|
||||
if (this->backend)
|
||||
{
|
||||
this->backend->free();
|
||||
@ -1223,76 +1065,14 @@ static CaptureResult dxgi_capture(void)
|
||||
computeFrameDamage(tex);
|
||||
computeTexDamage(tex);
|
||||
|
||||
if (this->hdr)
|
||||
{
|
||||
// setup the pixel shader input resource view
|
||||
comRef_defineLocal(ID3D11ShaderResourceView, inputSRV);
|
||||
{
|
||||
const D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc =
|
||||
{
|
||||
.Format = this->dxgiSrcFormat,
|
||||
.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D,
|
||||
.Texture2D.MipLevels = 1
|
||||
};
|
||||
status = ID3D11Device_CreateShaderResourceView(
|
||||
*this->device, (ID3D11Resource *)*src, &srvDesc, inputSRV);
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the source resource view", status);
|
||||
result = CAPTURE_RESULT_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
float nits = getSDRWhiteLevel(&this->displayPathInfo);
|
||||
if (nits != this->sdrWhiteLevel)
|
||||
{
|
||||
this->sdrWhiteLevel = nits;
|
||||
|
||||
struct ShaderConsts consts =
|
||||
{
|
||||
.sdrWhiteLevel = 80.0f / nits
|
||||
};
|
||||
|
||||
ID3D11DeviceContext_UpdateSubresource(
|
||||
*this->deviceContext, (ID3D11Resource*)*this->constBuffer,
|
||||
0, NULL, &consts, 0, 0);
|
||||
}
|
||||
|
||||
ID3D11DeviceContext_VSSetShader(
|
||||
*this->deviceContext, *this->vertexShader, NULL, 0);
|
||||
|
||||
ID3D11DeviceContext_PSSetShader(
|
||||
*this->deviceContext, *this->pixelShader, NULL, 0);
|
||||
ID3D11DeviceContext_PSSetShaderResources(
|
||||
*this->deviceContext, 0, 1, inputSRV);
|
||||
ID3D11DeviceContext_PSSetSamplers(
|
||||
*this->deviceContext, 0, 1, this->samplerState);
|
||||
ID3D11DeviceContext_PSSetConstantBuffers(
|
||||
*this->deviceContext, 0, 1, this->constBuffer);
|
||||
|
||||
ID3D11DeviceContext_OMSetRenderTargets(
|
||||
*this->deviceContext, 1, tex->renderTarget, NULL);
|
||||
|
||||
ID3D11DeviceContext_IASetPrimitiveTopology(
|
||||
*this->deviceContext, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
|
||||
ID3D11DeviceContext_Draw(*this->deviceContext, 4, 0);
|
||||
ID3D11Texture2D * dst = ppRun(tex, *src);
|
||||
if (dst != *src)
|
||||
ID3D11DeviceContext_Flush(*this->deviceContext);
|
||||
|
||||
if (!this->backend->copyFrame(tex, *tex->hdrTex))
|
||||
{
|
||||
result = CAPTURE_RESULT_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!this->backend->copyFrame(tex, dst))
|
||||
{
|
||||
if (!this->backend->copyFrame(tex, *src))
|
||||
{
|
||||
result = CAPTURE_RESULT_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
result = CAPTURE_RESULT_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (int i = 0; i < this->maxTextures; ++i)
|
||||
@ -1535,6 +1315,51 @@ static CaptureResult dxgi_releaseFrame(void)
|
||||
return CAPTURE_RESULT_OK;
|
||||
}
|
||||
|
||||
static bool ppInit(const DXGIPostProcess * pp, bool shareable)
|
||||
{
|
||||
if (!pp->setup(this->device, this->deviceContext, this->output))
|
||||
return false;
|
||||
|
||||
for(int i = 0; i < this->maxTextures; ++i)
|
||||
{
|
||||
PostProcessInstance inst = { .pp = pp };
|
||||
if (!pp->init(&inst.opaque, this->width, this->height, shareable))
|
||||
return false;
|
||||
|
||||
vector_push(&this->texture[i].pp, &inst);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src)
|
||||
{
|
||||
PostProcessInstance * inst;
|
||||
vector_forEachRef(inst, &tex->pp)
|
||||
src = inst->pp->run(inst->opaque, src);
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
static void ppFreeAll(void)
|
||||
{
|
||||
for(int i = 0; i < this->maxTextures; ++i)
|
||||
{
|
||||
Texture * tex = &this->texture[i];
|
||||
if (!tex->pp.data)
|
||||
continue;
|
||||
|
||||
PostProcessInstance * inst;
|
||||
vector_forEachRef(inst, &tex->pp)
|
||||
{
|
||||
inst->pp->free(inst->opaque);
|
||||
if (i == this->maxTextures - 1)
|
||||
inst->pp->finish();
|
||||
}
|
||||
vector_destroy(&tex->pp);
|
||||
}
|
||||
}
|
||||
|
||||
struct CaptureInterface Capture_DXGI =
|
||||
{
|
||||
.shortName = "DXGI",
|
||||
|
@ -18,6 +18,8 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "pp.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <dxgi.h>
|
||||
#include <dxgi1_2.h>
|
||||
@ -28,6 +30,7 @@
|
||||
#include "common/event.h"
|
||||
#include "common/locking.h"
|
||||
#include "common/types.h"
|
||||
#include "common/vector.h"
|
||||
#include "interface/capture.h"
|
||||
|
||||
enum TextureState
|
||||
@ -47,8 +50,9 @@ typedef struct Texture
|
||||
FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
int32_t texDamageCount;
|
||||
FrameDamageRect texDamageRects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
ID3D11RenderTargetView ** renderTarget;
|
||||
ID3D11Texture2D ** hdrTex;
|
||||
|
||||
// post processing
|
||||
Vector pp;
|
||||
|
||||
void * impl;
|
||||
}
|
||||
@ -89,13 +93,7 @@ struct DXGIInterface
|
||||
bool needsRelease;
|
||||
DXGI_FORMAT dxgiSrcFormat, dxgiFormat;
|
||||
bool hdr;
|
||||
DISPLAYCONFIG_PATH_INFO displayPathInfo;
|
||||
DXGI_COLOR_SPACE_TYPE dxgiColorSpace;
|
||||
float sdrWhiteLevel;
|
||||
ID3D11Buffer ** constBuffer;
|
||||
ID3D11PixelShader ** pixelShader;
|
||||
ID3D11VertexShader ** vertexShader;
|
||||
ID3D11SamplerState ** samplerState;
|
||||
struct DXGICopyBackend * backend;
|
||||
|
||||
CaptureGetPointerBuffer getPointerBufferFn;
|
||||
|
54
host/platform/Windows/capture/DXGI/src/pp.h
Normal file
54
host/platform/Windows/capture/DXGI/src/pp.h
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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 <d3d11.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* the friendly name of the processor for debugging */
|
||||
const char * name;
|
||||
|
||||
/* early initialization for registering options */
|
||||
void (*earlyInit)(void);
|
||||
|
||||
/* common setup */
|
||||
bool (*setup)(
|
||||
ID3D11Device ** device,
|
||||
ID3D11DeviceContext ** context,
|
||||
IDXGIOutput ** output);
|
||||
|
||||
/* instance initialization */
|
||||
bool (*init)(
|
||||
void ** opaque,
|
||||
int width,
|
||||
int height,
|
||||
bool shareable);
|
||||
|
||||
/* perform the processing */
|
||||
ID3D11Texture2D * (*run)(void * opaque, ID3D11Texture2D * src);
|
||||
|
||||
/* instance destruction */
|
||||
void (*free)(void * opaque);
|
||||
|
||||
/* cleanup */
|
||||
void (*finish)(void);
|
||||
}
|
||||
DXGIPostProcess;
|
377
host/platform/Windows/capture/DXGI/src/pp/sdrwhitelevel.c
Normal file
377
host/platform/Windows/capture/DXGI/src/pp/sdrwhitelevel.c
Normal file
@ -0,0 +1,377 @@
|
||||
/**
|
||||
* 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 "common/debug.h"
|
||||
#include "common/windebug.h"
|
||||
|
||||
#include <dxgi1_6.h>
|
||||
|
||||
typedef struct SDRWhiteLevel
|
||||
{
|
||||
ID3D11Device ** device;
|
||||
ID3D11DeviceContext ** context;
|
||||
|
||||
ID3D11VertexShader ** vshader;
|
||||
ID3D11PixelShader ** pshader;
|
||||
ID3D11SamplerState ** sampler;
|
||||
ID3D11Buffer ** buffer;
|
||||
|
||||
DISPLAYCONFIG_PATH_INFO displayPathInfo;
|
||||
float sdrWhiteLevel;
|
||||
}
|
||||
SDRWhiteLevel;
|
||||
SDRWhiteLevel this = {0};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ID3D11Texture2D ** tex;
|
||||
ID3D11RenderTargetView ** target;
|
||||
}
|
||||
SDRWhiteLevelInst;
|
||||
|
||||
struct ShaderConsts
|
||||
{
|
||||
float sdrWhiteLevel;
|
||||
}
|
||||
__attribute__((aligned(16)));
|
||||
|
||||
static const char * vshader =
|
||||
"void main(\n"
|
||||
" in uint vertexID : SV_VERTEXID,\n"
|
||||
" out float4 position : SV_POSITION,\n"
|
||||
" out float2 texCoord : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" float2 positions[4] =\n"
|
||||
" {\n"
|
||||
" float2(-1.0, 1.0),\n"
|
||||
" float2( 1.0, 1.0),\n"
|
||||
" float2(-1.0, -1.0),\n"
|
||||
" float2( 1.0, -1.0)\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" float2 texCoords[4] =\n"
|
||||
" {\n"
|
||||
" float2(0.0, 0.0),\n"
|
||||
" float2(1.0, 0.0),\n"
|
||||
" float2(0.0, 1.0),\n"
|
||||
" float2(1.0, 1.0)\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" position = float4(positions[vertexID], 0.0, 1.0);\n"
|
||||
" texCoord = texCoords[vertexID];\n"
|
||||
"}";
|
||||
|
||||
static const char * pshader =
|
||||
"Texture2D gInputTexture : register(t0);\n"
|
||||
"SamplerState gSamplerState : register(s0);\n"
|
||||
"cbuffer gConsts : register(b0)\n"
|
||||
"{\n"
|
||||
" float SDRWhiteLevel;"
|
||||
"};\n"
|
||||
"\n"
|
||||
"float4 main(\n"
|
||||
" float4 position : SV_POSITION,\n"
|
||||
" float2 texCoord : TEXCOORD0) : SV_TARGET"
|
||||
"{\n"
|
||||
" float4 color = gInputTexture.Sample(gSamplerState, texCoord);\n"
|
||||
" color.rgb *= SDRWhiteLevel;\n"
|
||||
" return color;\n"
|
||||
"}\n";
|
||||
|
||||
static void updateConsts(void);
|
||||
|
||||
static bool sdrWhiteLevel_setup(
|
||||
ID3D11Device ** device,
|
||||
ID3D11DeviceContext ** context,
|
||||
IDXGIOutput ** output
|
||||
)
|
||||
{
|
||||
bool result = false;
|
||||
comRef_scopePush();
|
||||
HRESULT status;
|
||||
|
||||
this.device = device;
|
||||
this.context = context;
|
||||
|
||||
comRef_defineLocal(IDXGIOutput6, output6);
|
||||
status = IDXGIOutput_QueryInterface(
|
||||
*output, &IID_IDXGIOutput6, (void **)output6);
|
||||
|
||||
if (!SUCCEEDED(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to get the IDXGIOutput6 interface");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DXGI_OUTPUT_DESC1 desc1;
|
||||
IDXGIOutput6_GetDesc1(*output6, &desc1);
|
||||
if (!getDisplayPathInfo(desc1.Monitor, &this.displayPathInfo))
|
||||
{
|
||||
DEBUG_ERROR("Failed to get the display path info");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// compile and create the vertex shader
|
||||
comRef_defineLocal(ID3DBlob, byteCode);
|
||||
if (!compileShader(byteCode, "main", "vs_5_0", vshader))
|
||||
goto exit;
|
||||
|
||||
status = ID3D11Device_CreateVertexShader(
|
||||
*this.device,
|
||||
ID3D10Blob_GetBufferPointer(*byteCode),
|
||||
ID3D10Blob_GetBufferSize (*byteCode),
|
||||
NULL,
|
||||
(ID3D11VertexShader **)comRef_newGlobal(&this.vshader));
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the vertex shader", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
comRef_release(byteCode);
|
||||
if (!compileShader(byteCode, "main", "ps_5_0", pshader))
|
||||
goto exit;
|
||||
|
||||
status = ID3D11Device_CreatePixelShader(
|
||||
*this.device,
|
||||
ID3D10Blob_GetBufferPointer(*byteCode),
|
||||
ID3D10Blob_GetBufferSize (*byteCode),
|
||||
NULL,
|
||||
(ID3D11PixelShader **)comRef_newGlobal(&this.pshader));
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the pixel shader", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
status = ID3D11Device_CreateSamplerState(
|
||||
*this.device, &samplerDesc,
|
||||
(ID3D11SamplerState **)comRef_newGlobal(&this.sampler));
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the sampler state", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
D3D11_BUFFER_DESC bufferDesc =
|
||||
{
|
||||
.ByteWidth = sizeof(struct ShaderConsts),
|
||||
.Usage = D3D11_USAGE_DEFAULT,
|
||||
.BindFlags = D3D11_BIND_CONSTANT_BUFFER,
|
||||
};
|
||||
|
||||
status = ID3D11Device_CreateBuffer(
|
||||
*this.device, &bufferDesc, NULL,
|
||||
(ID3D11Buffer **)comRef_newGlobal(&this.buffer));
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the constant buffer", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
updateConsts();
|
||||
DEBUG_INFO("SDR White Level : %f" , this.sdrWhiteLevel);
|
||||
|
||||
result = true;
|
||||
|
||||
exit:
|
||||
comRef_scopePop();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void sdrWhiteLevel_finish(void)
|
||||
{
|
||||
memset(&this, 0, sizeof(this));
|
||||
}
|
||||
|
||||
static bool sdrWhiteLevel_init(
|
||||
void ** opaque,
|
||||
int width,
|
||||
int height,
|
||||
bool shareable)
|
||||
{
|
||||
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)calloc(1, sizeof(*inst));
|
||||
if (!inst)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
comRef_scopePush();
|
||||
|
||||
// create the output texture
|
||||
D3D11_TEXTURE2D_DESC texDesc =
|
||||
{
|
||||
.Width = width,
|
||||
.Height = height,
|
||||
.MipLevels = 1,
|
||||
.ArraySize = 1,
|
||||
.SampleDesc.Count = 1,
|
||||
.SampleDesc.Quality = 0,
|
||||
.Usage = D3D11_USAGE_DEFAULT,
|
||||
.Format = DXGI_FORMAT_R10G10B10A2_UNORM,
|
||||
.BindFlags = D3D11_BIND_RENDER_TARGET |
|
||||
D3D11_BIND_SHADER_RESOURCE,
|
||||
.CPUAccessFlags = 0,
|
||||
.MiscFlags = 0
|
||||
};
|
||||
|
||||
// allow texture sharing with other backends
|
||||
if (shareable)
|
||||
texDesc.MiscFlags |=
|
||||
D3D11_RESOURCE_MISC_SHARED |
|
||||
D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
|
||||
|
||||
comRef_defineLocal(ID3D11Texture2D, tex);
|
||||
HRESULT 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;
|
||||
}
|
||||
|
||||
*opaque = inst;
|
||||
comRef_toGlobal(inst->tex , tex );
|
||||
comRef_toGlobal(inst->target, target);
|
||||
|
||||
comRef_scopePop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
comRef_scopePop();
|
||||
free(inst);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void sdrWhiteLevel_free(void * opaque)
|
||||
{
|
||||
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)opaque;
|
||||
comRef_release(inst->target);
|
||||
comRef_release(inst->tex );
|
||||
free(inst);
|
||||
}
|
||||
|
||||
static void updateConsts(void)
|
||||
{
|
||||
float nits = getSDRWhiteLevel(&this.displayPathInfo);
|
||||
if (nits == this.sdrWhiteLevel)
|
||||
return;
|
||||
|
||||
this.sdrWhiteLevel = nits;
|
||||
|
||||
struct ShaderConsts consts = { .sdrWhiteLevel = 80.0f / nits };
|
||||
ID3D11DeviceContext_UpdateSubresource(
|
||||
*this.context, *(ID3D11Resource**)this.buffer,
|
||||
0, NULL, &consts, 0, 0);
|
||||
}
|
||||
|
||||
static ID3D11Texture2D * sdrWhiteLevel_run(void * opaque, ID3D11Texture2D * src)
|
||||
{
|
||||
comRef_scopePush();
|
||||
ID3D11Texture2D * result = NULL;
|
||||
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)opaque;
|
||||
HRESULT status;
|
||||
|
||||
updateConsts();
|
||||
|
||||
// setup the pixel shader input resource view
|
||||
comRef_defineLocal(ID3D11ShaderResourceView, inputSRV);
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
ID3D11Texture2D_GetDesc(src, &desc);
|
||||
|
||||
const D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc =
|
||||
{
|
||||
.Format = desc.Format,
|
||||
.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D,
|
||||
.Texture2D.MipLevels = 1
|
||||
};
|
||||
status = ID3D11Device_CreateShaderResourceView(
|
||||
*this.device, (ID3D11Resource *)src, &srvDesc, inputSRV);
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the source resource view", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// set the vertex and pixel shader
|
||||
ID3D11DeviceContext_VSSetShader(*this.context, *this.vshader, NULL, 0);
|
||||
ID3D11DeviceContext_PSSetShader(*this.context, *this.pshader, NULL, 0);
|
||||
|
||||
// set the pixel shader resources
|
||||
ID3D11DeviceContext_PSSetShaderResources(*this.context, 0, 1, inputSRV );
|
||||
ID3D11DeviceContext_PSSetSamplers (*this.context, 0, 1, this.sampler);
|
||||
ID3D11DeviceContext_PSSetConstantBuffers(*this.context, 0, 1, this.buffer );
|
||||
|
||||
// set the render target
|
||||
ID3D11DeviceContext_OMSetRenderTargets(*this.context, 1, inst->target, NULL);
|
||||
|
||||
ID3D11DeviceContext_IASetPrimitiveTopology(
|
||||
*this.context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
|
||||
ID3D11DeviceContext_Draw(*this.context, 4, 0);
|
||||
|
||||
result = *inst->tex;
|
||||
|
||||
exit:
|
||||
comRef_scopePop();
|
||||
return result;
|
||||
}
|
||||
|
||||
DXGIPostProcess DXGIPP_SDRWhiteLevel =
|
||||
{
|
||||
.name = "SDRWhiteLevel",
|
||||
.earlyInit = NULL,
|
||||
.setup = sdrWhiteLevel_setup,
|
||||
.init = sdrWhiteLevel_init,
|
||||
.free = sdrWhiteLevel_free,
|
||||
.run = sdrWhiteLevel_run,
|
||||
.finish = sdrWhiteLevel_finish
|
||||
};
|
Loading…
Reference in New Issue
Block a user