Merge pull request #177 from ValveTextureFile/shader-macos-fixing

Launcher/overlay: fall back to ImGui's stock pixel shader when the HDR one can't be built
This commit is contained in:
zeex64 authored and GitHub committed 2026-10-11 11:04:09 -05:00
commit 43e88fa433
4 files changed
+87 -53

No files matched your search

+3
View File
@@ -401,6 +401,9 @@ bool setup_graphics() {
// Font upload uses the exact swapchain queue, and this pinned backend waits
// for its own upload fence before returning from device-object creation.
const bool objects = s.dx12_ready && ImGui_ImplDX12_CreateDeviceObjects();
if (objects && !ImGui_ImplDX12_HasOutputTransfer())
dingosdk::logging::write(dingosdk::logging::Level::warning, dingosdk::logging::Channel::graphics,
"Overlay output: this system could not build the HDR-aware shader; drawing in SDR, so an HDR game shows the overlay off-colour.");
ImGui::SetCurrentContext(previous);
if (!objects) {
dingosdk::logging::printf(dingosdk::logging::Level::error, dingosdk::logging::Channel::graphics, "Graphics setup failed in ImGui initialization: win32=%d dx12=%d objects=%d",
+78 -53
View File
@@ -121,6 +121,11 @@ void ImGui_ImplDX12_SetOutputTransfer(int mode, float white_nits)
g_ReSkateOutputTransfer[0] = (float)mode;
g_ReSkateOutputTransfer[1] = white_nits;
}
static bool g_ReSkateOutputTransferAvailable = false;
bool ImGui_ImplDX12_HasOutputTransfer()
{
return g_ReSkateOutputTransferAvailable;
}
// Functions
static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list, ImGui_ImplDX12_RenderBuffers* fr)
@@ -536,7 +541,6 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
ID3DBlob* vertexShaderBlob;
ID3DBlob* pixelShaderBlob;
// Create the vertex shader
{
@@ -582,55 +586,6 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
psoDesc.InputLayout = { local_layout, 3 };
}
// Create the pixel shader
{
static const char* pixelShader =
"struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
cbuffer vertexBuffer : register(b0) \
{\
float4x4 ProjectionMatrix; \
float4 OutputTransfer; \
};\
SamplerState sampler0 : register(s0);\
Texture2D texture0 : register(t0);\
\
float3 srgb_to_linear(float3 c)\
{\
return lerp(c / 12.92, pow(abs((c + 0.055) / 1.055), 2.4), step(0.04045, c)); \
}\
float4 main(PS_INPUT input) : SV_Target\
{\
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
if (OutputTransfer.x > 0.5) \
{\
float3 lin = srgb_to_linear(saturate(out_col.rgb)); \
if (OutputTransfer.x < 1.5) \
{\
out_col.rgb = lin * (OutputTransfer.y / 80.0); \
}\
else \
{\
float3 wide = float3(dot(lin, float3(0.6274, 0.3293, 0.0433)), dot(lin, float3(0.0691, 0.9195, 0.0114)), dot(lin, float3(0.0164, 0.0880, 0.8956))); \
float3 y = pow(saturate(wide * (OutputTransfer.y / 10000.0)), 0.1593017578125); \
out_col.rgb = pow((0.8359375 + 18.8515625 * y) / (1.0 + 18.6875 * y), 78.84375); \
}\
}\
return out_col; \
}";
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &pixelShaderBlob, nullptr)))
{
vertexShaderBlob->Release();
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
}
psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
}
// Create the blending setup
{
D3D12_BLEND_DESC& desc = psoDesc.BlendState;
@@ -673,10 +628,80 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
desc.BackFace = desc.FrontFace;
}
HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState));
// Create the pixel shader and the pipeline
// [ReSkate] The HDR-aware shader first, then ImGui's stock one. Some D3DCompile()s cannot build the HDR one (Wine's
// builtin d3dcompiler, as under Apple's Game Porting Toolkit), and an SDR-only window beats no window at all.
{
static const char* pixelShaders[] =
{
"struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
cbuffer vertexBuffer : register(b0) \
{\
float4x4 ProjectionMatrix; \
float4 OutputTransfer; \
};\
SamplerState sampler0 : register(s0);\
Texture2D texture0 : register(t0);\
\
float3 srgb_to_linear(float3 c)\
{\
return lerp(c / 12.92, pow(abs((c + 0.055) / 1.055), 2.4), step(0.04045, c)); \
}\
float4 main(PS_INPUT input) : SV_Target\
{\
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
if (OutputTransfer.x > 0.5) \
{\
float3 lin = srgb_to_linear(saturate(out_col.rgb)); \
if (OutputTransfer.x < 1.5) \
{\
out_col.rgb = lin * (OutputTransfer.y / 80.0); \
}\
else \
{\
float3 wide = float3(dot(lin, float3(0.6274, 0.3293, 0.0433)), dot(lin, float3(0.0691, 0.9195, 0.0114)), dot(lin, float3(0.0164, 0.0880, 0.8956))); \
float3 y = pow(saturate(wide * (OutputTransfer.y / 10000.0)), 0.1593017578125); \
out_col.rgb = pow((0.8359375 + 18.8515625 * y) / (1.0 + 18.6875 * y), 78.84375); \
}\
}\
return out_col; \
}",
"struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
SamplerState sampler0 : register(s0);\
Texture2D texture0 : register(t0);\
\
float4 main(PS_INPUT input) : SV_Target\
{\
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
return out_col; \
}",
};
g_ReSkateOutputTransferAvailable = false;
for (int i = 0; i < IM_ARRAYSIZE(pixelShaders) && bd->pPipelineState == nullptr; i++)
{
ID3DBlob* pixelShaderBlob = nullptr;
if (FAILED(D3DCompile(pixelShaders[i], strlen(pixelShaders[i]), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &pixelShaderBlob, nullptr)))
continue; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
if (bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState)) != S_OK)
bd->pPipelineState = nullptr;
pixelShaderBlob->Release();
g_ReSkateOutputTransferAvailable = bd->pPipelineState != nullptr && i == 0;
}
}
vertexShaderBlob->Release();
pixelShaderBlob->Release();
if (result_pipeline_state != S_OK)
if (bd->pPipelineState == nullptr)
return false;
return ImGui_ImplDX12_CreateFontsTexture();
+3
View File
@@ -56,6 +56,9 @@ IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3
// primaries with the ST.2084 (PQ) curve (a 10-bit HDR target). `white_nits`: how bright white
// is drawn in 1 and 2. Read at each ImGui_ImplDX12_RenderDrawData.
IMGUI_IMPL_API void ImGui_ImplDX12_SetOutputTransfer(int mode, float white_nits);
// [ReSkate] Whether the pipeline made by the last ImGui_ImplDX12_CreateDeviceObjects() applies that transfer. False when
// D3DCompile() or the driver could not build the HDR-aware shader and ImGui's stock (SDR) one is drawing instead.
IMGUI_IMPL_API bool ImGui_ImplDX12_HasOutputTransfer();
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
// Legacy initialization API Obsoleted in 1.91.5
+3
View File
@@ -127,6 +127,9 @@ bool Renderer::init(HWND window) {
"Launcher renderer: this driver cannot create the Direct3D 12 pipeline the window draws with.");
return false;
}
if (!ImGui_ImplDX12_HasOutputTransfer())
logging::write(logging::Level::info, logging::Channel::launcher,
"Launcher renderer: drawing with ImGui's stock shader; this system could not build the HDR-aware one.");
return true;
}