Added Vulkan HDR10, fixed D3D11/D3D12 HDR10 color space, and ImGui colors in HDR10. (#4061)

This commit is contained in:
Branimir Karadžić
2026-10-17 09:57:27 -07:00
committed by GitHub
parent 227eac0d75
commit fe3f08fb0e
22 changed files with 2020 additions and 906 deletions
+1 -1
View File
@@ -4797,7 +4797,7 @@ public static class bgfx
/// <summary>
/// Set shader uniform parameter for frame.
///
/// @attention Uniform must be created with `bgfx::UniformFreq::View` argument.
/// @attention Uniform must be created with `bgfx::UniformFreq::Frame` argument.
///
/// </summary>
///
+1 -1
View File
@@ -3494,7 +3494,7 @@ extern fn void set_view_uniform(ushort _id, UniformHandle _handle, void* _value,
// Set shader uniform parameter for frame.
//
// @attention Uniform must be created with `bgfx::UniformFreq::View` argument.
// @attention Uniform must be created with `bgfx::UniformFreq::Frame` argument.
//
// _handle : `Uniform.`
// _value : `Pointer to uniform data.`
+1 -1
View File
@@ -4744,7 +4744,7 @@ public static partial class bgfx
/// <summary>
/// Set shader uniform parameter for frame.
///
/// @attention Uniform must be created with `bgfx::UniformFreq::View` argument.
/// @attention Uniform must be created with `bgfx::UniformFreq::Frame` argument.
///
/// </summary>
///
+1 -1
View File
@@ -3963,7 +3963,7 @@ mixin(joinFnBinds((){
/**
* Set shader uniform parameter for frame.
*
* Attention: Uniform must be created with `bgfx::UniformFreq::View` argument.
* Attention: Uniform must be created with `bgfx::UniformFreq::Frame` argument.
*
Params:
handle = Uniform.
+1 -1
View File
@@ -2825,7 +2825,7 @@ def bgfx_set_view_uniform(_id: int, _handle: UniformHandle, _value: Any, _num: i
# Set shader uniform parameter for frame.
#
# @attention Uniform must be created with `bgfx::UniformFreq::View` argument.
# @attention Uniform must be created with `bgfx::UniformFreq::Frame` argument.
#
def bgfx_set_frame_uniform(_handle: UniformHandle, _value: Any, _num: int, /) -> None: ...
+1 -1
View File
@@ -3903,7 +3903,7 @@ extern fn bgfx_set_view_uniform(_id: ViewId, _handle: UniformHandle, _value: ?*c
/// Set shader uniform parameter for frame.
///
/// @attention Uniform must be created with `bgfx::UniformFreq::View` argument.
/// @attention Uniform must be created with `bgfx::UniformFreq::Frame` argument.
///
/// <param name="_handle">Uniform.</param>
/// <param name="_value">Pointer to uniform data.</param>
+12
View File
@@ -227,6 +227,18 @@ public:
);
imguiLabel(m_width*0.5f, m_height - 10.0f, "status", text);
const bool hdr10Output = true
&& hdr10
&& 0 != (caps->supported & BGFX_CAPS_HDR10)
;
imguiSetOutput(
!hdr10Output ? ImguiOutput::Srgb
: m_pq ? ImguiOutput::Pq
: ImguiOutput::Linear
, m_pq ? kBarNits : 1.0f
);
imguiEndFrame();
m_reset = (m_reset & ~BGFX_RESET_HDR10) | (hdr10 ? BGFX_RESET_HDR10 : 0);
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -6,6 +6,7 @@ $input v_texcoord0
*/
#include <bgfx_shader.sh>
#include "imgui_output.sh"
uniform vec4 u_imageLodEnabled;
SAMPLER2D(s_texColor, 0);
@@ -17,5 +18,5 @@ void main()
{
vec3 color = texture2DLod(s_texColor, v_texcoord0, u_imageLod).xyz;
float alpha = 0.2 + 0.8*u_imageEnabled;
gl_FragColor = vec4(color, alpha);
gl_FragColor = vec4(imguiOutput(color), alpha);
}
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -1,11 +1,13 @@
$input v_color0, v_texcoord0
#include "../common.sh"
#include "imgui_output.sh"
SAMPLER2D(s_tex, 0);
void main()
{
vec4 texel = texture2D(s_tex, v_texcoord0);
gl_FragColor = texel * v_color0;
vec4 color = texel * v_color0;
gl_FragColor = vec4(imguiOutput(color.xyz), color.w);
}
+20
View File
@@ -154,6 +154,7 @@ struct OcornutImguiContext
bx::mtxOrtho(ortho, x, x + width, y + height, y, 0.0f, 1000.0f, 0.0f, caps->homogeneousDepth);
bgfx::setViewTransform(m_viewId, NULL, ortho);
bgfx::setViewRect(m_viewId, 0, 0, uint16_t(width), uint16_t(height) );
bgfx::setFrameUniform(u_imguiOutput, m_output);
}
const ImVec2 clipPos = _drawData->DisplayPos; // (0,0) unless using multi-viewports
@@ -275,6 +276,8 @@ struct OcornutImguiContext
m_lastScroll = 0;
m_last = bx::getHPCounter();
setOutput(ImguiOutput::Srgb, 1.0f);
ImGui::SetAllocatorFunctions(memAlloc, memFree, NULL);
m_imgui = ImGui::CreateContext();
@@ -414,6 +417,7 @@ struct OcornutImguiContext
);
u_imageLodEnabled = bgfx::createUniform("u_imageLodEnabled", bgfx::UniformType::Vec4);
u_imguiOutput = bgfx::createUniform("u_imguiOutput", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4);
m_imageProgram = bgfx::createProgram(
bgfx::createEmbeddedShader(s_embeddedShaders, type, "vs_imgui_image")
, bgfx::createEmbeddedShader(s_embeddedShaders, type, "fs_imgui_image")
@@ -480,6 +484,7 @@ struct OcornutImguiContext
bgfx::destroy(s_tex);
bgfx::destroy(u_imageLodEnabled);
bgfx::destroy(u_imguiOutput);
bgfx::destroy(m_imageProgram);
bgfx::destroy(m_program);
@@ -578,6 +583,14 @@ struct OcornutImguiContext
render(ImGui::GetDrawData() );
}
void setOutput(ImguiOutput::Enum _output, float _white)
{
m_output[0] = float(_output);
m_output[1] = ImguiOutput::Pq == _output ? _white/10000.0f : _white;
m_output[2] = 0.0f;
m_output[3] = 0.0f;
}
ImGuiContext* m_imgui;
bx::AllocatorI* m_allocator;
bgfx::VertexLayout m_layout;
@@ -585,6 +598,8 @@ struct OcornutImguiContext
bgfx::ProgramHandle m_imageProgram;
bgfx::UniformHandle s_tex;
bgfx::UniformHandle u_imageLodEnabled;
bgfx::UniformHandle u_imguiOutput;
float m_output[4];
ImFont* m_font[ImGui::Font::Count];
int64_t m_last;
int32_t m_lastScroll;
@@ -628,6 +643,11 @@ void imguiEndFrame()
s_ctx.endFrame();
}
void imguiSetOutput(ImguiOutput::Enum _output, float _white)
{
s_ctx.setOutput(_output, _white);
}
namespace ImGui
{
void PushFont(Font::Enum _font, float _fontSizeBaseUnscaled)
+14
View File
@@ -34,6 +34,20 @@ void imguiDestroy();
void imguiBeginFrame(int32_t _mx, int32_t _my, uint8_t _button, int32_t _scroll, uint16_t _width, uint16_t _height, int _inputChar = -1, bgfx::ViewId _view = UINT16_MAX);
void imguiEndFrame();
struct ImguiOutput
{
enum Enum
{
Srgb,
Linear,
Pq,
Count
};
};
void imguiSetOutput(ImguiOutput::Enum _output, float _white);
namespace entry { class AppI; }
void showExampleDialog(entry::AppI* _app, const char* _errorText = NULL);
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright 2011-2026 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
*/
#ifndef IMGUI_OUTPUT_SH_HEADER_GUARD
#define IMGUI_OUTPUT_SH_HEADER_GUARD
uniform vec4 u_imguiOutput;
#define u_imguiOutputMode u_imguiOutput.x
#define u_imguiOutputWhite u_imguiOutput.y
vec3 imguiOutput(vec3 _rgb)
{
if (u_imguiOutputMode < 0.5)
{
return _rgb;
}
vec3 lo = _rgb / 12.92;
vec3 hi = pow( (_rgb + 0.055) / 1.055, vec3_splat(2.4) );
vec3 rgb = mix(hi, lo, vec3(lessThanEqual(_rgb, vec3_splat(0.04045) ) ) ) * u_imguiOutputWhite;
if (u_imguiOutputMode < 1.5)
{
return rgb;
}
vec3 bt2020 = vec3(
dot(vec3(0.6274, 0.3293, 0.0433), rgb)
, dot(vec3(0.0691, 0.9195, 0.0114), rgb)
, dot(vec3(0.0164, 0.0880, 0.8956), rgb)
);
const float m1 = 2610.0/16384.0;
const float m2 = 2523.0/4096.0*128.0;
const float c1 = 3424.0/4096.0;
const float c2 = 2413.0/4096.0*32.0;
const float c3 = 2392.0/4096.0*32.0;
vec3 yy = pow(clamp(bt2020, 0.0, 1.0), vec3_splat(m1) );
return pow( (c1 + c2*yy) / (1.0 + c3*yy), vec3_splat(m2) );
}
#endif // IMGUI_OUTPUT_SH_HEADER_GUARD
+1 -1
View File
@@ -4429,7 +4429,7 @@ namespace bgfx
/// @param[in] _num Number of elements. Passing `UINT16_MAX` will
/// use the _num passed on uniform creation.
///
/// @attention Uniform must be created with `bgfx::UniformFreq::View` argument.
/// @attention Uniform must be created with `bgfx::UniformFreq::Frame` argument.
///
/// @attention C99's equivalent binding is `bgfx_set_frame_uniform`.
///
+1 -1
View File
@@ -3301,7 +3301,7 @@ BGFX_C_API void bgfx_set_view_uniform(bgfx_view_id_t _id, bgfx_uniform_handle_t
/**
* Set shader uniform parameter for frame.
*
* @attention Uniform must be created with `bgfx::UniformFreq::View` argument.
* @attention Uniform must be created with `bgfx::UniformFreq::Frame` argument.
*
* @param[in] _handle Uniform.
* @param[in] _value Pointer to uniform data.
+1 -1
View File
@@ -2884,7 +2884,7 @@ func.setViewUniform { section = "Draw/Uniforms" }
--- Set shader uniform parameter for frame.
---
--- @attention Uniform must be created with `bgfx::UniformFreq::View` argument.
--- @attention Uniform must be created with `bgfx::UniformFreq::Frame` argument.
---
func.setFrameUniform { section = "Draw/Uniforms" }
"void"
+29 -19
View File
@@ -666,18 +666,27 @@ namespace bgfx
if (SUCCEEDED(hr) )
{
const bool hdr10 = true
&& _scd.hdr10
&& 0 != (g_caps.supported & BGFX_CAPS_HDR10)
;
const DXGI_COLOR_SPACE_TYPE colorSpace =
_scd.format == DXGI_FORMAT_R10G10B10A2_UNORM ? DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
!hdr10 ? DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
: _scd.format == DXGI_FORMAT_R10G10B10A2_UNORM ? DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
: _scd.format == DXGI_FORMAT_R16G16B16A16_FLOAT ? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
;
hr = swapChain4->SetColorSpace1(colorSpace);
if (SUCCEEDED(hr) )
if (SUCCEEDED(hr)
&& DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 != colorSpace)
{
swapChain4->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_NONE, 0, NULL);
}
else if (SUCCEEDED(hr) )
{
DXGI_OUTPUT_DESC1 desc;
IDXGIOutput* output;
hr = _swapChain->GetContainingOutput(&output);
if (SUCCEEDED(hr) )
@@ -686,6 +695,7 @@ namespace bgfx
hr = output->QueryInterface(IID_IDXGIOutput6, (void**)&output6);
if (SUCCEEDED(hr) )
{
DXGI_OUTPUT_DESC1 desc;
hr = output6->GetDesc1(&desc);
if (SUCCEEDED(hr) )
{
@@ -701,6 +711,21 @@ namespace bgfx
BX_TRACE("\t MinLuminance: %f", desc.MinLuminance);
BX_TRACE("\t MaxLuminance: %f", desc.MaxLuminance);
BX_TRACE("\tMaxFullFrameLuminance: %f", desc.MaxFullFrameLuminance);
DXGI_HDR_METADATA_HDR10 metaData;
metaData.RedPrimary[0] = uint16_t(desc.RedPrimary[0] * 50000.0f);
metaData.RedPrimary[1] = uint16_t(desc.RedPrimary[1] * 50000.0f);
metaData.GreenPrimary[0] = uint16_t(desc.GreenPrimary[0] * 50000.0f);
metaData.GreenPrimary[1] = uint16_t(desc.GreenPrimary[1] * 50000.0f);
metaData.BluePrimary[0] = uint16_t(desc.BluePrimary[0] * 50000.0f);
metaData.BluePrimary[1] = uint16_t(desc.BluePrimary[1] * 50000.0f);
metaData.WhitePoint[0] = uint16_t(desc.WhitePoint[0] * 50000.0f);
metaData.WhitePoint[1] = uint16_t(desc.WhitePoint[1] * 50000.0f);
metaData.MaxMasteringLuminance = uint32_t(desc.MaxLuminance * 10000.0f);
metaData.MinMasteringLuminance = uint32_t(desc.MinLuminance * 10000.0f);
metaData.MaxContentLightLevel = uint16_t(desc.MaxFullFrameLuminance);
metaData.MaxFrameAverageLightLevel = uint16_t(desc.MaxFullFrameLuminance);
swapChain4->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_HDR10, sizeof(DXGI_HDR_METADATA_HDR10), &metaData);
}
DX_RELEASE(output6, 1);
@@ -708,21 +733,6 @@ namespace bgfx
DX_RELEASE(output, 0);
}
DXGI_HDR_METADATA_HDR10 hdr10;
hdr10.RedPrimary[0] = uint16_t(desc.RedPrimary[0] * 50000.0f);
hdr10.RedPrimary[1] = uint16_t(desc.RedPrimary[1] * 50000.0f);
hdr10.GreenPrimary[0] = uint16_t(desc.GreenPrimary[0] * 50000.0f);
hdr10.GreenPrimary[1] = uint16_t(desc.GreenPrimary[1] * 50000.0f);
hdr10.BluePrimary[0] = uint16_t(desc.BluePrimary[0] * 50000.0f);
hdr10.BluePrimary[1] = uint16_t(desc.BluePrimary[1] * 50000.0f);
hdr10.WhitePoint[0] = uint16_t(desc.WhitePoint[0] * 50000.0f);
hdr10.WhitePoint[1] = uint16_t(desc.WhitePoint[1] * 50000.0f);
hdr10.MaxMasteringLuminance = uint32_t(desc.MaxLuminance * 10000.0f);
hdr10.MinMasteringLuminance = uint32_t(desc.MinLuminance * 10000.0f);
hdr10.MaxContentLightLevel = uint16_t(desc.MaxFullFrameLuminance);
hdr10.MaxFrameAverageLightLevel = uint16_t(desc.MaxFullFrameLuminance);
hr = swapChain4->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_HDR10, sizeof(DXGI_HDR_METADATA_HDR10), &hdr10);
}
DX_RELEASE(swapChain4, 1);
+1
View File
@@ -46,6 +46,7 @@ namespace bgfx
void* nwh;
void* ndt;
bool windowed;
bool hdr10;
};
struct DxgiSwapChain
+3
View File
@@ -1186,6 +1186,7 @@ namespace bgfx { namespace d3d11
m_scd.nwh = _init.swapChain.nwh;
m_scd.ndt = _init.swapChain.ndt;
m_scd.windowed = true;
m_scd.hdr10 = 0 != (_init.swapChain.flags & BGFX_SWAP_CHAIN_HDR10);
if (NULL != m_scd.nwh)
{
@@ -2608,6 +2609,7 @@ namespace bgfx { namespace d3d11
m_scd.height = _swapChain.height;
// see comment in init() about why we don't worry about BGFX_RESET_SRGB_BACKBUFFER here
m_scd.format = s_textureFormat[_swapChain.formatColor].m_fmt;
m_scd.hdr10 = 0 != (_swapChain.flags & BGFX_SWAP_CHAIN_HDR10);
preReset();
@@ -6003,6 +6005,7 @@ namespace bgfx { namespace d3d11
scd.nwh = m_desc.nwh;
scd.ndt = m_desc.ndt;
scd.sampleDesc = s_msaa[(m_desc.flags&BGFX_SWAP_CHAIN_MSAA_MASK)>>BGFX_SWAP_CHAIN_MSAA_SHIFT];
scd.hdr10 = 0 != (m_desc.flags & BGFX_SWAP_CHAIN_HDR10);
return scd;
}
+3
View File
@@ -1465,6 +1465,7 @@ namespace bgfx { namespace d3d12
m_scd.nwh = _init.swapChain.nwh;
m_scd.ndt = _init.swapChain.ndt;
m_scd.windowed = true;
m_scd.hdr10 = 0 != (_init.swapChain.flags & BGFX_SWAP_CHAIN_HDR10);
m_backBufferColorIdx = m_scd.bufferCount-1;
@@ -3329,6 +3330,7 @@ namespace bgfx { namespace d3d12
m_scd.width = _swapChain.width;
m_scd.height = _swapChain.height;
m_scd.format = s_textureFormat[_swapChain.formatColor].m_fmt;
m_scd.hdr10 = 0 != (_swapChain.flags & BGFX_SWAP_CHAIN_HDR10);
preReset();
@@ -8132,6 +8134,7 @@ namespace bgfx { namespace d3d12
scd.nwh = m_desc.nwh;
scd.ndt = m_desc.ndt;
scd.sampleDesc = s_msaa[(m_desc.flags&BGFX_SWAP_CHAIN_MSAA_MASK)>>BGFX_SWAP_CHAIN_MSAA_SHIFT];
scd.hdr10 = 0 != (m_desc.flags & BGFX_SWAP_CHAIN_HDR10);
scd.waitable = true;
return scd;
+41 -3
View File
@@ -390,6 +390,7 @@ VK_IMPORT_DEVICE
EXT_memory_budget,
EXT_shader_viewport_index_layer,
EXT_surface_maintenance1,
EXT_swapchain_colorspace,
EXT_swapchain_maintenance1,
KHR_16bit_storage,
KHR_draw_indirect_count,
@@ -442,6 +443,7 @@ VK_IMPORT_DEVICE
{ "VK_EXT_memory_budget", 1, false, false, true, Layer::Count },
{ "VK_EXT_shader_viewport_index_layer", 1, false, false, true, Layer::Count },
{ "VK_EXT_surface_maintenance1", 1, false, false, true, Layer::Count },
{ "VK_EXT_swapchain_colorspace", 1, false, false, true, Layer::Count },
{ "VK_EXT_swapchain_maintenance1", 1, false, false, true, Layer::Count },
{ "VK_KHR_16bit_storage", 1, false, false, true, Layer::Count },
{ "VK_KHR_draw_indirect_count", 1, false, false, true, Layer::Count },
@@ -1108,6 +1110,14 @@ VK_IMPORT_DEVICE
;
}
VkColorSpaceKHR getHdr10ColorSpace(TextureFormat::Enum _format)
{
return TextureFormat::RGB10A2 == _format ? VK_COLOR_SPACE_HDR10_ST2084_EXT
: TextureFormat::RGBA16F == _format ? VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
: VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
;
}
void setImageMemoryBarrier(
VkCommandBuffer _commandBuffer
, VkImage _image
@@ -2471,6 +2481,22 @@ VK_IMPORT_DEVICE
{
const VkSurfaceFormatKHR& surfaceFormat = surfaceFormats[sfidx];
static const TextureFormat::Enum hdr10Formats[] =
{
TextureFormat::RGB10A2,
TextureFormat::RGBA16F,
};
for (TextureFormat::Enum format : hdr10Formats)
{
if (s_extension[Extension::EXT_swapchain_colorspace].m_supported
&& surfaceFormat.format == s_textureFormat[format].m_fmt
&& surfaceFormat.colorSpace == getHdr10ColorSpace(format) )
{
g_caps.supported |= BGFX_CAPS_HDR10;
}
}
for (uint32_t ii = TextureFormat::Unknown+1; ii < TextureFormat::UnknownDepth; ++ii)
{
if (0 != (g_caps.formats[ii] & BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER) )
@@ -8926,7 +8952,7 @@ VK_DESTROY
const VkPhysicalDevice physicalDevice = s_renderVK->m_physicalDevice;
const uint64_t recreateSurfaceMask = BGFX_SWAP_CHAIN_HIDPI;
const uint64_t recreateSwapchainMask = BGFX_SWAP_CHAIN_SRGB_BACKBUFFER;
const uint64_t recreateSwapchainMask = BGFX_SWAP_CHAIN_SRGB_BACKBUFFER | BGFX_SWAP_CHAIN_HDR10;
const uint64_t recreateAttachmentsMask = BGFX_SWAP_CHAIN_MSAA_MASK;
const bool vsync = !!(s_renderVK->m_reset & BGFX_RESET_VSYNC);
@@ -9263,9 +9289,21 @@ VK_DESTROY
const uint32_t swapBufferCount = bx::clamp<uint32_t>(m_desc.numBackBuffers, minSwapBufferCount, maxSwapBufferCount);
const VkColorSpaceKHR surfaceColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
const bool srgb = !!(m_desc.flags & BGFX_SWAP_CHAIN_SRGB_BACKBUFFER);
const VkColorSpaceKHR hdr10ColorSpace = getHdr10ColorSpace(m_desc.formatColor);
const bool hdr10 = true
&& 0 != (m_desc.flags & BGFX_SWAP_CHAIN_HDR10)
&& s_extension[Extension::EXT_swapchain_colorspace].m_supported
&& VK_COLOR_SPACE_SRGB_NONLINEAR_KHR != hdr10ColorSpace
&& m_desc.formatColor == findSurfaceFormat(m_desc.formatColor, hdr10ColorSpace, srgb)
;
const VkColorSpaceKHR surfaceColorSpace = hdr10
? hdr10ColorSpace
: VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
;
m_colorFormat = findSurfaceFormat(m_desc.formatColor, surfaceColorSpace, srgb);
m_depthFormat = bgfx::TextureFormat::UnknownDepth;