mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-07-20 22:32:01 +00:00
[host] hdr: encode legacy captures as HDR10
Convert FP16 scRGB captures to BT.2020 PQ before storing them in the 10-bit wire format. Preserve linear-light downsampling, publish the real SDR white level and display metadata, and advance the format version when those properties change.
This commit is contained in:
@@ -84,8 +84,17 @@ typedef struct CaptureFrame
|
|||||||
bool truncated; // true if the frame data is truncated
|
bool truncated; // true if the frame data is truncated
|
||||||
bool hdr; // true if the frame format is HDR
|
bool hdr; // true if the frame format is HDR
|
||||||
bool hdrPQ; // true if the frame format is PQ transformed
|
bool hdrPQ; // true if the frame format is PQ transformed
|
||||||
|
bool hdrMetadata; // true if the HDR static metadata is valid
|
||||||
CaptureRotation rotation; // output rotation of the frame
|
CaptureRotation rotation; // output rotation of the frame
|
||||||
|
|
||||||
|
uint16_t hdrDisplayPrimary[3][2];
|
||||||
|
uint16_t hdrWhitePoint[2];
|
||||||
|
uint32_t hdrMaxDisplayLuminance;
|
||||||
|
uint32_t hdrMinDisplayLuminance;
|
||||||
|
uint32_t hdrMaxContentLightLevel;
|
||||||
|
uint32_t hdrMaxFrameAverageLightLevel;
|
||||||
|
uint32_t sdrWhiteLevel;
|
||||||
|
|
||||||
uint32_t damageRectsCount;
|
uint32_t damageRectsCount;
|
||||||
FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS];
|
FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <dxgi1_3.h>
|
#include <dxgi1_3.h>
|
||||||
#include <dxgi1_6.h>
|
#include <dxgi1_6.h>
|
||||||
#include <d3dcommon.h>
|
#include <d3dcommon.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
// definitions
|
// definitions
|
||||||
struct D12Interface
|
struct D12Interface
|
||||||
@@ -49,6 +50,7 @@ struct D12Interface
|
|||||||
ID3D12Device3 ** device;
|
ID3D12Device3 ** device;
|
||||||
|
|
||||||
DISPLAYCONFIG_PATH_INFO displayPathInfo;
|
DISPLAYCONFIG_PATH_INFO displayPathInfo;
|
||||||
|
DXGI_OUTPUT_DESC1 outputDesc;
|
||||||
|
|
||||||
ID3D12CommandQueue ** copyQueue;
|
ID3D12CommandQueue ** copyQueue;
|
||||||
ID3D12CommandQueue ** computeQueue;
|
ID3D12CommandQueue ** computeQueue;
|
||||||
@@ -110,6 +112,54 @@ ComScope * d12_comScope = NULL;
|
|||||||
|
|
||||||
static struct D12Interface * this = NULL;
|
static struct D12Interface * this = NULL;
|
||||||
|
|
||||||
|
static bool d12_setHDRMetadata(CaptureFrame * frame,
|
||||||
|
const DXGI_OUTPUT_DESC1 * desc)
|
||||||
|
{
|
||||||
|
const float coordinates[] =
|
||||||
|
{
|
||||||
|
desc->RedPrimary [0], desc->RedPrimary [1],
|
||||||
|
desc->GreenPrimary[0], desc->GreenPrimary[1],
|
||||||
|
desc->BluePrimary [0], desc->BluePrimary [1],
|
||||||
|
desc->WhitePoint [0], desc->WhitePoint [1],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < ARRAY_LENGTH(coordinates); ++i)
|
||||||
|
if (coordinates[i] < 0.0f || coordinates[i] > 1.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (desc->RedPrimary[1] == 0.0f || desc->GreenPrimary[1] == 0.0f ||
|
||||||
|
desc->BluePrimary[1] == 0.0f || desc->WhitePoint[1] == 0.0f ||
|
||||||
|
desc->MaxLuminance <= 0.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
frame->hdrDisplayPrimary[0][0] = (uint16_t)lroundf(
|
||||||
|
desc->RedPrimary[0] * 50000.0f);
|
||||||
|
frame->hdrDisplayPrimary[0][1] = (uint16_t)lroundf(
|
||||||
|
desc->RedPrimary[1] * 50000.0f);
|
||||||
|
frame->hdrDisplayPrimary[1][0] = (uint16_t)lroundf(
|
||||||
|
desc->GreenPrimary[0] * 50000.0f);
|
||||||
|
frame->hdrDisplayPrimary[1][1] = (uint16_t)lroundf(
|
||||||
|
desc->GreenPrimary[1] * 50000.0f);
|
||||||
|
frame->hdrDisplayPrimary[2][0] = (uint16_t)lroundf(
|
||||||
|
desc->BluePrimary[0] * 50000.0f);
|
||||||
|
frame->hdrDisplayPrimary[2][1] = (uint16_t)lroundf(
|
||||||
|
desc->BluePrimary[1] * 50000.0f);
|
||||||
|
frame->hdrWhitePoint[0] = (uint16_t)lroundf(
|
||||||
|
desc->WhitePoint[0] * 50000.0f);
|
||||||
|
frame->hdrWhitePoint[1] = (uint16_t)lroundf(
|
||||||
|
desc->WhitePoint[1] * 50000.0f);
|
||||||
|
frame->hdrMaxDisplayLuminance = (uint32_t)lroundf(desc->MaxLuminance);
|
||||||
|
frame->hdrMinDisplayLuminance = desc->MinLuminance > 0.0f ?
|
||||||
|
(uint32_t)lroundf(desc->MinLuminance * 10000.0f) : 0;
|
||||||
|
|
||||||
|
if ((uint64_t)frame->hdrMaxDisplayLuminance * 10000 <=
|
||||||
|
frame->hdrMinDisplayLuminance)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
frame->hdrMetadata = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// forwards
|
// forwards
|
||||||
|
|
||||||
static bool d12_enumerateDevices(
|
static bool d12_enumerateDevices(
|
||||||
@@ -298,6 +348,7 @@ static bool d12_init(void * ivshmemBase, unsigned * alignSize)
|
|||||||
|
|
||||||
DXGI_OUTPUT_DESC1 desc1;
|
DXGI_OUTPUT_DESC1 desc1;
|
||||||
IDXGIOutput6_GetDesc1(*output6, &desc1);
|
IDXGIOutput6_GetDesc1(*output6, &desc1);
|
||||||
|
this->outputDesc = desc1;
|
||||||
if (!display_getPathInfo(desc1.Monitor, &this->displayPathInfo))
|
if (!display_getPathInfo(desc1.Monitor, &this->displayPathInfo))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to get the display path info");
|
DEBUG_ERROR("Failed to get the display path info");
|
||||||
@@ -546,12 +597,16 @@ static CaptureResult d12_waitFrame(unsigned frameBufferIndex,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const D3D12_RESOURCE_DESC srcDesc = ID3D12Resource_GetDesc(*src);
|
||||||
D12FrameFormat srcFormat =
|
D12FrameFormat srcFormat =
|
||||||
{
|
{
|
||||||
.desc = ID3D12Resource_GetDesc(*src),
|
.desc = srcDesc,
|
||||||
.colorSpace = desc.colorSpace,
|
.colorSpace = desc.colorSpace,
|
||||||
.width = srcFormat.desc.Width,
|
.width = srcDesc.Width,
|
||||||
.height = srcFormat.desc.Height
|
.height = srcDesc.Height,
|
||||||
|
.hdr = desc.colorSpace ==
|
||||||
|
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020,
|
||||||
|
.hdrPQ = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch(srcFormat.desc.Format)
|
switch(srcFormat.desc.Format)
|
||||||
@@ -577,12 +632,25 @@ static CaptureResult d12_waitFrame(unsigned frameBufferIndex,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (srcFormat.hdr)
|
||||||
|
{
|
||||||
|
if (srcFormat.format == CAPTURE_FMT_RGBA10)
|
||||||
|
srcFormat.hdrPQ = true;
|
||||||
|
else if (srcFormat.format != CAPTURE_FMT_RGBA16F)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("HDR capture did not provide an FP16 scRGB or PQ texture");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if the input format changed, reconfigure the effects
|
// if the input format changed, reconfigure the effects
|
||||||
if (srcFormat.desc.Width == 0 ||
|
if (srcFormat.desc.Width == 0 ||
|
||||||
srcFormat.desc.Width != this->captureFormat.desc.Width ||
|
srcFormat.desc.Width != this->captureFormat.desc.Width ||
|
||||||
srcFormat.desc.Height != this->captureFormat.desc.Height ||
|
srcFormat.desc.Height != this->captureFormat.desc.Height ||
|
||||||
srcFormat.desc.Format != this->captureFormat.desc.Format ||
|
srcFormat.desc.Format != this->captureFormat.desc.Format ||
|
||||||
srcFormat.colorSpace != this->captureFormat.colorSpace)
|
srcFormat.colorSpace != this->captureFormat.colorSpace ||
|
||||||
|
srcFormat.hdr != this->captureFormat.hdr ||
|
||||||
|
srcFormat.hdrPQ != this->captureFormat.hdrPQ)
|
||||||
{
|
{
|
||||||
DEBUG_TRACE("Capture format changed");
|
DEBUG_TRACE("Capture format changed");
|
||||||
|
|
||||||
@@ -621,7 +689,9 @@ static CaptureResult d12_waitFrame(unsigned frameBufferIndex,
|
|||||||
dstFormat.colorSpace != this->dstFormat.colorSpace ||
|
dstFormat.colorSpace != this->dstFormat.colorSpace ||
|
||||||
dstFormat.width != this->dstFormat.width ||
|
dstFormat.width != this->dstFormat.width ||
|
||||||
dstFormat.height != this->dstFormat.height ||
|
dstFormat.height != this->dstFormat.height ||
|
||||||
dstFormat.format != this->dstFormat.format)
|
dstFormat.format != this->dstFormat.format ||
|
||||||
|
dstFormat.hdr != this->dstFormat.hdr ||
|
||||||
|
dstFormat.hdrPQ != this->dstFormat.hdrPQ)
|
||||||
{
|
{
|
||||||
DEBUG_TRACE("Output format changed");
|
DEBUG_TRACE("Output format changed");
|
||||||
++this->formatVer;
|
++this->formatVer;
|
||||||
@@ -655,9 +725,12 @@ static CaptureResult d12_waitFrame(unsigned frameBufferIndex,
|
|||||||
frame->pitch = this->pitch;
|
frame->pitch = this->pitch;
|
||||||
frame->stride = this->pitch / this->bpp;
|
frame->stride = this->pitch / this->bpp;
|
||||||
frame->format = this->dstFormat.format;
|
frame->format = this->dstFormat.format;
|
||||||
frame->hdr = this->dstFormat.colorSpace ==
|
frame->hdr = this->dstFormat.hdr;
|
||||||
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
|
frame->hdrPQ = this->dstFormat.hdrPQ;
|
||||||
frame->hdrPQ = false;
|
frame->sdrWhiteLevel = (uint32_t)lroundf(
|
||||||
|
display_getSDRWhiteLevel(&this->displayPathInfo));
|
||||||
|
if (frame->hdr)
|
||||||
|
d12_setHDRMetadata(frame, &this->outputDesc);
|
||||||
frame->rotation = desc.rotation;
|
frame->rotation = desc.rotation;
|
||||||
|
|
||||||
D12Effect * effect;
|
D12Effect * effect;
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ typedef struct D12FrameFormat
|
|||||||
DXGI_COLOR_SPACE_TYPE colorSpace;
|
DXGI_COLOR_SPACE_TYPE colorSpace;
|
||||||
unsigned width, height;
|
unsigned width, height;
|
||||||
CaptureFormat format;
|
CaptureFormat format;
|
||||||
|
bool hdr;
|
||||||
|
bool hdrPQ;
|
||||||
}
|
}
|
||||||
D12FrameFormat;
|
D12FrameFormat;
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/windebug.h"
|
#include "common/windebug.h"
|
||||||
#include "common/array.h"
|
#include "common/array.h"
|
||||||
#include "common/display.h"
|
|
||||||
#include "common/option.h"
|
#include "common/option.h"
|
||||||
|
|
||||||
#include <d3dcompiler.h>
|
#include <d3dcompiler.h>
|
||||||
@@ -36,17 +35,9 @@ typedef struct HDR16to10Inst
|
|||||||
{
|
{
|
||||||
D12Effect base;
|
D12Effect base;
|
||||||
|
|
||||||
const DISPLAYCONFIG_PATH_INFO * displayPathInfo;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
float SDRWhiteLevel;
|
|
||||||
}
|
|
||||||
consts;
|
|
||||||
|
|
||||||
ID3D12RootSignature ** rootSignature;
|
ID3D12RootSignature ** rootSignature;
|
||||||
ID3D12PipelineState ** pso;
|
ID3D12PipelineState ** pso;
|
||||||
ID3D12DescriptorHeap ** descHeap;
|
ID3D12DescriptorHeap ** descHeap;
|
||||||
ID3D12Resource ** constBuffer;
|
|
||||||
|
|
||||||
unsigned threadsX, threadsY;
|
unsigned threadsX, threadsY;
|
||||||
ID3D12Resource ** dst;
|
ID3D12Resource ** dst;
|
||||||
@@ -76,6 +67,8 @@ static void d12_effect_hdr16to10InitOptions(void)
|
|||||||
static D12EffectStatus d12_effect_hdr16to10Create(D12Effect ** instance,
|
static D12EffectStatus d12_effect_hdr16to10Create(D12Effect ** instance,
|
||||||
ID3D12Device3 * device, const DISPLAYCONFIG_PATH_INFO * displayPathInfo)
|
ID3D12Device3 * device, const DISPLAYCONFIG_PATH_INFO * displayPathInfo)
|
||||||
{
|
{
|
||||||
|
(void)displayPathInfo;
|
||||||
|
|
||||||
if (!option_get_bool("d12", "HDR16to10"))
|
if (!option_get_bool("d12", "HDR16to10"))
|
||||||
return D12_EFFECT_STATUS_BYPASS;
|
return D12_EFFECT_STATUS_BYPASS;
|
||||||
|
|
||||||
@@ -90,18 +83,9 @@ static D12EffectStatus d12_effect_hdr16to10Create(D12Effect ** instance,
|
|||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
comRef_scopePush(10);
|
comRef_scopePush(10);
|
||||||
|
|
||||||
this->displayPathInfo = displayPathInfo;
|
|
||||||
|
|
||||||
// shader resource view
|
// shader resource view
|
||||||
D3D12_DESCRIPTOR_RANGE descriptorRanges[3] =
|
D3D12_DESCRIPTOR_RANGE descriptorRanges[2] =
|
||||||
{
|
{
|
||||||
{
|
|
||||||
.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
|
|
||||||
.NumDescriptors = 1,
|
|
||||||
.BaseShaderRegister = 0,
|
|
||||||
.RegisterSpace = 0,
|
|
||||||
.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
|
.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
|
||||||
.NumDescriptors = 1,
|
.NumDescriptors = 1,
|
||||||
@@ -175,18 +159,27 @@ static D12EffectStatus d12_effect_hdr16to10Create(D12Effect ** instance,
|
|||||||
|
|
||||||
// Compile the shader
|
// Compile the shader
|
||||||
const char * testCode =
|
const char * testCode =
|
||||||
"cbuffer Constants : register(b0)\n"
|
|
||||||
"{\n"
|
|
||||||
" float SDRWhiteLevel;\n"
|
|
||||||
"};\n"
|
|
||||||
"\n"
|
|
||||||
"Texture2D <float4> src : register(t0);\n"
|
"Texture2D <float4> src : register(t0);\n"
|
||||||
"RWTexture2D<float4> dst : register(u0);\n"
|
"RWTexture2D<float4> dst : register(u0);\n"
|
||||||
|
"static const float PQ_m1 = 0.1593017578125;\n"
|
||||||
|
"static const float PQ_m2 = 78.84375;\n"
|
||||||
|
"static const float PQ_c1 = 0.8359375;\n"
|
||||||
|
"static const float PQ_c2 = 18.8515625;\n"
|
||||||
|
"static const float PQ_c3 = 18.6875;\n"
|
||||||
"\n"
|
"\n"
|
||||||
"[numthreads(" STR(THREADS) ", " STR(THREADS) ", 1)]\n"
|
"[numthreads(" STR(THREADS) ", " STR(THREADS) ", 1)]\n"
|
||||||
"void main(uint3 dt : SV_DispatchThreadID)\n"
|
"void main(uint3 dt : SV_DispatchThreadID)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" dst[dt.xy] = src[dt.xy] * SDRWhiteLevel;"
|
" float4 color = src[dt.xy];\n"
|
||||||
|
" float3 linear709 = color.rgb * (80.0 / 10000.0);\n"
|
||||||
|
" float3 linear2020 = float3(\n"
|
||||||
|
" dot(linear709, float3(0.6274039, 0.3292830, 0.0433131)),\n"
|
||||||
|
" dot(linear709, float3(0.0690973, 0.9195404, 0.0113623)),\n"
|
||||||
|
" dot(linear709, float3(0.0163914, 0.0880133, 0.8955953)));\n"
|
||||||
|
" float3 p = pow(max(linear2020, 0.0), PQ_m1);\n"
|
||||||
|
" float3 pq = pow((PQ_c1 + PQ_c2 * p) /\n"
|
||||||
|
" (1.0 + PQ_c3 * p), PQ_m2);\n"
|
||||||
|
" dst[dt.xy] = float4(pq, color.a);\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
bool debug = false;
|
bool debug = false;
|
||||||
@@ -240,48 +233,9 @@ static D12EffectStatus d12_effect_hdr16to10Create(D12Effect ** instance,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_HEAP_PROPERTIES constHeapProps =
|
|
||||||
{
|
|
||||||
.Type = D3D12_HEAP_TYPE_UPLOAD,
|
|
||||||
.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
|
||||||
.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN
|
|
||||||
};
|
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC constBufferDesc =
|
|
||||||
{
|
|
||||||
.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
|
|
||||||
.Width = ALIGN_TO(sizeof(this->consts),
|
|
||||||
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT),
|
|
||||||
.Height = 1,
|
|
||||||
.DepthOrArraySize = 1,
|
|
||||||
.MipLevels = 1,
|
|
||||||
.Format = DXGI_FORMAT_UNKNOWN,
|
|
||||||
.SampleDesc.Count = 1,
|
|
||||||
.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
|
||||||
.Flags = D3D12_RESOURCE_FLAG_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
comRef_defineLocal(ID3D12Resource, constBuffer);
|
|
||||||
hr = ID3D12Device3_CreateCommittedResource(
|
|
||||||
device,
|
|
||||||
&constHeapProps,
|
|
||||||
D3D12_HEAP_FLAG_NONE,
|
|
||||||
&constBufferDesc,
|
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
||||||
NULL,
|
|
||||||
&IID_ID3D12Resource,
|
|
||||||
(void **)constBuffer);
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
DEBUG_WINERROR("Failed to create the constant buffer resource", hr);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
comRef_toGlobal(this->rootSignature, rootSignature);
|
comRef_toGlobal(this->rootSignature, rootSignature);
|
||||||
comRef_toGlobal(this->pso , pso );
|
comRef_toGlobal(this->pso , pso );
|
||||||
comRef_toGlobal(this->descHeap , descHeap );
|
comRef_toGlobal(this->descHeap , descHeap );
|
||||||
comRef_toGlobal(this->constBuffer , constBuffer );
|
|
||||||
|
|
||||||
result = D12_EFFECT_STATUS_OK;
|
result = D12_EFFECT_STATUS_OK;
|
||||||
*instance = &this->base;
|
*instance = &this->base;
|
||||||
@@ -313,7 +267,7 @@ static D12EffectStatus d12_effect_hdr16to10SetFormat(D12Effect * effect,
|
|||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
if (src->desc.Format != DXGI_FORMAT_R16G16B16A16_FLOAT ||
|
if (src->desc.Format != DXGI_FORMAT_R16G16B16A16_FLOAT ||
|
||||||
src->colorSpace != DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
|
!src->hdr || src->hdrPQ)
|
||||||
{
|
{
|
||||||
result = D12_EFFECT_STATUS_BYPASS;
|
result = D12_EFFECT_STATUS_BYPASS;
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -358,6 +312,8 @@ static D12EffectStatus d12_effect_hdr16to10SetFormat(D12Effect * effect,
|
|||||||
|
|
||||||
dst->desc = desc;
|
dst->desc = desc;
|
||||||
dst->format = CAPTURE_FMT_RGBA10;
|
dst->format = CAPTURE_FMT_RGBA10;
|
||||||
|
dst->hdr = true;
|
||||||
|
dst->hdrPQ = true;
|
||||||
result = D12_EFFECT_STATUS_OK;
|
result = D12_EFFECT_STATUS_OK;
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
@@ -371,21 +327,6 @@ static ID3D12Resource * d12_effect_hdr16to10Run(D12Effect * effect,
|
|||||||
{
|
{
|
||||||
HDR16to10Inst * this = UPCAST(HDR16to10Inst, effect);
|
HDR16to10Inst * this = UPCAST(HDR16to10Inst, effect);
|
||||||
|
|
||||||
float nits = 80.0f / display_getSDRWhiteLevel(this->displayPathInfo);
|
|
||||||
if (nits != this->consts.SDRWhiteLevel)
|
|
||||||
{
|
|
||||||
this->consts.SDRWhiteLevel = nits;
|
|
||||||
|
|
||||||
void * data;
|
|
||||||
D3D12_RANGE readRange = { 0, 0 };
|
|
||||||
HRESULT hr = ID3D12Resource_Map(*this->constBuffer, 0, &readRange, &data);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
memcpy(data, &this->consts, sizeof(this->consts));
|
|
||||||
ID3D12Resource_Unmap(*this->constBuffer, 0, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// transition the destination texture to unordered access so we can write to it
|
// transition the destination texture to unordered access so we can write to it
|
||||||
{
|
{
|
||||||
D3D12_RESOURCE_BARRIER barrier =
|
D3D12_RESOURCE_BARRIER barrier =
|
||||||
@@ -407,19 +348,6 @@ static ID3D12Resource * d12_effect_hdr16to10Run(D12Effect * effect,
|
|||||||
D3D12_CPU_DESCRIPTOR_HANDLE cpuSrvUavHandle =
|
D3D12_CPU_DESCRIPTOR_HANDLE cpuSrvUavHandle =
|
||||||
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(*this->descHeap);
|
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(*this->descHeap);
|
||||||
|
|
||||||
// descriptor for input CBV
|
|
||||||
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc =
|
|
||||||
{
|
|
||||||
.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(*this->constBuffer),
|
|
||||||
.SizeInBytes = ALIGN_TO(sizeof(this->consts),
|
|
||||||
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)
|
|
||||||
};
|
|
||||||
ID3D12Device3_CreateConstantBufferView(device, &cbvDesc, cpuSrvUavHandle);
|
|
||||||
|
|
||||||
// move to the next slot
|
|
||||||
cpuSrvUavHandle.ptr += ID3D12Device3_GetDescriptorHandleIncrementSize(
|
|
||||||
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
|
||||||
|
|
||||||
// descriptor for input SRV
|
// descriptor for input SRV
|
||||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc =
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc =
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "interface/platform.h"
|
#include "interface/platform.h"
|
||||||
#include "common/array.h"
|
#include "common/array.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
|
#include "common/display.h"
|
||||||
#include "common/windebug.h"
|
#include "common/windebug.h"
|
||||||
#include "common/option.h"
|
#include "common/option.h"
|
||||||
#include "common/locking.h"
|
#include "common/locking.h"
|
||||||
@@ -53,13 +54,13 @@
|
|||||||
|
|
||||||
//post processers
|
//post processers
|
||||||
extern const DXGIPostProcess DXGIPP_Downsample;
|
extern const DXGIPostProcess DXGIPP_Downsample;
|
||||||
extern const DXGIPostProcess DXGIPP_SDRWhiteLevel;
|
extern const DXGIPostProcess DXGIPP_HDR16to10;
|
||||||
extern const DXGIPostProcess DXGIPP_RGB24;
|
extern const DXGIPostProcess DXGIPP_RGB24;
|
||||||
|
|
||||||
const DXGIPostProcess * postProcessors[] =
|
const DXGIPostProcess * postProcessors[] =
|
||||||
{
|
{
|
||||||
&DXGIPP_Downsample,
|
&DXGIPP_Downsample,
|
||||||
&DXGIPP_SDRWhiteLevel,
|
&DXGIPP_HDR16to10,
|
||||||
&DXGIPP_RGB24
|
&DXGIPP_RGB24
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -135,6 +136,10 @@ struct DXGIInterface
|
|||||||
DXGI_FORMAT dxgiSrcFormat, dxgiFormat;
|
DXGI_FORMAT dxgiSrcFormat, dxgiFormat;
|
||||||
bool hdr;
|
bool hdr;
|
||||||
DXGI_COLOR_SPACE_TYPE dxgiColorSpace;
|
DXGI_COLOR_SPACE_TYPE dxgiColorSpace;
|
||||||
|
DXGI_OUTPUT_DESC1 outputDesc;
|
||||||
|
bool outputDescValid;
|
||||||
|
DISPLAYCONFIG_PATH_INFO displayPathInfo;
|
||||||
|
bool displayPathInfoValid;
|
||||||
ID3D11VertexShader ** vshader;
|
ID3D11VertexShader ** vshader;
|
||||||
struct DXGICopyBackend * backend;
|
struct DXGICopyBackend * backend;
|
||||||
bool backendConfigured;
|
bool backendConfigured;
|
||||||
@@ -165,6 +170,54 @@ struct DXGIInterface
|
|||||||
|
|
||||||
static struct DXGIInterface * this = NULL;
|
static struct DXGIInterface * this = NULL;
|
||||||
|
|
||||||
|
static bool dxgi_setHDRMetadata(CaptureFrame * frame,
|
||||||
|
const DXGI_OUTPUT_DESC1 * desc)
|
||||||
|
{
|
||||||
|
const float coordinates[] =
|
||||||
|
{
|
||||||
|
desc->RedPrimary [0], desc->RedPrimary [1],
|
||||||
|
desc->GreenPrimary[0], desc->GreenPrimary[1],
|
||||||
|
desc->BluePrimary [0], desc->BluePrimary [1],
|
||||||
|
desc->WhitePoint [0], desc->WhitePoint [1],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < ARRAY_LENGTH(coordinates); ++i)
|
||||||
|
if (coordinates[i] < 0.0f || coordinates[i] > 1.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (desc->RedPrimary[1] == 0.0f || desc->GreenPrimary[1] == 0.0f ||
|
||||||
|
desc->BluePrimary[1] == 0.0f || desc->WhitePoint[1] == 0.0f ||
|
||||||
|
desc->MaxLuminance <= 0.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
frame->hdrDisplayPrimary[0][0] = (uint16_t)lroundf(
|
||||||
|
desc->RedPrimary[0] * 50000.0f);
|
||||||
|
frame->hdrDisplayPrimary[0][1] = (uint16_t)lroundf(
|
||||||
|
desc->RedPrimary[1] * 50000.0f);
|
||||||
|
frame->hdrDisplayPrimary[1][0] = (uint16_t)lroundf(
|
||||||
|
desc->GreenPrimary[0] * 50000.0f);
|
||||||
|
frame->hdrDisplayPrimary[1][1] = (uint16_t)lroundf(
|
||||||
|
desc->GreenPrimary[1] * 50000.0f);
|
||||||
|
frame->hdrDisplayPrimary[2][0] = (uint16_t)lroundf(
|
||||||
|
desc->BluePrimary[0] * 50000.0f);
|
||||||
|
frame->hdrDisplayPrimary[2][1] = (uint16_t)lroundf(
|
||||||
|
desc->BluePrimary[1] * 50000.0f);
|
||||||
|
frame->hdrWhitePoint[0] = (uint16_t)lroundf(
|
||||||
|
desc->WhitePoint[0] * 50000.0f);
|
||||||
|
frame->hdrWhitePoint[1] = (uint16_t)lroundf(
|
||||||
|
desc->WhitePoint[1] * 50000.0f);
|
||||||
|
frame->hdrMaxDisplayLuminance = (uint32_t)lroundf(desc->MaxLuminance);
|
||||||
|
frame->hdrMinDisplayLuminance = desc->MinLuminance > 0.0f ?
|
||||||
|
(uint32_t)lroundf(desc->MinLuminance * 10000.0f) : 0;
|
||||||
|
|
||||||
|
if ((uint64_t)frame->hdrMaxDisplayLuminance * 10000 <=
|
||||||
|
frame->hdrMinDisplayLuminance)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
frame->hdrMetadata = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
extern struct DXGICopyBackend copyBackendD3D11;
|
extern struct DXGICopyBackend copyBackendD3D11;
|
||||||
static struct DXGICopyBackend * backends[] = {
|
static struct DXGICopyBackend * backends[] = {
|
||||||
©BackendD3D11,
|
©BackendD3D11,
|
||||||
@@ -364,6 +417,15 @@ static bool dxgi_init(void * ivshmemBase, unsigned * alignSize)
|
|||||||
{
|
{
|
||||||
DEBUG_ASSERT(this);
|
DEBUG_ASSERT(this);
|
||||||
|
|
||||||
|
// These describe the output selected by this initialization. Do not retain
|
||||||
|
// metadata from a previous duplication session if the replacement output
|
||||||
|
// does not expose IDXGIOutput6 or display path information.
|
||||||
|
this->dxgiColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||||
|
this->outputDescValid = false;
|
||||||
|
this->displayPathInfoValid = false;
|
||||||
|
memset(&this->outputDesc , 0, sizeof(this->outputDesc ));
|
||||||
|
memset(&this->displayPathInfo, 0, sizeof(this->displayPathInfo));
|
||||||
|
|
||||||
comRef_initGlobalScope(20 + this->maxTextures * 16, this->comScope);
|
comRef_initGlobalScope(20 + this->maxTextures * 16, this->comScope);
|
||||||
comRef_scopePush(20);
|
comRef_scopePush(20);
|
||||||
|
|
||||||
@@ -725,7 +787,11 @@ static bool dxgi_init(void * ivshmemBase, unsigned * alignSize)
|
|||||||
{
|
{
|
||||||
DXGI_OUTPUT_DESC1 desc1;
|
DXGI_OUTPUT_DESC1 desc1;
|
||||||
IDXGIOutput6_GetDesc1(*output6, &desc1);
|
IDXGIOutput6_GetDesc1(*output6, &desc1);
|
||||||
this->dxgiColorSpace = desc1.ColorSpace;
|
this->dxgiColorSpace = desc1.ColorSpace;
|
||||||
|
this->outputDesc = desc1;
|
||||||
|
this->outputDescValid = true;
|
||||||
|
this->displayPathInfoValid =
|
||||||
|
display_getPathInfo(desc1.Monitor, &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));
|
||||||
@@ -793,6 +859,12 @@ static bool dxgi_init(void * ivshmemBase, unsigned * alignSize)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->hdr && this->format != CAPTURE_FMT_RGBA16F)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("HDR capture did not provide an FP16 scRGB texture");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
this->outputWidth = this->width;
|
this->outputWidth = this->width;
|
||||||
this->outputHeight = this->height;
|
this->outputHeight = this->height;
|
||||||
|
|
||||||
@@ -824,23 +896,23 @@ static bool dxgi_init(void * ivshmemBase, unsigned * alignSize)
|
|||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
bool shareable = this->backend != ©BackendD3D11;
|
bool shareable = this->backend != ©BackendD3D11;
|
||||||
if (this->hdr)
|
// Downsampling must happen in linear light, before HDR conversion or RGB24
|
||||||
{
|
// packing.
|
||||||
//HDR content needs to be corrected and converted to HDR10
|
|
||||||
if (!ppInit(&DXGIPP_SDRWhiteLevel, shareable))
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("Failed to initialize the SDRWhiteLevel post processor");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Downsampling must happen before conversion to RGB24
|
|
||||||
if (!ppInit(&DXGIPP_Downsample, shareable))
|
if (!ppInit(&DXGIPP_Downsample, shareable))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to intiailize the downsample post processor");
|
DEBUG_ERROR("Failed to intiailize the downsample post processor");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->hdr)
|
||||||
|
{
|
||||||
|
if (!ppInit(&DXGIPP_HDR16to10, shareable))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to initialize the HDR16to10 post processor");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//If not HDR, pack to RGB24
|
//If not HDR, pack to RGB24
|
||||||
if (!this->hdr && this->allowRGB24)
|
if (!this->hdr && this->allowRGB24)
|
||||||
{
|
{
|
||||||
@@ -1416,7 +1488,11 @@ static CaptureResult dxgi_waitFrame(unsigned frameBufferIndex,
|
|||||||
frame->stride = this->stride;
|
frame->stride = this->stride;
|
||||||
frame->format = this->outputFormat;
|
frame->format = this->outputFormat;
|
||||||
frame->hdr = this->hdr;
|
frame->hdr = this->hdr;
|
||||||
frame->hdrPQ = false;
|
frame->hdrPQ = this->hdr;
|
||||||
|
frame->sdrWhiteLevel = this->displayPathInfoValid ?
|
||||||
|
(uint32_t)lroundf(display_getSDRWhiteLevel(&this->displayPathInfo)) : 0;
|
||||||
|
if (frame->hdr && this->outputDescValid)
|
||||||
|
dxgi_setHDRMetadata(frame, &this->outputDesc);
|
||||||
frame->rotation = this->rotation;
|
frame->rotation = this->rotation;
|
||||||
|
|
||||||
frame->damageRectsCount = tex->damageRectsCount;
|
frame->damageRectsCount = tex->damageRectsCount;
|
||||||
|
|||||||
@@ -24,11 +24,8 @@
|
|||||||
|
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/windebug.h"
|
#include "common/windebug.h"
|
||||||
#include "common/display.h"
|
|
||||||
|
|
||||||
#include <dxgi1_6.h>
|
typedef struct HDR16to10
|
||||||
|
|
||||||
typedef struct SDRWhiteLevel
|
|
||||||
{
|
{
|
||||||
ComScope * comScope;
|
ComScope * comScope;
|
||||||
|
|
||||||
@@ -38,13 +35,9 @@ typedef struct SDRWhiteLevel
|
|||||||
bool shareable;
|
bool shareable;
|
||||||
ID3D11PixelShader ** pshader;
|
ID3D11PixelShader ** pshader;
|
||||||
ID3D11SamplerState ** sampler;
|
ID3D11SamplerState ** sampler;
|
||||||
ID3D11Buffer ** buffer;
|
|
||||||
|
|
||||||
DISPLAYCONFIG_PATH_INFO displayPathInfo;
|
|
||||||
float sdrWhiteLevel;
|
|
||||||
}
|
}
|
||||||
SDRWhiteLevel;
|
HDR16to10;
|
||||||
static SDRWhiteLevel this = {0};
|
static HDR16to10 this = {0};
|
||||||
|
|
||||||
#define comRef_toGlobal(dst, src) \
|
#define comRef_toGlobal(dst, src) \
|
||||||
_comRef_toGlobal(this.comScope, dst, src)
|
_comRef_toGlobal(this.comScope, dst, src)
|
||||||
@@ -54,23 +47,16 @@ typedef struct
|
|||||||
ID3D11Texture2D ** tex;
|
ID3D11Texture2D ** tex;
|
||||||
ID3D11RenderTargetView ** target;
|
ID3D11RenderTargetView ** target;
|
||||||
}
|
}
|
||||||
SDRWhiteLevelInst;
|
HDR16to10Inst;
|
||||||
|
|
||||||
struct ShaderConsts
|
static bool hdr16to10_setup(
|
||||||
{
|
|
||||||
float sdrWhiteLevel;
|
|
||||||
}
|
|
||||||
__attribute__((aligned(16)));
|
|
||||||
|
|
||||||
static void updateConsts(void);
|
|
||||||
|
|
||||||
static bool sdrWhiteLevel_setup(
|
|
||||||
ID3D11Device ** device,
|
ID3D11Device ** device,
|
||||||
ID3D11DeviceContext ** context,
|
ID3D11DeviceContext ** context,
|
||||||
IDXGIOutput ** output,
|
IDXGIOutput ** output,
|
||||||
bool shareable
|
bool shareable
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
(void)output;
|
||||||
bool result = false;
|
bool result = false;
|
||||||
HRESULT status;
|
HRESULT status;
|
||||||
|
|
||||||
@@ -78,41 +64,30 @@ static bool sdrWhiteLevel_setup(
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.shareable = shareable;
|
this.shareable = shareable;
|
||||||
|
|
||||||
comRef_initGlobalScope(11, this.comScope);
|
comRef_initGlobalScope(10, this.comScope);
|
||||||
comRef_scopePush(11);
|
comRef_scopePush(10);
|
||||||
|
|
||||||
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 (!display_getPathInfo(desc1.Monitor, &this.displayPathInfo))
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("Failed to get the display path info");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char * pshaderSrc =
|
static const char * pshaderSrc =
|
||||||
"Texture2D gInputTexture : register(t0);\n"
|
"Texture2D gInputTexture : register(t0);\n"
|
||||||
"SamplerState gSamplerState : register(s0);\n"
|
"SamplerState gSamplerState : register(s0);\n"
|
||||||
"cbuffer gConsts : register(b0)\n"
|
"static const float PQ_m1 = 0.1593017578125;\n"
|
||||||
"{\n"
|
"static const float PQ_m2 = 78.84375;\n"
|
||||||
" float SDRWhiteLevel;"
|
"static const float PQ_c1 = 0.8359375;\n"
|
||||||
"};\n"
|
"static const float PQ_c2 = 18.8515625;\n"
|
||||||
"\n"
|
"static const float PQ_c3 = 18.6875;\n"
|
||||||
"float4 main(\n"
|
"float4 main(\n"
|
||||||
" float4 position : SV_POSITION,\n"
|
" float4 position : SV_POSITION,\n"
|
||||||
" float2 texCoord : TEXCOORD0) : SV_TARGET"
|
" float2 texCoord : TEXCOORD0) : SV_TARGET"
|
||||||
"{\n"
|
"{\n"
|
||||||
" float4 color = gInputTexture.Sample(gSamplerState, texCoord);\n"
|
" float4 color = gInputTexture.Sample(gSamplerState, texCoord);\n"
|
||||||
" color.rgb *= SDRWhiteLevel;\n"
|
" float3 linear709 = color.rgb * (80.0 / 10000.0);\n"
|
||||||
|
" float3 linear2020 = float3(\n"
|
||||||
|
" dot(linear709, float3(0.6274039, 0.3292830, 0.0433131)),\n"
|
||||||
|
" dot(linear709, float3(0.0690973, 0.9195404, 0.0113623)),\n"
|
||||||
|
" dot(linear709, float3(0.0163914, 0.0880133, 0.8955953)));\n"
|
||||||
|
" float3 p = pow(max(linear2020, 0.0), PQ_m1);\n"
|
||||||
|
" color.rgb = pow((PQ_c1 + PQ_c2 * p) /\n"
|
||||||
|
" (1.0 + PQ_c3 * p), PQ_m2);\n"
|
||||||
" return color;\n"
|
" return color;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
@@ -156,29 +131,7 @@ static bool sdrWhiteLevel_setup(
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11_BUFFER_DESC bufferDesc =
|
|
||||||
{
|
|
||||||
.ByteWidth = sizeof(struct ShaderConsts),
|
|
||||||
.Usage = D3D11_USAGE_DEFAULT,
|
|
||||||
.BindFlags = D3D11_BIND_CONSTANT_BUFFER,
|
|
||||||
};
|
|
||||||
|
|
||||||
comRef_defineLocal(ID3D11Buffer, buffer);
|
|
||||||
status = ID3D11Device_CreateBuffer(
|
|
||||||
*this.device, &bufferDesc, NULL,
|
|
||||||
buffer);
|
|
||||||
|
|
||||||
if (FAILED(status))
|
|
||||||
{
|
|
||||||
DEBUG_WINERROR("Failed to create the constant buffer", status);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
comRef_toGlobal(this.sampler, sampler);
|
comRef_toGlobal(this.sampler, sampler);
|
||||||
comRef_toGlobal(this.buffer , buffer );
|
|
||||||
|
|
||||||
updateConsts();
|
|
||||||
DEBUG_INFO("SDR White Level : %f" , this.sdrWhiteLevel);
|
|
||||||
|
|
||||||
result = true;
|
result = true;
|
||||||
|
|
||||||
@@ -187,15 +140,15 @@ exit:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdrWhiteLevel_finish(void)
|
static void hdr16to10_finish(void)
|
||||||
{
|
{
|
||||||
comRef_freeScope(&this.comScope);
|
comRef_freeScope(&this.comScope);
|
||||||
memset(&this, 0, sizeof(this));
|
memset(&this, 0, sizeof(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sdrWhiteLevel_init(void ** opaque)
|
static bool hdr16to10_init(void ** opaque)
|
||||||
{
|
{
|
||||||
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)calloc(1, sizeof(*inst));
|
HDR16to10Inst * inst = (HDR16to10Inst *)calloc(1, sizeof(*inst));
|
||||||
if (!inst)
|
if (!inst)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to allocate memory");
|
DEBUG_ERROR("Failed to allocate memory");
|
||||||
@@ -206,34 +159,26 @@ static bool sdrWhiteLevel_init(void ** opaque)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdrWhiteLevel_free(void * opaque)
|
static void hdr16to10_free(void * opaque)
|
||||||
{
|
{
|
||||||
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)opaque;
|
HDR16to10Inst * inst = (HDR16to10Inst *)opaque;
|
||||||
comRef_release(inst->target);
|
comRef_release(inst->target);
|
||||||
comRef_release(inst->tex );
|
comRef_release(inst->tex );
|
||||||
free(inst);
|
free(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updateConsts(void)
|
static bool hdr16to10_configure(void * opaque,
|
||||||
{
|
|
||||||
float nits = display_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 bool sdrWhiteLevel_configure(void * opaque,
|
|
||||||
int * width, int * height,
|
int * width, int * height,
|
||||||
int * cols , int * rows,
|
int * cols , int * rows,
|
||||||
CaptureFormat * format)
|
CaptureFormat * format)
|
||||||
{
|
{
|
||||||
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)opaque;
|
HDR16to10Inst * inst = (HDR16to10Inst *)opaque;
|
||||||
|
if (*format != CAPTURE_FMT_RGBA16F)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("HDR16to10 requires an FP16 scRGB source");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (inst->tex)
|
if (inst->tex)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -295,12 +240,10 @@ fail:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ID3D11Texture2D * sdrWhiteLevel_run(void * opaque,
|
static ID3D11Texture2D * hdr16to10_run(void * opaque,
|
||||||
ID3D11ShaderResourceView * srv)
|
ID3D11ShaderResourceView * srv)
|
||||||
{
|
{
|
||||||
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)opaque;
|
HDR16to10Inst * inst = (HDR16to10Inst *)opaque;
|
||||||
|
|
||||||
updateConsts();
|
|
||||||
|
|
||||||
// set the pixel shader & resource
|
// set the pixel shader & resource
|
||||||
ID3D11DeviceContext_PSSetShader(*this.context, *this.pshader, NULL, 0);
|
ID3D11DeviceContext_PSSetShader(*this.context, *this.pshader, NULL, 0);
|
||||||
@@ -308,7 +251,6 @@ static ID3D11Texture2D * sdrWhiteLevel_run(void * opaque,
|
|||||||
// set the pixel shader resources
|
// set the pixel shader resources
|
||||||
ID3D11DeviceContext_PSSetShaderResources(*this.context, 0, 1, &srv );
|
ID3D11DeviceContext_PSSetShaderResources(*this.context, 0, 1, &srv );
|
||||||
ID3D11DeviceContext_PSSetSamplers (*this.context, 0, 1, this.sampler);
|
ID3D11DeviceContext_PSSetSamplers (*this.context, 0, 1, this.sampler);
|
||||||
ID3D11DeviceContext_PSSetConstantBuffers(*this.context, 0, 1, this.buffer );
|
|
||||||
|
|
||||||
// set the render target
|
// set the render target
|
||||||
ID3D11DeviceContext_OMSetRenderTargets(*this.context, 1, inst->target, NULL);
|
ID3D11DeviceContext_OMSetRenderTargets(*this.context, 1, inst->target, NULL);
|
||||||
@@ -316,14 +258,14 @@ static ID3D11Texture2D * sdrWhiteLevel_run(void * opaque,
|
|||||||
return *inst->tex;
|
return *inst->tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
DXGIPostProcess DXGIPP_SDRWhiteLevel =
|
DXGIPostProcess DXGIPP_HDR16to10 =
|
||||||
{
|
{
|
||||||
.name = "SDRWhiteLevel",
|
.name = "HDR16to10",
|
||||||
.earlyInit = NULL,
|
.earlyInit = NULL,
|
||||||
.setup = sdrWhiteLevel_setup,
|
.setup = hdr16to10_setup,
|
||||||
.init = sdrWhiteLevel_init,
|
.init = hdr16to10_init,
|
||||||
.free = sdrWhiteLevel_free,
|
.free = hdr16to10_free,
|
||||||
.configure = sdrWhiteLevel_configure,
|
.configure = hdr16to10_configure,
|
||||||
.run = sdrWhiteLevel_run,
|
.run = hdr16to10_run,
|
||||||
.finish = sdrWhiteLevel_finish
|
.finish = hdr16to10_finish
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -107,6 +107,18 @@ struct app
|
|||||||
unsigned int readIndex;
|
unsigned int readIndex;
|
||||||
bool frameValid;
|
bool frameValid;
|
||||||
uint32_t frameSerial;
|
uint32_t frameSerial;
|
||||||
|
uint32_t formatVer;
|
||||||
|
unsigned int captureFormatVer;
|
||||||
|
bool hdr;
|
||||||
|
bool hdrPQ;
|
||||||
|
bool hdrMetadata;
|
||||||
|
uint16_t hdrDisplayPrimary[3][2];
|
||||||
|
uint16_t hdrWhitePoint[2];
|
||||||
|
uint32_t hdrMaxDisplayLuminance;
|
||||||
|
uint32_t hdrMinDisplayLuminance;
|
||||||
|
uint32_t hdrMaxContentLightLevel;
|
||||||
|
uint32_t hdrMaxFrameAverageLightLevel;
|
||||||
|
_Atomic(uint32_t) sdrWhiteLevel;
|
||||||
|
|
||||||
CaptureInterface * iface;
|
CaptureInterface * iface;
|
||||||
bool captureStarted;
|
bool captureStarted;
|
||||||
@@ -278,9 +290,44 @@ static bool sendFrame(CaptureResult result, bool * restart)
|
|||||||
}
|
}
|
||||||
|
|
||||||
KVMFRFrame * fi = app.frame[app.captureIndex];
|
KVMFRFrame * fi = app.frame[app.captureIndex];
|
||||||
|
const uint32_t sdrWhiteLevel = frame.sdrWhiteLevel ?
|
||||||
|
frame.sdrWhiteLevel : KVMFR_SDR_WHITE_LEVEL_DEFAULT;
|
||||||
|
const bool metadataChanged =
|
||||||
|
app.hdrMetadata != frame.hdrMetadata ||
|
||||||
|
(frame.hdrMetadata &&
|
||||||
|
(memcmp(app.hdrDisplayPrimary, frame.hdrDisplayPrimary,
|
||||||
|
sizeof(app.hdrDisplayPrimary)) != 0 ||
|
||||||
|
memcmp(app.hdrWhitePoint, frame.hdrWhitePoint,
|
||||||
|
sizeof(app.hdrWhitePoint)) != 0 ||
|
||||||
|
app.hdrMaxDisplayLuminance != frame.hdrMaxDisplayLuminance ||
|
||||||
|
app.hdrMinDisplayLuminance != frame.hdrMinDisplayLuminance ||
|
||||||
|
app.hdrMaxContentLightLevel != frame.hdrMaxContentLightLevel ||
|
||||||
|
app.hdrMaxFrameAverageLightLevel !=
|
||||||
|
frame.hdrMaxFrameAverageLightLevel));
|
||||||
|
|
||||||
|
if (!app.frameValid || app.captureFormatVer != frame.formatVer ||
|
||||||
|
app.hdr != frame.hdr || app.hdrPQ != frame.hdrPQ ||
|
||||||
|
metadataChanged || atomic_load(&app.sdrWhiteLevel) != sdrWhiteLevel)
|
||||||
|
++app.formatVer;
|
||||||
|
|
||||||
|
app.captureFormatVer = frame.formatVer;
|
||||||
|
app.hdr = frame.hdr;
|
||||||
|
app.hdrPQ = frame.hdrPQ;
|
||||||
|
app.hdrMetadata = frame.hdrMetadata;
|
||||||
|
memcpy(app.hdrDisplayPrimary, frame.hdrDisplayPrimary,
|
||||||
|
sizeof(app.hdrDisplayPrimary));
|
||||||
|
memcpy(app.hdrWhitePoint, frame.hdrWhitePoint,
|
||||||
|
sizeof(app.hdrWhitePoint));
|
||||||
|
app.hdrMaxDisplayLuminance = frame.hdrMaxDisplayLuminance;
|
||||||
|
app.hdrMinDisplayLuminance = frame.hdrMinDisplayLuminance;
|
||||||
|
app.hdrMaxContentLightLevel = frame.hdrMaxContentLightLevel;
|
||||||
|
app.hdrMaxFrameAverageLightLevel = frame.hdrMaxFrameAverageLightLevel;
|
||||||
|
atomic_store(&app.sdrWhiteLevel, sdrWhiteLevel);
|
||||||
|
|
||||||
KVMFRFrameFlags flags =
|
KVMFRFrameFlags flags =
|
||||||
(frame.hdr ? FRAME_FLAG_HDR : 0) |
|
(frame.hdr ? FRAME_FLAG_HDR : 0) |
|
||||||
(frame.hdrPQ ? FRAME_FLAG_HDR_PQ : 0);
|
(frame.hdrPQ ? FRAME_FLAG_HDR_PQ : 0) |
|
||||||
|
(frame.hdrMetadata ? FRAME_FLAG_HDR_METADATA : 0);
|
||||||
|
|
||||||
switch(frame.format)
|
switch(frame.format)
|
||||||
{
|
{
|
||||||
@@ -335,7 +382,7 @@ static bool sendFrame(CaptureResult result, bool * restart)
|
|||||||
if (frame.truncated)
|
if (frame.truncated)
|
||||||
flags |= FRAME_FLAG_TRUNCATED;
|
flags |= FRAME_FLAG_TRUNCATED;
|
||||||
|
|
||||||
fi->formatVer = frame.formatVer;
|
fi->formatVer = app.formatVer;
|
||||||
fi->frameSerial = app.frameSerial++;
|
fi->frameSerial = app.frameSerial++;
|
||||||
fi->screenWidth = frame.screenWidth;
|
fi->screenWidth = frame.screenWidth;
|
||||||
fi->screenHeight = frame.screenHeight;
|
fi->screenHeight = frame.screenHeight;
|
||||||
@@ -347,7 +394,28 @@ static bool sendFrame(CaptureResult result, bool * restart)
|
|||||||
fi->pitch = frame.pitch;
|
fi->pitch = frame.pitch;
|
||||||
// fi->offset is initialized at startup
|
// fi->offset is initialized at startup
|
||||||
fi->flags = flags;
|
fi->flags = flags;
|
||||||
fi->sdrWhiteLevel = KVMFR_SDR_WHITE_LEVEL_DEFAULT;
|
fi->sdrWhiteLevel = sdrWhiteLevel;
|
||||||
|
if (frame.hdrMetadata)
|
||||||
|
{
|
||||||
|
memcpy(fi->hdrDisplayPrimary, frame.hdrDisplayPrimary,
|
||||||
|
sizeof(fi->hdrDisplayPrimary));
|
||||||
|
memcpy(fi->hdrWhitePoint, frame.hdrWhitePoint,
|
||||||
|
sizeof(fi->hdrWhitePoint));
|
||||||
|
fi->hdrMaxDisplayLuminance = frame.hdrMaxDisplayLuminance;
|
||||||
|
fi->hdrMinDisplayLuminance = frame.hdrMinDisplayLuminance;
|
||||||
|
fi->hdrMaxContentLightLevel = frame.hdrMaxContentLightLevel;
|
||||||
|
fi->hdrMaxFrameAverageLightLevel =
|
||||||
|
frame.hdrMaxFrameAverageLightLevel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset(fi->hdrDisplayPrimary, 0, sizeof(fi->hdrDisplayPrimary));
|
||||||
|
memset(fi->hdrWhitePoint, 0, sizeof(fi->hdrWhitePoint));
|
||||||
|
fi->hdrMaxDisplayLuminance = 0;
|
||||||
|
fi->hdrMinDisplayLuminance = 0;
|
||||||
|
fi->hdrMaxContentLightLevel = 0;
|
||||||
|
fi->hdrMaxFrameAverageLightLevel = 0;
|
||||||
|
}
|
||||||
fi->damageRectsCount = frame.damageRectsCount;
|
fi->damageRectsCount = frame.damageRectsCount;
|
||||||
memcpy(fi->damageRects, frame.damageRects,
|
memcpy(fi->damageRects, frame.damageRects,
|
||||||
frame.damageRectsCount * sizeof(FrameDamageRect));
|
frame.damageRectsCount * sizeof(FrameDamageRect));
|
||||||
@@ -515,7 +583,7 @@ static void sendPointer(bool newClient)
|
|||||||
KVMFRCursor *cursor = lgmpHostMemPtr(mem);
|
KVMFRCursor *cursor = lgmpHostMemPtr(mem);
|
||||||
cursor->x = app.pointerInfo.x;
|
cursor->x = app.pointerInfo.x;
|
||||||
cursor->y = app.pointerInfo.y;
|
cursor->y = app.pointerInfo.y;
|
||||||
cursor->sdrWhiteLevel = KVMFR_SDR_WHITE_LEVEL_DEFAULT;
|
cursor->sdrWhiteLevel = atomic_load(&app.sdrWhiteLevel);
|
||||||
|
|
||||||
const uint32_t flags = CURSOR_FLAG_POSITION | CURSOR_FLAG_VISIBLE_VALID |
|
const uint32_t flags = CURSOR_FLAG_POSITION | CURSOR_FLAG_VISIBLE_VALID |
|
||||||
(app.pointerShapeValid ? CURSOR_FLAG_SHAPE : 0) |
|
(app.pointerShapeValid ? CURSOR_FLAG_SHAPE : 0) |
|
||||||
@@ -540,7 +608,7 @@ static void sendPointer(bool newClient)
|
|||||||
app.pointerIndex = 0;
|
app.pointerIndex = 0;
|
||||||
}
|
}
|
||||||
KVMFRCursor *cursor = lgmpHostMemPtr(mem);
|
KVMFRCursor *cursor = lgmpHostMemPtr(mem);
|
||||||
cursor->sdrWhiteLevel = KVMFR_SDR_WHITE_LEVEL_DEFAULT;
|
cursor->sdrWhiteLevel = atomic_load(&app.sdrWhiteLevel);
|
||||||
|
|
||||||
if (app.pointerInfo.positionUpdate || newClient)
|
if (app.pointerInfo.positionUpdate || newClient)
|
||||||
{
|
{
|
||||||
@@ -795,6 +863,8 @@ static bool lgmpSetup(struct IVSHMEM * shmDev)
|
|||||||
app.frameBuffer[i] = (FrameBuffer *)(((uint8_t*)app.frame[i]) + alignOffset);
|
app.frameBuffer[i] = (FrameBuffer *)(((uint8_t*)app.frame[i]) + alignOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atomic_store(&app.sdrWhiteLevel,
|
||||||
|
KVMFR_SDR_WHITE_LEVEL_DEFAULT);
|
||||||
atomic_store(&app.lgmpTimerState, LGMP_TIMER_STATE_OK);
|
atomic_store(&app.lgmpTimerState, LGMP_TIMER_STATE_OK);
|
||||||
if (!lgCreateTimer(10, lgmpTimer, NULL, &app.lgmpTimer))
|
if (!lgCreateTimer(10, lgmpTimer, NULL, &app.lgmpTimer))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user