Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 9 additions & 17 deletions dependencies/imgui/imgui_impl_dx11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ struct ImGui_ImplDX11_Data
ID3D11RasterizerState* pRasterizerState;
ID3D11BlendState* pBlendState;
ID3D11DepthStencilState* pDepthStencilState;
ImGui_ImplDXGI_ColorSpace ColorSpace;
int VertexBufferSize;
int IndexBufferSize;

Expand Down Expand Up @@ -456,24 +457,14 @@ bool ImGui_ImplDX11_CreateDeviceObjects()

// Create the pixel shader
{
static const char* pixelShader =
"struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
sampler sampler0;\
Texture2D texture0;\
\
float4 main(PS_INPUT input) : SV_Target\
{\
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
return out_col; \
}";
const D3D_SHADER_MACRO shaderDefines[] =
{
{ "IMGUI_COLOR_SPACE", ImGui_ImplDXGI_GetColorSpaceShaderDefine(bd->ColorSpace) },
{ nullptr, nullptr },
};

ID3DBlob* pixelShaderBlob;
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &pixelShaderBlob, nullptr)))
if (FAILED(D3DCompile(ImGui_ImplDXGI_PixelShader, strlen(ImGui_ImplDXGI_PixelShader), nullptr, shaderDefines, nullptr, "main", "ps_4_0", 0, 0, &pixelShaderBlob, nullptr)))
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), nullptr, &bd->pPixelShader) != S_OK)
{
Expand Down Expand Up @@ -548,13 +539,14 @@ void ImGui_ImplDX11_InvalidateDeviceObjects()
if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = nullptr; }
}

bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context, ImGui_ImplDXGI_ColorSpace color_space)
{
ImGuiIO& io = *igGetIO();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");

// Setup backend capabilities flags
ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)();
bd->ColorSpace = color_space;
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx11";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
Expand Down
3 changes: 2 additions & 1 deletion dependencies/imgui/imgui_impl_dx11.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@

#pragma once
#include <imgui_impl.h>
#include <imgui_impl_dxgi_hdr.h>
#ifndef IMGUI_DISABLE

struct ID3D11Device;
struct ID3D11DeviceContext;

IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context, ImGui_ImplDXGI_ColorSpace color_space = ImGui_ImplDXGI_ColorSpace_SDR);
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
Expand Down
27 changes: 10 additions & 17 deletions dependencies/imgui/imgui_impl_dx12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ struct ImGui_ImplDX12_Data
D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle;
ID3D12DescriptorHeap* pd3dSrvDescHeap;
UINT numFramesInFlight;
ImGui_ImplDXGI_ColorSpace ColorSpace;

ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); }
};
Expand Down Expand Up @@ -676,23 +677,13 @@ bool ImGui_ImplDX12_CreateDeviceObjects()

// Create the pixel shader
{
static const char* pixelShader =
"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; \
}";
const D3D_SHADER_MACRO shaderDefines[] =
{
{ "IMGUI_COLOR_SPACE", ImGui_ImplDXGI_GetColorSpaceShaderDefine(bd->ColorSpace) },
{ nullptr, nullptr },
};

if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &pixelShaderBlob, nullptr)))
if (FAILED(D3DCompile(ImGui_ImplDXGI_PixelShader, strlen(ImGui_ImplDXGI_PixelShader), nullptr, shaderDefines, 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!
Expand Down Expand Up @@ -774,7 +765,8 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
}

bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle,
ImGui_ImplDXGI_ColorSpace color_space)
{
ImGuiIO& io = *igGetIO();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
Expand All @@ -790,6 +782,7 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO

bd->pd3dDevice = device;
bd->RTVFormat = rtv_format;
bd->ColorSpace = color_space;
bd->hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
bd->hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
bd->numFramesInFlight = num_frames_in_flight;
Expand Down
4 changes: 3 additions & 1 deletion dependencies/imgui/imgui_impl_dx12.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#pragma once
#include <imgui_impl.h>
#include <imgui_impl_dxgi_hdr.h>
#ifndef IMGUI_DISABLE
#include <dxgiformat.h> // DXGI_FORMAT

Expand All @@ -33,7 +34,8 @@ struct D3D12_GPU_DESCRIPTOR_HANDLE;
// render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle.
// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture.
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle,
ImGui_ImplDXGI_ColorSpace color_space = ImGui_ImplDXGI_ColorSpace_SDR);
IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
Expand Down
89 changes: 89 additions & 0 deletions dependencies/imgui/imgui_impl_dxgi_hdr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#pragma once

enum ImGui_ImplDXGI_ColorSpace
{
ImGui_ImplDXGI_ColorSpace_SDR = 0,
ImGui_ImplDXGI_ColorSpace_scRGB,
ImGui_ImplDXGI_ColorSpace_HDR10,
};

inline const char* ImGui_ImplDXGI_GetColorSpaceShaderDefine(ImGui_ImplDXGI_ColorSpace color_space)
{
switch (color_space)
{
case ImGui_ImplDXGI_ColorSpace_scRGB:
return "1";
case ImGui_ImplDXGI_ColorSpace_HDR10:
return "2";
default:
return "0";
}
}

// ImGui colors and textures are treated as sRGB/Rec.709. HDR output uses a
// 203-nit graphics white, as recommended by BT.2408, while SDR output remains
// byte-for-byte compatible with the stock Dear ImGui renderer backend.
inline constexpr const char* ImGui_ImplDXGI_PixelShader = R"(
#ifndef IMGUI_COLOR_SPACE
#define IMGUI_COLOR_SPACE 0
#endif

struct PS_INPUT
{
float4 pos : SV_POSITION;
float4 col : COLOR0;
float2 uv : TEXCOORD0;
};

SamplerState sampler0 : register(s0);
Texture2D texture0 : register(t0);

static const float GRAPHICS_WHITE_NITS = 203.0;

float3 SrgbToLinear(float3 color)
{
float3 low = color / 12.92;
float3 high = pow((color + 0.055) / 1.055, 2.4);
return lerp(low, high, step(0.04045, color));
}

float3 Rec709ToRec2020(float3 color)
{
const float3x3 transform =
{
0.6274040, 0.3292820, 0.0433136,
0.0690970, 0.9195400, 0.0113612,
0.0163916, 0.0880132, 0.8955950
};
return mul(transform, color);
}

float3 LinearToPq(float3 color)
{
const float m1 = 2610.0 / 16384.0;
const float m2 = 2523.0 / 32.0;
const float c1 = 3424.0 / 4096.0;
const float c2 = 2413.0 / 128.0;
const float c3 = 2392.0 / 128.0;

float3 p = pow(max(color, 0.0), m1);
return pow((c1 + c2 * p) / (1.0 + c3 * p), m2);
}

float4 main(PS_INPUT input) : SV_Target
{
float4 out_col = input.col * texture0.Sample(sampler0, input.uv);

#if IMGUI_COLOR_SPACE == 1
// scRGB is linear Rec.709 and defines 1.0 as 80 nits.
out_col.rgb = SrgbToLinear(saturate(out_col.rgb)) * (GRAPHICS_WHITE_NITS / 80.0);
#elif IMGUI_COLOR_SPACE == 2
// HDR10 uses Rec.2020 primaries and the absolute ST.2084/PQ transfer curve.
float3 linear_rec709 = SrgbToLinear(saturate(out_col.rgb));
float3 linear_rec2020 = Rec709ToRec2020(linear_rec709);
out_col.rgb = LinearToPq(linear_rec2020 * (GRAPHICS_WHITE_NITS / 10000.0));
#endif

return out_col;
}
)";
55 changes: 51 additions & 4 deletions mhw-cs-plugin-loader/D3DModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@
// DirectXTK12 References SerializeRootSignature so we need to link this
#pragma comment(lib, "d3d12.lib")

namespace {

// DXGI exposes methods to set a swap-chain color space, but not to query the
// active one. MHW uses these back-buffer formats for its two HDR output paths.
ImGui_ImplDXGI_ColorSpace infer_imgui_color_space(DXGI_FORMAT back_buffer_format) {
switch (back_buffer_format) {
case DXGI_FORMAT_R16G16B16A16_FLOAT:
dlog::debug("Using scRGB color management for ImGui");
return ImGui_ImplDXGI_ColorSpace_scRGB;

case DXGI_FORMAT_R10G10B10A2_UNORM:
dlog::debug("Using HDR10 color management for ImGui");
return ImGui_ImplDXGI_ColorSpace_HDR10;

default:
dlog::debug("Using SDR color management for ImGui");
return ImGui_ImplDXGI_ColorSpace_SDR;
}
}

}

void D3DModule::initialize(CoreClr* coreclr) {
if (!preloader::LoaderConfig::get().get_imgui_rendering_enabled()) {
dlog::debug("Skipping D3D module initialization because imgui rendering is disabled");
Expand Down Expand Up @@ -558,6 +580,8 @@ void D3DModule::d3d12_initialize_imgui(IDXGISwapChain* swap_chain) {
const auto rtv_descriptor_size = m_d3d12_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = m_d3d12_back_buffers->GetCPUDescriptorHandleForHeapStart();

DXGI_FORMAT back_buffer_format = DXGI_FORMAT_UNKNOWN;

for (auto i = 0u; i < desc.BufferCount; ++i) {
ComPtr<ID3D12Resource> back_buffer;
if (FAILED(swap_chain->GetBuffer(i, IID_PPV_ARGS(back_buffer.GetAddressOf())))) {
Expand All @@ -566,7 +590,17 @@ void D3DModule::d3d12_initialize_imgui(IDXGISwapChain* swap_chain) {
}

const auto buffer_desc = back_buffer->GetDesc();
dlog::debug("Creating RTV for back buffer {}, with size {}x{}", i, buffer_desc.Width, buffer_desc.Height);
if (i == 0) {
back_buffer_format = buffer_desc.Format;
}

dlog::debug(
"Creating RTV for back buffer {}, with size {}x{} and format {}",
i,
buffer_desc.Width,
buffer_desc.Height,
static_cast<u32>(buffer_desc.Format)
);

m_d3d12_device->CreateRenderTargetView(back_buffer.Get(), nullptr, rtv_handle);
m_d3d12_frame_contexts[i].RenderTargetDescriptor = rtv_handle;
Expand All @@ -575,6 +609,8 @@ void D3DModule::d3d12_initialize_imgui(IDXGISwapChain* swap_chain) {
rtv_handle.ptr += rtv_descriptor_size;
}

const auto imgui_color_space = infer_imgui_color_space(back_buffer_format);

if (!ImGui_ImplWin32_Init(m_game_window)) {
dlog::error("Failed to initialize ImGui Win32");
return;
Expand All @@ -583,9 +619,10 @@ void D3DModule::d3d12_initialize_imgui(IDXGISwapChain* swap_chain) {
ImGui_ImplWin32_EnableDpiAwareness();

if (!ImGui_ImplDX12_Init(m_d3d12_device, desc.BufferCount,
DXGI_FORMAT_R8G8B8A8_UNORM, m_d3d12_srv_heap.Get(),
back_buffer_format, m_d3d12_srv_heap.Get(),
m_d3d12_srv_heap->GetCPUDescriptorHandleForHeapStart(),
m_d3d12_srv_heap->GetGPUDescriptorHandleForHeapStart())) {
m_d3d12_srv_heap->GetGPUDescriptorHandleForHeapStart(),
imgui_color_space)) {
dlog::error("Failed to initialize ImGui D3D12");
return;
}
Expand Down Expand Up @@ -618,6 +655,16 @@ void D3DModule::d3d11_initialize_imgui(IDXGISwapChain* swap_chain) {
return;
}

DXGI_FORMAT back_buffer_format = desc.BufferDesc.Format;
ComPtr<ID3D11Texture2D> back_buffer;
if (SUCCEEDED(swap_chain->GetBuffer(0, IID_PPV_ARGS(back_buffer.GetAddressOf())))) {
D3D11_TEXTURE2D_DESC back_buffer_desc;
back_buffer->GetDesc(&back_buffer_desc);
back_buffer_format = back_buffer_desc.Format;
}

const auto imgui_color_space = infer_imgui_color_space(back_buffer_format);

RECT client_rect;
GetClientRect(desc.OutputWindow, &client_rect);

Expand All @@ -638,7 +685,7 @@ void D3DModule::d3d11_initialize_imgui(IDXGISwapChain* swap_chain) {
return;
}

if (!ImGui_ImplDX11_Init(m_d3d11_device, m_d3d11_device_context)) {
if (!ImGui_ImplDX11_Init(m_d3d11_device, m_d3d11_device_context, imgui_color_space)) {
dlog::error("Failed to initialize ImGui D3D11");
return;
}
Expand Down
3 changes: 2 additions & 1 deletion mhw-cs-plugin-loader/mhw-cs-plugin-loader.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
<ClInclude Include="..\dependencies\imgui\imgui_impl.h" />
<ClInclude Include="..\dependencies\imgui\imgui_impl_dx11.h" />
<ClInclude Include="..\dependencies\imgui\imgui_impl_dx12.h" />
<ClInclude Include="..\dependencies\imgui\imgui_impl_dxgi_hdr.h" />
<ClInclude Include="..\dependencies\imgui\imgui_impl_win32.h" />
<ClInclude Include="AddressRepository.h" />
<ClInclude Include="Bitfield.h" />
Expand Down Expand Up @@ -206,4 +207,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
5 changes: 4 additions & 1 deletion mhw-cs-plugin-loader/mhw-cs-plugin-loader.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@
<ClInclude Include="..\dependencies\imgui\imgui_impl_dx12.h">
<Filter>Header Files\ImGui</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\imgui\imgui_impl_dxgi_hdr.h">
<Filter>Header Files\ImGui</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\imgui\imgui_impl_win32.h">
<Filter>Header Files\ImGui</Filter>
</ClInclude>
Expand Down Expand Up @@ -246,4 +249,4 @@
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
</Project>
</Project>
Loading