[host] dxgi: seperate out and implement a post processor chain

This commit is contained in:
Geoffrey McRae 2023-10-29 20:26:26 +11:00
parent e225f66cee
commit 21cd380cad
5 changed files with 526 additions and 270 deletions

View File

@ -8,6 +8,8 @@ add_library(capture_DXGI STATIC
src/ods_capture.c src/ods_capture.c
src/util.c src/util.c
src/com_ref.c src/com_ref.c
src/pp/sdrwhitelevel.c
) )
add_definitions("-DCOBJMACROS -DINITGUID") add_definitions("-DCOBJMACROS -DINITGUID")

View File

@ -49,6 +49,16 @@
#define LOCKED(...) INTERLOCKED_SECTION(this->deviceContextLock, __VA_ARGS__) #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 typedef struct
{ {
unsigned int id; unsigned int id;
@ -61,12 +71,6 @@ DownsampleRule;
static Vector downsampleRules = {0}; static Vector downsampleRules = {0};
struct ShaderConsts
{
float sdrWhiteLevel;
}
__attribute__((aligned(16)));
// locals // locals
static struct DXGIInterface * this = NULL; static struct DXGIInterface * this = NULL;
@ -82,6 +86,10 @@ static struct DXGICopyBackend * backends[] = {
static bool dxgi_deinit(void); static bool dxgi_deinit(void);
static CaptureResult dxgi_releaseFrame(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 // implementation
static const char * dxgi_getName(void) static const char * dxgi_getName(void)
@ -626,18 +634,10 @@ static bool dxgi_init(void)
IDXGIOutput6_GetDesc1(*output6, &desc1); IDXGIOutput6_GetDesc1(*output6, &desc1);
this->dxgiColorSpace = desc1.ColorSpace; 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("Bits Per Color : %u" , desc1.BitsPerColor);
DEBUG_INFO("Color Space : %s" , getDXGIColorSpaceTypeStr(this->dxgiColorSpace)); DEBUG_INFO("Color Space : %s" , getDXGIColorSpaceTypeStr(this->dxgiColorSpace));
DEBUG_INFO("Min/Max Luminance : %f/%f", desc1.MinLuminance, desc1.MaxLuminance); DEBUG_INFO("Min/Max Luminance : %f/%f", desc1.MinLuminance, desc1.MaxLuminance);
DEBUG_INFO("Frame Luminance : %f" , desc1.MaxFullFrameLuminance); 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) for (int i = 0; i < this->maxTextures; ++i)
{ {
this->texture[i].texDamageCount = -1; this->texture[i].texDamageCount = -1;
if (!this->hdr) vector_create(&this->texture[i].pp, sizeof(PostProcessInstance), 0);
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 != &copyBackendD3D11)
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;
}
} }
if (this->hdr) const D3D11_VIEWPORT vp =
{ {
const D3D11_VIEWPORT vp = .TopLeftX = 0.0f,
{ .TopLeftY = 0.0f,
.TopLeftX = 0.0f, .Width = this->width,
.TopLeftY = 0.0f, .Height = this->height,
.Width = this->width, .MinDepth = 0.0f,
.Height = this->height, .MaxDepth = 1.0f,
.MinDepth = 0.0f, };
.MaxDepth = 1.0f, ID3D11DeviceContext_RSSetViewports(*this->deviceContext, 1, &vp);
};
ID3D11DeviceContext_RSSetViewports(*this->deviceContext, 1, &vp);
static const char * vshader = // if HDR add the SDRWhiteLevel post processor to correct the output
"void main(\n" if (this->hdr && !ppInit(&DXGIPP_SDRWhiteLevel,
" in uint vertexID : SV_VERTEXID,\n" this->backend != &copyBackendD3D11))
" out float4 position : SV_POSITION,\n" {
" out float2 texCoord : TEXCOORD0)\n" DEBUG_ERROR("Failed to initialize the SDRWhiteLevel post processor");
"{\n" goto fail;
" 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;
}
} }
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i) 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) for (int i = 0; i < this->maxTextures; ++i)
{ {
if (this->texture[i].map) Texture * tex = &this->texture[i];
{ if (!tex->map)
this->backend->unmapTexture(this->texture + i); continue;
this->texture[i].map = NULL; this->backend->unmapTexture(tex);
} tex->map = NULL;
} }
if (this->dup && *this->dup) if (this->dup && *this->dup)
dxgi_releaseFrame(); dxgi_releaseFrame();
// this MUST run before backend->free(). // this MUST run before backend->free() & ppFreeAll.
comRef_free(); comRef_free();
ppFreeAll();
if (this->backend) if (this->backend)
{ {
this->backend->free(); this->backend->free();
@ -1223,76 +1065,14 @@ static CaptureResult dxgi_capture(void)
computeFrameDamage(tex); computeFrameDamage(tex);
computeTexDamage(tex); computeTexDamage(tex);
if (this->hdr) ID3D11Texture2D * dst = ppRun(tex, *src);
{ if (dst != *src)
// 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);
ID3D11DeviceContext_Flush(*this->deviceContext); ID3D11DeviceContext_Flush(*this->deviceContext);
if (!this->backend->copyFrame(tex, *tex->hdrTex)) if (!this->backend->copyFrame(tex, dst))
{
result = CAPTURE_RESULT_ERROR;
goto exit;
}
}
else
{ {
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) for (int i = 0; i < this->maxTextures; ++i)
@ -1535,6 +1315,51 @@ static CaptureResult dxgi_releaseFrame(void)
return CAPTURE_RESULT_OK; 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 = struct CaptureInterface Capture_DXGI =
{ {
.shortName = "DXGI", .shortName = "DXGI",

View File

@ -18,6 +18,8 @@
* Temple Place, Suite 330, Boston, MA 02111-1307 USA * Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "pp.h"
#include <stdint.h> #include <stdint.h>
#include <dxgi.h> #include <dxgi.h>
#include <dxgi1_2.h> #include <dxgi1_2.h>
@ -28,6 +30,7 @@
#include "common/event.h" #include "common/event.h"
#include "common/locking.h" #include "common/locking.h"
#include "common/types.h" #include "common/types.h"
#include "common/vector.h"
#include "interface/capture.h" #include "interface/capture.h"
enum TextureState enum TextureState
@ -47,8 +50,9 @@ typedef struct Texture
FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS]; FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS];
int32_t texDamageCount; int32_t texDamageCount;
FrameDamageRect texDamageRects[KVMFR_MAX_DAMAGE_RECTS]; FrameDamageRect texDamageRects[KVMFR_MAX_DAMAGE_RECTS];
ID3D11RenderTargetView ** renderTarget;
ID3D11Texture2D ** hdrTex; // post processing
Vector pp;
void * impl; void * impl;
} }
@ -89,13 +93,7 @@ struct DXGIInterface
bool needsRelease; bool needsRelease;
DXGI_FORMAT dxgiSrcFormat, dxgiFormat; DXGI_FORMAT dxgiSrcFormat, dxgiFormat;
bool hdr; bool hdr;
DISPLAYCONFIG_PATH_INFO displayPathInfo;
DXGI_COLOR_SPACE_TYPE dxgiColorSpace; DXGI_COLOR_SPACE_TYPE dxgiColorSpace;
float sdrWhiteLevel;
ID3D11Buffer ** constBuffer;
ID3D11PixelShader ** pixelShader;
ID3D11VertexShader ** vertexShader;
ID3D11SamplerState ** samplerState;
struct DXGICopyBackend * backend; struct DXGICopyBackend * backend;
CaptureGetPointerBuffer getPointerBufferFn; CaptureGetPointerBuffer getPointerBufferFn;

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

View 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
};