mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-07-21 06:42:02 +00:00
[idd/client/obs] hdr: wire up the SdrWhiteLevel from the capture
This commit is contained in:
@@ -92,6 +92,7 @@ typedef struct LG_RendererFormat
|
|||||||
uint32_t hdrMinDisplayLuminance;
|
uint32_t hdrMinDisplayLuminance;
|
||||||
uint32_t hdrMaxContentLightLevel;
|
uint32_t hdrMaxContentLightLevel;
|
||||||
uint32_t hdrMaxFrameAverageLightLevel;
|
uint32_t hdrMaxFrameAverageLightLevel;
|
||||||
|
uint32_t sdrWhiteLevel;
|
||||||
}
|
}
|
||||||
LG_RendererFormat;
|
LG_RendererFormat;
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ struct CursorTex
|
|||||||
GLuint uRotate;
|
GLuint uRotate;
|
||||||
GLuint uCBMode;
|
GLuint uCBMode;
|
||||||
GLint uMapSDRtoPQ;
|
GLint uMapSDRtoPQ;
|
||||||
|
GLint uSDRWhiteLevel;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CursorPos
|
struct CursorPos
|
||||||
@@ -79,6 +80,7 @@ struct EGL_Cursor
|
|||||||
_Atomic(struct CursorSize) size;
|
_Atomic(struct CursorSize) size;
|
||||||
_Atomic(float) scale;
|
_Atomic(float) scale;
|
||||||
_Atomic(bool) mapSDRtoPQ;
|
_Atomic(bool) mapSDRtoPQ;
|
||||||
|
_Atomic(float) sdrWhiteLevel;
|
||||||
|
|
||||||
struct CursorTex norm;
|
struct CursorTex norm;
|
||||||
struct CursorTex mono;
|
struct CursorTex mono;
|
||||||
@@ -108,11 +110,12 @@ static bool cursorTexInit(struct CursorTex * t,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->uMousePos = egl_shaderGetUniform(t->shader, "mouse" );
|
t->uMousePos = egl_shaderGetUniform(t->shader, "mouse" );
|
||||||
t->uScale = egl_shaderGetUniform(t->shader, "scale" );
|
t->uScale = egl_shaderGetUniform(t->shader, "scale" );
|
||||||
t->uRotate = egl_shaderGetUniform(t->shader, "rotate" );
|
t->uRotate = egl_shaderGetUniform(t->shader, "rotate" );
|
||||||
t->uCBMode = egl_shaderGetUniform(t->shader, "cbMode" );
|
t->uCBMode = egl_shaderGetUniform(t->shader, "cbMode" );
|
||||||
t->uMapSDRtoPQ = egl_shaderGetUniform(t->shader, "mapSDRtoPQ");
|
t->uMapSDRtoPQ = egl_shaderGetUniform(t->shader, "mapSDRtoPQ" );
|
||||||
|
t->uSDRWhiteLevel = egl_shaderGetUniform(t->shader, "sdrWhiteLevel");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -121,11 +124,12 @@ static inline void setCursorTexUniforms(EGL_Cursor * cursor,
|
|||||||
struct CursorTex * t, bool mono, float x, float y,
|
struct CursorTex * t, bool mono, float x, float y,
|
||||||
float w, float h, float scale)
|
float w, float h, float scale)
|
||||||
{
|
{
|
||||||
glUniform4f(t->uMousePos , x, y, w, mono ? h / 2 : h);
|
glUniform4f(t->uMousePos , x, y, w, mono ? h / 2 : h);
|
||||||
glUniform1f(t->uScale , scale);
|
glUniform1f(t->uScale , scale);
|
||||||
glUniform1i(t->uRotate , cursor->rotate);
|
glUniform1i(t->uRotate , cursor->rotate);
|
||||||
glUniform1i(t->uCBMode , cursor->cbMode);
|
glUniform1i(t->uCBMode , cursor->cbMode);
|
||||||
glUniform1i(t->uMapSDRtoPQ, !mono && atomic_load(&cursor->mapSDRtoPQ));
|
glUniform1i(t->uMapSDRtoPQ , !mono && atomic_load(&cursor->mapSDRtoPQ));
|
||||||
|
glUniform1f(t->uSDRWhiteLevel, atomic_load(&cursor->sdrWhiteLevel));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cursorTexFree(struct CursorTex * t)
|
static void cursorTexFree(struct CursorTex * t)
|
||||||
@@ -174,6 +178,8 @@ bool egl_cursorInit(EGL_Cursor ** cursor)
|
|||||||
atomic_init(&(*cursor)->size , size );
|
atomic_init(&(*cursor)->size , size );
|
||||||
atomic_init(&(*cursor)->scale , 1.0f );
|
atomic_init(&(*cursor)->scale , 1.0f );
|
||||||
atomic_init(&(*cursor)->mapSDRtoPQ, false);
|
atomic_init(&(*cursor)->mapSDRtoPQ, false);
|
||||||
|
atomic_init(&(*cursor)->sdrWhiteLevel,
|
||||||
|
(float)KVMFR_SDR_WHITE_LEVEL_DEFAULT);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -435,7 +441,10 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void egl_cursorSetHDRState(EGL_Cursor * cursor, bool hdrActive, bool hdrPQ)
|
void egl_cursorSetHDRState(EGL_Cursor * cursor, bool hdrActive, bool hdrPQ,
|
||||||
|
float sdrWhiteLevel)
|
||||||
{
|
{
|
||||||
|
atomic_store(&cursor->sdrWhiteLevel, sdrWhiteLevel > 0.0f ?
|
||||||
|
sdrWhiteLevel : (float)KVMFR_SDR_WHITE_LEVEL_DEFAULT);
|
||||||
atomic_store(&cursor->mapSDRtoPQ, hdrActive && hdrPQ);
|
atomic_store(&cursor->mapSDRtoPQ, hdrActive && hdrPQ);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,4 +53,5 @@ void egl_cursorSetState(EGL_Cursor * cursor, const bool visible,
|
|||||||
struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
||||||
LG_RendererRotate rotate, int width, int height);
|
LG_RendererRotate rotate, int width, int height);
|
||||||
|
|
||||||
void egl_cursorSetHDRState(EGL_Cursor * cursor, bool hdrActive, bool hdrPQ);
|
void egl_cursorSetHDRState(EGL_Cursor * cursor, bool hdrActive, bool hdrPQ,
|
||||||
|
float sdrWhiteLevel);
|
||||||
|
|||||||
@@ -631,7 +631,8 @@ static bool egl_onFrameFormat(LG_Renderer * renderer, const LG_RendererFormat fo
|
|||||||
egl_desktopSetNativeHDR(this->desktop, useNativeHDR);
|
egl_desktopSetNativeHDR(this->desktop, useNativeHDR);
|
||||||
|
|
||||||
// Tell the cursor shader whether to map SDR cursor colors into PQ
|
// Tell the cursor shader whether to map SDR cursor colors into PQ
|
||||||
egl_cursorSetHDRState(this->cursor, useNativeHDR, format.hdrPQ);
|
egl_cursorSetHDRState(this->cursor, useNativeHDR, format.hdrPQ,
|
||||||
|
format.sdrWhiteLevel);
|
||||||
|
|
||||||
egl_update_scale_type(this);
|
egl_update_scale_type(this);
|
||||||
egl_damageSetup(this->damage, format.frameWidth, format.frameHeight);
|
egl_damageSetup(this->damage, format.frameWidth, format.frameHeight);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ out vec4 color;
|
|||||||
uniform sampler2D sampler1;
|
uniform sampler2D sampler1;
|
||||||
uniform float scale;
|
uniform float scale;
|
||||||
uniform bool mapSDRtoPQ;
|
uniform bool mapSDRtoPQ;
|
||||||
|
uniform float sdrWhiteLevel;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
@@ -32,7 +33,7 @@ void main()
|
|||||||
if (mapSDRtoPQ)
|
if (mapSDRtoPQ)
|
||||||
{
|
{
|
||||||
vec3 linear = bt709to2020(srgb2lin(tmp.rgb));
|
vec3 linear = bt709to2020(srgb2lin(tmp.rgb));
|
||||||
tmp.rgb = lin2pq(linear * (203.0 / 10000.0));
|
tmp.rgb = lin2pq(linear * (sdrWhiteLevel / 10000.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
color = tmp;
|
color = tmp;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ uniform sampler2D sampler1;
|
|||||||
uniform float scale;
|
uniform float scale;
|
||||||
uniform int cbMode;
|
uniform int cbMode;
|
||||||
uniform bool mapSDRtoPQ;
|
uniform bool mapSDRtoPQ;
|
||||||
|
uniform float sdrWhiteLevel;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
@@ -38,7 +39,7 @@ void main()
|
|||||||
// then premultiply again so the blend operation remains valid.
|
// then premultiply again so the blend operation remains valid.
|
||||||
vec3 srgb = clamp(color.rgb / color.a, 0.0, 1.0);
|
vec3 srgb = clamp(color.rgb / color.a, 0.0, 1.0);
|
||||||
vec3 linear = bt709to2020(srgb2lin(srgb));
|
vec3 linear = bt709to2020(srgb2lin(srgb));
|
||||||
color.rgb = lin2pq(linear * (203.0 / 10000.0)) * color.a;
|
color.rgb = lin2pq(linear * (sdrWhiteLevel / 10000.0)) * color.a;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
color.rgb = vec3(0.0);
|
color.rgb = vec3(0.0);
|
||||||
|
|||||||
@@ -629,17 +629,19 @@ int main_frameThread(void * unused)
|
|||||||
if (!g_state.formatValid || frame->formatVer != formatVer)
|
if (!g_state.formatValid || frame->formatVer != formatVer)
|
||||||
{
|
{
|
||||||
// setup the renderer format with the frame format details
|
// setup the renderer format with the frame format details
|
||||||
lgrFormat.type = frame->type;
|
lgrFormat.type = frame->type;
|
||||||
lgrFormat.screenWidth = frame->screenWidth;
|
lgrFormat.screenWidth = frame->screenWidth;
|
||||||
lgrFormat.screenHeight = frame->screenHeight;
|
lgrFormat.screenHeight = frame->screenHeight;
|
||||||
lgrFormat.dataWidth = frame->dataWidth;
|
lgrFormat.dataWidth = frame->dataWidth;
|
||||||
lgrFormat.dataHeight = frame->dataHeight;
|
lgrFormat.dataHeight = frame->dataHeight;
|
||||||
lgrFormat.frameWidth = frame->frameWidth;
|
lgrFormat.frameWidth = frame->frameWidth;
|
||||||
lgrFormat.frameHeight = frame->frameHeight;
|
lgrFormat.frameHeight = frame->frameHeight;
|
||||||
lgrFormat.stride = frame->stride;
|
lgrFormat.stride = frame->stride;
|
||||||
lgrFormat.pitch = frame->pitch;
|
lgrFormat.pitch = frame->pitch;
|
||||||
lgrFormat.hdr = frame->flags & FRAME_FLAG_HDR;
|
lgrFormat.hdr = frame->flags & FRAME_FLAG_HDR;
|
||||||
lgrFormat.hdrPQ = frame->flags & FRAME_FLAG_HDR_PQ;
|
lgrFormat.hdrPQ = frame->flags & FRAME_FLAG_HDR_PQ;
|
||||||
|
lgrFormat.sdrWhiteLevel = frame->sdrWhiteLevel ?
|
||||||
|
frame->sdrWhiteLevel : KVMFR_SDR_WHITE_LEVEL_DEFAULT;
|
||||||
|
|
||||||
if (lgrFormat.hdr)
|
if (lgrFormat.hdr)
|
||||||
{
|
{
|
||||||
@@ -728,14 +730,15 @@ int main_frameThread(void * unused)
|
|||||||
g_state.formatValid = true;
|
g_state.formatValid = true;
|
||||||
formatVer = frame->formatVer;
|
formatVer = frame->formatVer;
|
||||||
|
|
||||||
DEBUG_INFO("Format: %s %ux%u (%ux%u) stride:%u pitch:%u rotation:%d hdr:%d pq:%d",
|
DEBUG_INFO("Format: %s %ux%u (%ux%u) stride:%u pitch:%u rotation:%d hdr:%d pq:%d sdrWhite:%u nits",
|
||||||
FrameTypeStr[frame->type],
|
FrameTypeStr[frame->type],
|
||||||
frame->frameWidth, frame->frameHeight,
|
frame->frameWidth, frame->frameHeight,
|
||||||
frame->dataWidth , frame->dataHeight ,
|
frame->dataWidth , frame->dataHeight ,
|
||||||
frame->stride, frame->pitch,
|
frame->stride, frame->pitch,
|
||||||
frame->rotation,
|
frame->rotation,
|
||||||
frame->flags & FRAME_FLAG_HDR ? 1 : 0,
|
frame->flags & FRAME_FLAG_HDR ? 1 : 0,
|
||||||
frame->flags & FRAME_FLAG_HDR_PQ ? 1 : 0);
|
frame->flags & FRAME_FLAG_HDR_PQ ? 1 : 0,
|
||||||
|
lgrFormat.sdrWhiteLevel);
|
||||||
|
|
||||||
LG_LOCK(g_state.lgrLock);
|
LG_LOCK(g_state.lgrLock);
|
||||||
if (!RENDERER(onFrameFormat, lgrFormat))
|
if (!RENDERER(onFrameFormat, lgrFormat))
|
||||||
|
|||||||
@@ -28,7 +28,11 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define KVMFR_MAGIC "KVMFR---"
|
#define KVMFR_MAGIC "KVMFR---"
|
||||||
#define KVMFR_VERSION 20
|
#define KVMFR_VERSION 21
|
||||||
|
|
||||||
|
// Fallback used by producers that cannot report the source display's SDR
|
||||||
|
// white level. IDD frames override this with IDDCX_METADATA2::SdrWhiteLevel.
|
||||||
|
#define KVMFR_SDR_WHITE_LEVEL_DEFAULT 203u
|
||||||
|
|
||||||
#define KVMFR_MAX_DAMAGE_RECTS 64
|
#define KVMFR_MAX_DAMAGE_RECTS 64
|
||||||
|
|
||||||
@@ -175,6 +179,10 @@ typedef struct KVMFRFrame
|
|||||||
uint32_t hdrMinDisplayLuminance; // Min mastering display luminance (0.0001 cd/m²)
|
uint32_t hdrMinDisplayLuminance; // Min mastering display luminance (0.0001 cd/m²)
|
||||||
uint32_t hdrMaxContentLightLevel; // MaxCLL (cd/m²)
|
uint32_t hdrMaxContentLightLevel; // MaxCLL (cd/m²)
|
||||||
uint32_t hdrMaxFrameAverageLightLevel; // MaxFALL (cd/m²)
|
uint32_t hdrMaxFrameAverageLightLevel; // MaxFALL (cd/m²)
|
||||||
|
|
||||||
|
// White level in nits for SDR content composited into an HDR frame, such as
|
||||||
|
// the hardware cursor. Valid for all frames; SDR modes normally report 80.
|
||||||
|
uint32_t sdrWhiteLevel;
|
||||||
}
|
}
|
||||||
KVMFRFrame;
|
KVMFRFrame;
|
||||||
|
|
||||||
|
|||||||
@@ -347,6 +347,7 @@ 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->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));
|
||||||
|
|||||||
@@ -957,7 +957,8 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
|
|||||||
m_lastHDRMaxDisplayLuminance != dstFormat.maxDisplayLuminance ||
|
m_lastHDRMaxDisplayLuminance != dstFormat.maxDisplayLuminance ||
|
||||||
m_lastHDRMinDisplayLuminance != dstFormat.minDisplayLuminance ||
|
m_lastHDRMinDisplayLuminance != dstFormat.minDisplayLuminance ||
|
||||||
m_lastHDRMaxContentLightLevel != dstFormat.maxContentLightLevel ||
|
m_lastHDRMaxContentLightLevel != dstFormat.maxContentLightLevel ||
|
||||||
m_lastHDRMaxFrameAverageLightLevel != dstFormat.maxFrameAverageLightLevel)
|
m_lastHDRMaxFrameAverageLightLevel != dstFormat.maxFrameAverageLightLevel ||
|
||||||
|
m_lastSDRWhiteLevel != dstFormat.sdrWhiteLevel)
|
||||||
{
|
{
|
||||||
++m_formatVer;
|
++m_formatVer;
|
||||||
}
|
}
|
||||||
@@ -975,6 +976,7 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
|
|||||||
m_lastHDRMinDisplayLuminance = dstFormat.minDisplayLuminance;
|
m_lastHDRMinDisplayLuminance = dstFormat.minDisplayLuminance;
|
||||||
m_lastHDRMaxContentLightLevel = dstFormat.maxContentLightLevel;
|
m_lastHDRMaxContentLightLevel = dstFormat.maxContentLightLevel;
|
||||||
m_lastHDRMaxFrameAverageLightLevel = dstFormat.maxFrameAverageLightLevel;
|
m_lastHDRMaxFrameAverageLightLevel = dstFormat.maxFrameAverageLightLevel;
|
||||||
|
m_lastSDRWhiteLevel = dstFormat.sdrWhiteLevel;
|
||||||
|
|
||||||
if (++m_frameIndex == LGMP_Q_FRAME_LEN)
|
if (++m_frameIndex == LGMP_Q_FRAME_LEN)
|
||||||
m_frameIndex = 0;
|
m_frameIndex = 0;
|
||||||
@@ -1012,6 +1014,7 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
|
|||||||
fi->pitch = pitch;
|
fi->pitch = pitch;
|
||||||
// fi->offset is initialized at startup
|
// fi->offset is initialized at startup
|
||||||
fi->flags = flags;
|
fi->flags = flags;
|
||||||
|
fi->sdrWhiteLevel = dstFormat.sdrWhiteLevel;
|
||||||
fi->rotation = FRAME_ROT_0;
|
fi->rotation = FRAME_ROT_0;
|
||||||
fi->type = dstFormat.format;
|
fi->type = dstFormat.format;
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ private:
|
|||||||
uint32_t m_lastHDRMinDisplayLuminance = 0;
|
uint32_t m_lastHDRMinDisplayLuminance = 0;
|
||||||
uint32_t m_lastHDRMaxContentLightLevel = 0;
|
uint32_t m_lastHDRMaxContentLightLevel = 0;
|
||||||
uint32_t m_lastHDRMaxFrameAverageLightLevel = 0;
|
uint32_t m_lastHDRMaxFrameAverageLightLevel = 0;
|
||||||
|
uint32_t m_lastSDRWhiteLevel = 0;
|
||||||
bool m_lastHDRActive = false;
|
bool m_lastHDRActive = false;
|
||||||
|
|
||||||
void QueryIddCxCapabilities();
|
void QueryIddCxCapabilities();
|
||||||
|
|||||||
@@ -66,14 +66,15 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat, bool * formatCha
|
|||||||
if (formatChanged)
|
if (formatChanged)
|
||||||
*formatChanged = false;
|
*formatChanged = false;
|
||||||
|
|
||||||
if (srcFormat.desc.Width == m_srcFormat.desc.Width &&
|
if (srcFormat.desc.Width == m_srcFormat.desc.Width &&
|
||||||
srcFormat.desc.Height == m_srcFormat.desc.Height &&
|
srcFormat.desc.Height == m_srcFormat.desc.Height &&
|
||||||
srcFormat.desc.Format == m_srcFormat.desc.Format &&
|
srcFormat.desc.Format == m_srcFormat.desc.Format &&
|
||||||
srcFormat.format == m_srcFormat.format &&
|
srcFormat.format == m_srcFormat.format &&
|
||||||
srcFormat.width == m_srcFormat.width &&
|
srcFormat.width == m_srcFormat.width &&
|
||||||
srcFormat.height == m_srcFormat.height &&
|
srcFormat.height == m_srcFormat.height &&
|
||||||
srcFormat.hdr == m_srcFormat.hdr &&
|
srcFormat.hdr == m_srcFormat.hdr &&
|
||||||
srcFormat.hdrPQ == m_srcFormat.hdrPQ)
|
srcFormat.hdrPQ == m_srcFormat.hdrPQ &&
|
||||||
|
srcFormat.sdrWhiteLevel == m_srcFormat.sdrWhiteLevel)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
D12FrameFormat oldDst = m_dstFormat;
|
D12FrameFormat oldDst = m_dstFormat;
|
||||||
@@ -105,14 +106,15 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat, bool * formatCha
|
|||||||
|
|
||||||
m_dstFormat = cur;
|
m_dstFormat = cur;
|
||||||
if (formatChanged)
|
if (formatChanged)
|
||||||
*formatChanged = oldDst.desc.Width != m_dstFormat.desc.Width ||
|
*formatChanged = oldDst.desc.Width != m_dstFormat.desc.Width ||
|
||||||
oldDst.desc.Height != m_dstFormat.desc.Height ||
|
oldDst.desc.Height != m_dstFormat.desc.Height ||
|
||||||
oldDst.desc.Format != m_dstFormat.desc.Format ||
|
oldDst.desc.Format != m_dstFormat.desc.Format ||
|
||||||
oldDst.format != m_dstFormat.format ||
|
oldDst.format != m_dstFormat.format ||
|
||||||
oldDst.width != m_dstFormat.width ||
|
oldDst.width != m_dstFormat.width ||
|
||||||
oldDst.height != m_dstFormat.height ||
|
oldDst.height != m_dstFormat.height ||
|
||||||
oldDst.hdr != m_dstFormat.hdr ||
|
oldDst.hdr != m_dstFormat.hdr ||
|
||||||
oldDst.hdrPQ != m_dstFormat.hdrPQ;
|
oldDst.hdrPQ != m_dstFormat.hdrPQ ||
|
||||||
|
oldDst.sdrWhiteLevel != m_dstFormat.sdrWhiteLevel;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
struct CD3D12Device;
|
struct CD3D12Device;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#include "common/KVMFR.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ struct D12FrameFormat
|
|||||||
FrameType format = FRAME_TYPE_INVALID;
|
FrameType format = FRAME_TYPE_INVALID;
|
||||||
bool hdr = false;
|
bool hdr = false;
|
||||||
bool hdrPQ = false;
|
bool hdrPQ = false;
|
||||||
|
uint32_t sdrWhiteLevel = KVMFR_SDR_WHITE_LEVEL_DEFAULT;
|
||||||
|
|
||||||
// HDR static metadata (SMPTE ST 2086)
|
// HDR static metadata (SMPTE ST 2086)
|
||||||
// Display color primaries in 0.00002 units (xy coordinates)
|
// Display color primaries in 0.00002 units (xy coordinates)
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ bool CSwapChainProcessor::SwapChainThreadCore()
|
|||||||
// Only the buffer2 acquisition path (IddCx 1.10+) reports it; on the legacy
|
// Only the buffer2 acquisition path (IddCx 1.10+) reports it; on the legacy
|
||||||
// path HDR is not available, so default to SDR.
|
// path HDR is not available, so default to SDR.
|
||||||
DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||||
|
UINT sdrWhiteLevel = KVMFR_SDR_WHITE_LEVEL_DEFAULT;
|
||||||
|
|
||||||
#ifdef HAS_IDDCX_110
|
#ifdef HAS_IDDCX_110
|
||||||
if (m_devContext->CanProcessFP16())
|
if (m_devContext->CanProcessFP16())
|
||||||
@@ -179,10 +180,11 @@ bool CSwapChainProcessor::SwapChainThreadCore()
|
|||||||
hr = IddCxSwapChainReleaseAndAcquireBuffer2(m_hSwapChain, &acquireIn, &buffer);
|
hr = IddCxSwapChainReleaseAndAcquireBuffer2(m_hSwapChain, &acquireIn, &buffer);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
frameNumber = buffer.MetaData.PresentationFrameNumber;
|
frameNumber = buffer.MetaData.PresentationFrameNumber;
|
||||||
dirtyRectCount = buffer.MetaData.DirtyRectCount;
|
dirtyRectCount = buffer.MetaData.DirtyRectCount;
|
||||||
surface = buffer.MetaData.pSurface;
|
surface = buffer.MetaData.pSurface;
|
||||||
colorSpace = buffer.MetaData.SurfaceColorSpace;
|
colorSpace = buffer.MetaData.SurfaceColorSpace;
|
||||||
|
sdrWhiteLevel = buffer.MetaData.SdrWhiteLevel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -222,7 +224,7 @@ bool CSwapChainProcessor::SwapChainThreadCore()
|
|||||||
if (frameNumber != lastFrameNumber)
|
if (frameNumber != lastFrameNumber)
|
||||||
{
|
{
|
||||||
lastFrameNumber = frameNumber;
|
lastFrameNumber = frameNumber;
|
||||||
SwapChainNewFrame(surface, dirtyRectCount, colorSpace);
|
SwapChainNewFrame(surface, dirtyRectCount, colorSpace, sdrWhiteLevel);
|
||||||
|
|
||||||
// report that all GPU processing for this frame has been queued
|
// report that all GPU processing for this frame has been queued
|
||||||
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
|
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
|
||||||
@@ -334,7 +336,7 @@ static FrameType GetFrameType(DXGI_FORMAT format)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount,
|
bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount,
|
||||||
DXGI_COLOR_SPACE_TYPE colorSpace)
|
DXGI_COLOR_SPACE_TYPE colorSpace, UINT sdrWhiteLevel)
|
||||||
{
|
{
|
||||||
ComPtr<ID3D11Texture2D> texture;
|
ComPtr<ID3D11Texture2D> texture;
|
||||||
HRESULT hr = acquiredBuffer.As(&texture);
|
HRESULT hr = acquiredBuffer.As(&texture);
|
||||||
@@ -382,10 +384,11 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
|||||||
|
|
||||||
D3D12_RESOURCE_DESC srcDesc = srcRes->GetRes()->GetDesc();
|
D3D12_RESOURCE_DESC srcDesc = srcRes->GetRes()->GetDesc();
|
||||||
D12FrameFormat srcFormat = {};
|
D12FrameFormat srcFormat = {};
|
||||||
srcFormat.desc = srcDesc;
|
srcFormat.desc = srcDesc;
|
||||||
srcFormat.width = (unsigned)srcDesc.Width;
|
srcFormat.width = (unsigned)srcDesc.Width;
|
||||||
srcFormat.height = srcDesc.Height;
|
srcFormat.height = srcDesc.Height;
|
||||||
srcFormat.format = GetFrameType(srcDesc.Format);
|
srcFormat.format = GetFrameType(srcDesc.Format);
|
||||||
|
srcFormat.sdrWhiteLevel = sdrWhiteLevel;
|
||||||
|
|
||||||
switch (colorSpace)
|
switch (colorSpace)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ private:
|
|||||||
static void CompletionFunction(
|
static void CompletionFunction(
|
||||||
CD3D12CommandQueue * queue, bool result, void * param1, void * param2);
|
CD3D12CommandQueue * queue, bool result, void * param1, void * param2);
|
||||||
bool SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount,
|
bool SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount,
|
||||||
DXGI_COLOR_SPACE_TYPE colorSpace);
|
DXGI_COLOR_SPACE_TYPE colorSpace, UINT sdrWhiteLevel);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSwapChainProcessor(IDDCX_MONITOR monitor, CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,
|
CSwapChainProcessor(IDDCX_MONITOR monitor, CIndirectDeviceContext * devContext, IDDCX_SWAPCHAIN hSwapChain,
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ PostProcessStatus CHDR16to10Effect::SetFormat(
|
|||||||
dst.minDisplayLuminance = src.minDisplayLuminance;
|
dst.minDisplayLuminance = src.minDisplayLuminance;
|
||||||
dst.maxContentLightLevel = src.maxContentLightLevel;
|
dst.maxContentLightLevel = src.maxContentLightLevel;
|
||||||
dst.maxFrameAverageLightLevel = src.maxFrameAverageLightLevel;
|
dst.maxFrameAverageLightLevel = src.maxFrameAverageLightLevel;
|
||||||
|
dst.sdrWhiteLevel = src.sdrWhiteLevel;
|
||||||
|
|
||||||
return PostProcessStatus::SUCCESS;
|
return PostProcessStatus::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
25
obs/lg.c
25
obs/lg.c
@@ -104,6 +104,7 @@ typedef struct
|
|||||||
bool hideMouse;
|
bool hideMouse;
|
||||||
bool hdr;
|
bool hdr;
|
||||||
bool hdrPQ;
|
bool hdrPQ;
|
||||||
|
float sdrWhiteLevel; // source SDR white level in nits
|
||||||
struct vec3 colorMatrix[3]; // source primaries -> BT.709 (linear)
|
struct vec3 colorMatrix[3]; // source primaries -> BT.709 (linear)
|
||||||
float hdrScale; // scRGB reference white scaling
|
float hdrScale; // scRGB reference white scaling
|
||||||
#if LIBOBS_API_MAJOR_VER >= 27
|
#if LIBOBS_API_MAJOR_VER >= 27
|
||||||
@@ -822,10 +823,12 @@ static void lgFormatInit(LGPlugin * this, const KVMFRFrame * frame,
|
|||||||
this->texture = NULL;
|
this->texture = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->dataWidth = frame->dataWidth;
|
this->dataWidth = frame->dataWidth;
|
||||||
this->unpack = false;
|
this->unpack = false;
|
||||||
this->hdr = frame->flags & FRAME_FLAG_HDR;
|
this->hdr = frame->flags & FRAME_FLAG_HDR;
|
||||||
this->hdrPQ = frame->flags & FRAME_FLAG_HDR_PQ;
|
this->hdrPQ = frame->flags & FRAME_FLAG_HDR_PQ;
|
||||||
|
this->sdrWhiteLevel = frame->sdrWhiteLevel ?
|
||||||
|
(float)frame->sdrWhiteLevel : (float)KVMFR_SDR_WHITE_LEVEL_DEFAULT;
|
||||||
|
|
||||||
if (this->hdr && this->hdrPQ)
|
if (this->hdr && this->hdrPQ)
|
||||||
lgComputeColorMatrix(this, frame);
|
lgComputeColorMatrix(this, frame);
|
||||||
@@ -1223,14 +1226,14 @@ static void lgVideoRender(void * data, gs_effect_t * effect)
|
|||||||
gs_set_scissor_rect(&r);
|
gs_set_scissor_rect(&r);
|
||||||
|
|
||||||
/* Color cursor pixels are premultiplied sRGB. When rendering into OBS's
|
/* Color cursor pixels are premultiplied sRGB. When rendering into OBS's
|
||||||
* linear scRGB space, decode and scale them to its configured SDR white. */
|
* linear scRGB space, decode them and reproduce the source display's SDR
|
||||||
|
* white level reported by the IDD. */
|
||||||
bool mapCursorToScRGB = false;
|
bool mapCursorToScRGB = false;
|
||||||
float cursorScale = 1.0f;
|
float cursorScale = 1.0f;
|
||||||
#if LIBOBS_API_MAJOR_VER >= 28
|
#if LIBOBS_API_MAJOR_VER >= 28
|
||||||
mapCursorToScRGB = this->colorSpace == GS_CS_709_SCRGB;
|
mapCursorToScRGB = this->colorSpace == GS_CS_709_SCRGB;
|
||||||
if (mapCursorToScRGB)
|
if (mapCursorToScRGB)
|
||||||
cursorScale =
|
cursorScale = this->sdrWhiteLevel / LG_SCRGB_REFERENCE_WHITE;
|
||||||
obs_get_video_sdr_white_level() / LG_SCRGB_REFERENCE_WHITE;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
effect = mapCursorToScRGB && !this->cursorMono ?
|
effect = mapCursorToScRGB && !this->cursorMono ?
|
||||||
@@ -1261,9 +1264,13 @@ static void lgVideoRender(void * data, gs_effect_t * effect)
|
|||||||
if (this->cursor.type == CURSOR_TYPE_MASKED_COLOR &&
|
if (this->cursor.type == CURSOR_TYPE_MASKED_COLOR &&
|
||||||
this->cursorXorTex)
|
this->cursorXorTex)
|
||||||
{
|
{
|
||||||
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
effect = mapCursorToScRGB ?
|
||||||
image = gs_effect_get_param_by_name(effect, "image");
|
this->cursorEffect : obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
||||||
|
image = mapCursorToScRGB ?
|
||||||
|
this->cursorImage : gs_effect_get_param_by_name(effect, "image");
|
||||||
gs_effect_set_texture(image, this->cursorXorTex);
|
gs_effect_set_texture(image, this->cursorXorTex);
|
||||||
|
if (mapCursorToScRGB)
|
||||||
|
gs_effect_set_float(this->cursorMultiplier, cursorScale);
|
||||||
gs_blend_function_separate(
|
gs_blend_function_separate(
|
||||||
GS_BLEND_INVDSTCOLOR, GS_BLEND_INVSRCALPHA,
|
GS_BLEND_INVDSTCOLOR, GS_BLEND_INVSRCALPHA,
|
||||||
GS_BLEND_ZERO , GS_BLEND_ONE);
|
GS_BLEND_ZERO , GS_BLEND_ONE);
|
||||||
|
|||||||
Reference in New Issue
Block a user