Skip to content

Commit bbd4fed

Browse files
committed
Implement adaptive exposure
Add a compute shader that will compute the geometric mean of scene luminance, then map it to an exposure curve in the `cameraEffects` shader. This is controlled by `r_tonemapAdaptiveExposure`.
1 parent e91cb12 commit bbd4fed

18 files changed

+344
-20
lines changed

libs/crunch

src.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ set(GLSLSOURCELIST
173173
${ENGINE_DIR}/renderer/glsl_source/lighttile_fp.glsl
174174
${ENGINE_DIR}/renderer/glsl_source/computeLight_fp.glsl
175175
${ENGINE_DIR}/renderer/glsl_source/reliefMapping_fp.glsl
176+
${ENGINE_DIR}/renderer/glsl_source/luminanceReduction_cp.glsl
177+
${ENGINE_DIR}/renderer/glsl_source/clearFrameData_cp.glsl
176178

177179
# Common vertex shader libraries
178180
${ENGINE_DIR}/renderer/glsl_source/deformVertexes_vp.glsl

src/engine/renderer/Material.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,8 @@ enum class BufferBind {
291291
PORTAL_SURFACES = 5,
292292
GEOMETRY_CACHE_INPUT_VBO = 6,
293293
GEOMETRY_CACHE_VBO = 7,
294+
LUMINANCE = 3,
295+
LUMINANCE_STORAGE = 8,
294296
DEBUG = 10,
295297
UNUSED = INT32_MAX
296298
};

src/engine/renderer/gl_shader.cpp

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ GLShader_fxaa *gl_fxaaShader = nullptr;
5656
GLShader_motionblur *gl_motionblurShader = nullptr;
5757
GLShader_ssao *gl_ssaoShader = nullptr;
5858

59-
GLShader_depthtile1 *gl_depthtile1Shader = nullptr;
60-
GLShader_depthtile2 *gl_depthtile2Shader = nullptr;
61-
GLShader_lighttile *gl_lighttileShader = nullptr;
59+
GLShader_depthtile1* gl_depthtile1Shader = nullptr;
60+
GLShader_depthtile2* gl_depthtile2Shader = nullptr;
61+
GLShader_lighttile* gl_lighttileShader = nullptr;
62+
GLShader_luminanceReduction* gl_luminanceReductionShader = nullptr;
63+
GLShader_clearFrameData* gl_clearFrameDataShader = nullptr;
6264

6365
GLShader_generic *gl_genericShader = nullptr;
6466
GLShader_genericMaterial *gl_genericShaderMaterial = nullptr;
@@ -83,6 +85,7 @@ GLShader_skybox *gl_skyboxShader = nullptr;
8385
GLShader_skyboxMaterial *gl_skyboxShaderMaterial = nullptr;
8486
GLShader_debugShadowMap *gl_debugShadowMapShader = nullptr;
8587
GLShaderManager gl_shaderManager;
88+
GLBuffer luminanceBuffer( "luminance", Util::ordinal( BufferBind::LUMINANCE ), GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT );
8689

8790
namespace // Implementation details
8891
{
@@ -432,6 +435,9 @@ static const std::vector<addedExtension_t> fragmentVertexAddedExtensions = {
432435
where the core variables have different names. */
433436
{ glConfig2.shaderDrawParametersAvailable, -1, "ARB_shader_draw_parameters" },
434437
{ glConfig2.SSBOAvailable, 430, "ARB_shader_storage_buffer_object" },
438+
{ glConfig2.shadingLanguage420PackAvailable, 420, "ARB_shading_language_420pack" },
439+
{ glConfig2.explicitUniformLocationAvailable, 430, "ARB_explicit_uniform_location" },
440+
{ glConfig2.shaderAtomicCountersAvailable, 420, "ARB_shader_atomic_counters" },
435441
/* Even though these are part of the GL_KHR_shader_subgroup extension, we need to enable
436442
the individual extensions for each feature.
437443
GL_KHR_shader_subgroup itself can't be used in the shader. */
@@ -579,6 +585,10 @@ static std::string GenVertexHeader() {
579585
AddDefine( str, "BIND_LIGHTMAP_DATA", Util::ordinal( BufferBind::LIGHTMAP_DATA ) );
580586
}
581587

588+
if ( glConfig2.adaptiveExposureAvailable ) {
589+
AddDefine( str, "BIND_LUMINANCE", Util::ordinal( BufferBind::LUMINANCE ) );
590+
}
591+
582592
return str;
583593
}
584594

@@ -619,6 +629,10 @@ static std::string GenFragmentHeader() {
619629
AddDefine( str, "BIND_LIGHTMAP_DATA", Util::ordinal( BufferBind::LIGHTMAP_DATA ) );
620630
}
621631

632+
if ( glConfig2.adaptiveExposureAvailable ) {
633+
AddDefine( str, "BIND_LUMINANCE", Util::ordinal( BufferBind::LUMINANCE ) );
634+
}
635+
622636
return str;
623637
}
624638

@@ -644,6 +658,11 @@ static std::string GenComputeHeader() {
644658
AddDefine( str, "BIND_DEBUG", Util::ordinal( BufferBind::DEBUG ) );
645659
}
646660

661+
if ( glConfig2.adaptiveExposureAvailable ) {
662+
AddDefine( str, "BIND_LUMINANCE", Util::ordinal( BufferBind::LUMINANCE ) );
663+
AddDefine( str, "BIND_LUMINANCE_STORAGE", Util::ordinal( BufferBind::LUMINANCE_STORAGE ) );
664+
}
665+
647666
if ( glConfig2.usingBindlessTextures ) {
648667
str += "layout(bindless_image) uniform;\n";
649668
}
@@ -2816,6 +2835,23 @@ void GLShader_shadowFill::SetShaderProgramUniforms( ShaderProgramDescriptor *sha
28162835
glUniform1i( glGetUniformLocation( shaderProgram->id, "u_ColorMap" ), 0 );
28172836
}
28182837

2838+
GLShader_luminanceReduction::GLShader_luminanceReduction( GLShaderManager* manager ) :
2839+
GLShader( "luminanceReduction",
2840+
false, "luminanceReduction" ),
2841+
u_ViewWidth( this ),
2842+
u_ViewHeight( this ),
2843+
u_TonemapParms2( this ) {
2844+
}
2845+
2846+
void GLShader_luminanceReduction::SetShaderProgramUniforms( ShaderProgramDescriptor* shaderProgram ) {
2847+
glUniform1i( glGetUniformLocation( shaderProgram->id, "initialRenderImage" ), 0 );
2848+
}
2849+
2850+
GLShader_clearFrameData::GLShader_clearFrameData( GLShaderManager* manager ) :
2851+
GLShader( "clearFrameData",
2852+
false, "clearFrameData" ) {
2853+
}
2854+
28192855
GLShader_reflection::GLShader_reflection():
28202856
GLShader( "reflection", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT,
28212857
false, "reflection_CB", "reflection_CB" ),
@@ -3074,11 +3110,13 @@ GLShader_cameraEffects::GLShader_cameraEffects() :
30743110
u_CurrentMap( this ),
30753111
u_GlobalLightFactor( this ),
30763112
u_ColorModulate( this ),
3113+
u_ViewWidth( this ),
3114+
u_ViewHeight( this ),
30773115
u_Tonemap( this ),
3116+
u_TonemapAdaptiveExposure( this ),
30783117
u_TonemapParms( this ),
30793118
u_TonemapExposure( this ),
3080-
u_InverseGamma( this )
3081-
{
3119+
u_InverseGamma( this ) {
30823120
}
30833121

30843122
void GLShader_cameraEffects::SetShaderProgramUniforms( ShaderProgramDescriptor *shaderProgram )

src/engine/renderer/gl_shader.h

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4046,6 +4046,18 @@ class u_Tonemap :
40464046
}
40474047
};
40484048

4049+
class u_TonemapAdaptiveExposure :
4050+
GLUniform1Bool {
4051+
public:
4052+
u_TonemapAdaptiveExposure( GLShader* shader ) :
4053+
GLUniform1Bool( shader, "u_TonemapAdaptiveExposure", true ) {
4054+
}
4055+
4056+
void SetUniform_TonemapAdaptiveExposure( bool tonemapAdaptiveExposure ) {
4057+
this->SetValue( tonemapAdaptiveExposure );
4058+
}
4059+
};
4060+
40494061
class u_TonemapParms :
40504062
GLUniform4f {
40514063
public:
@@ -4058,6 +4070,18 @@ class u_TonemapParms :
40584070
}
40594071
};
40604072

4073+
class u_TonemapParms2 :
4074+
GLUniform4f {
4075+
public:
4076+
u_TonemapParms2( GLShader* shader ) :
4077+
GLUniform4f( shader, "u_TonemapParms2", true ) {
4078+
}
4079+
4080+
void SetUniform_TonemapParms2( vec4_t tonemapParms2 ) {
4081+
this->SetValue( tonemapParms2 );
4082+
}
4083+
};
4084+
40614085
class u_TonemapExposure :
40624086
GLUniform1f {
40634087
public:
@@ -4499,6 +4523,22 @@ class GLShader_shadowFill :
44994523
void SetShaderProgramUniforms( ShaderProgramDescriptor *shaderProgram ) override;
45004524
};
45014525

4526+
class GLShader_luminanceReduction :
4527+
public GLShader,
4528+
public u_ViewWidth,
4529+
public u_ViewHeight,
4530+
public u_TonemapParms2 {
4531+
public:
4532+
GLShader_luminanceReduction( GLShaderManager* manager );
4533+
void SetShaderProgramUniforms( ShaderProgramDescriptor* shaderProgram ) override;
4534+
};
4535+
4536+
class GLShader_clearFrameData :
4537+
public GLShader {
4538+
public:
4539+
GLShader_clearFrameData( GLShaderManager* manager );
4540+
};
4541+
45024542
class GLShader_reflection :
45034543
public GLShader,
45044544
public u_ColorMapCube,
@@ -4711,7 +4751,10 @@ class GLShader_cameraEffects :
47114751
public u_CurrentMap,
47124752
public u_GlobalLightFactor,
47134753
public u_ColorModulate,
4754+
public u_ViewWidth,
4755+
public u_ViewHeight,
47144756
public u_Tonemap,
4757+
public u_TonemapAdaptiveExposure,
47154758
public u_TonemapParms,
47164759
public u_TonemapExposure,
47174760
public u_InverseGamma
@@ -4943,9 +4986,11 @@ extern GLShader_fxaa *gl_fxaaShader;
49434986
extern GLShader_motionblur *gl_motionblurShader;
49444987
extern GLShader_ssao *gl_ssaoShader;
49454988

4946-
extern GLShader_depthtile1 *gl_depthtile1Shader;
4947-
extern GLShader_depthtile2 *gl_depthtile2Shader;
4948-
extern GLShader_lighttile *gl_lighttileShader;
4989+
extern GLShader_depthtile1* gl_depthtile1Shader;
4990+
extern GLShader_depthtile2* gl_depthtile2Shader;
4991+
extern GLShader_lighttile* gl_lighttileShader;
4992+
extern GLShader_luminanceReduction* gl_luminanceReductionShader;
4993+
extern GLShader_clearFrameData* gl_clearFrameDataShader;
49494994

49504995
extern GLShader_generic *gl_genericShader;
49514996
extern GLShader_genericMaterial *gl_genericShaderMaterial;
@@ -4970,5 +5015,6 @@ extern GLShader_skybox *gl_skyboxShader;
49705015
extern GLShader_skyboxMaterial *gl_skyboxShaderMaterial;
49715016
extern GLShader_debugShadowMap *gl_debugShadowMapShader;
49725017
extern GLShaderManager gl_shaderManager;
5018+
extern GLBuffer luminanceBuffer;
49735019

49745020
#endif // GL_SHADER_H

src/engine/renderer/glsl_source/cameraEffects_fp.glsl

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,24 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2525
uniform sampler2D u_CurrentMap;
2626

2727
#if defined(r_colorGrading)
28-
uniform sampler3D u_ColorMap3D;
28+
uniform sampler3D u_ColorMap3D;
2929
#endif
3030

31-
uniform vec4 u_ColorModulate;
32-
uniform float u_GlobalLightFactor; // 1 / tr.identityLight
33-
uniform float u_InverseGamma;
31+
uniform vec4 u_ColorModulate;
32+
uniform float u_GlobalLightFactor; // 1 / tr.identityLight
33+
uniform float u_InverseGamma;
3434

3535
// Tone mapping is not available when high-precision float framebuffer isn't enabled or supported.
3636
#if defined(r_highPrecisionRendering) && defined(HAVE_ARB_texture_float)
37+
uniform uint u_ViewWidth;
38+
uniform uint u_ViewHeight;
39+
40+
uniform bool u_Tonemap;
41+
uniform bool u_TonemapAdaptiveExposure;
3742
/* x: contrast
3843
y: highlightsCompressionSpeed
3944
z: shoulderClip
4045
w: highlightsCompression */
41-
uniform bool u_Tonemap;
4246
uniform vec4 u_TonemapParms;
4347
uniform float u_TonemapExposure;
4448

@@ -47,12 +51,21 @@ vec3 TonemapLottes( vec3 color ) {
4751
return pow( color, vec3( u_TonemapParms[0] ) )
4852
/ ( pow( color, vec3( u_TonemapParms[0] * u_TonemapParms[1] ) ) * u_TonemapParms[2] + u_TonemapParms[3] );
4953
}
54+
55+
#if defined(HAVE_ARB_explicit_uniform_location) && defined(HAVE_ARB_shader_atomic_counters)
56+
layout(std140, binding = BIND_LUMINANCE) uniform ub_LuminanceUBO {
57+
uint luminanceU;
58+
};
59+
#endif
60+
61+
float GetAverageLuminance( const in uint luminance ) {
62+
return float( luminanceU ) / ( 256.0f * u_ViewWidth * u_ViewHeight );
63+
}
5064
#endif
5165

5266
DECLARE_OUTPUT(vec4)
5367

54-
void main()
55-
{
68+
void main() {
5669
// calculate the screen texcoord in the 0.0 to 1.0 range
5770
vec2 st = gl_FragCoord.st / r_FBufSize;
5871

@@ -61,6 +74,13 @@ void main()
6174

6275
#if defined(r_highPrecisionRendering) && defined(HAVE_ARB_texture_float)
6376
if( u_Tonemap ) {
77+
#if defined(HAVE_ARB_explicit_uniform_location) && defined(HAVE_ARB_shader_atomic_counters)
78+
if( u_TonemapAdaptiveExposure ) {
79+
const float l = GetAverageLuminance( luminanceU ) - 8;
80+
color.rgb *= clamp( 0.18f / exp2( l * 0.8f + 0.1f ), 0.0f, 2.0f );
81+
}
82+
#endif
83+
6484
color.rgb = TonemapLottes( color.rgb * u_TonemapExposure );
6585
}
6686
#endif
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
===========================================================================
3+
4+
Daemon BSD Source Code
5+
Copyright (c) 2025 Daemon Developers
6+
All rights reserved.
7+
8+
This file is part of the Daemon BSD Source Code (Daemon Source Code).
9+
10+
Redistribution and use in source and binary forms, with or without
11+
modification, are permitted provided that the following conditions are met:
12+
* Redistributions of source code must retain the above copyright
13+
notice, this list of conditions and the following disclaimer.
14+
* Redistributions in binary form must reproduce the above copyright
15+
notice, this list of conditions and the following disclaimer in the
16+
documentation and/or other materials provided with the distribution.
17+
* Neither the name of the Daemon developers nor the
18+
names of its contributors may be used to endorse or promote products
19+
derived from this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
25+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
32+
===========================================================================
33+
*/
34+
35+
/* clearFrameData_cp.glsl */
36+
37+
#insert common_cp
38+
39+
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
40+
41+
layout(std430, binding = BIND_LUMINANCE_STORAGE) writeonly buffer luminanceBuffer {
42+
uint luminance;
43+
};
44+
45+
uniform uint u_Frame;
46+
47+
void main() {
48+
const uint globalInvocationID = GLOBAL_INVOCATION_ID;
49+
if( globalInvocationID >= 1 ) {
50+
return;
51+
}
52+
luminance = 0;
53+
}

src/engine/renderer/glsl_source/common_cp.glsl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ array must be in the form of uvec4 array[] */
5656

5757
/* Macro combinations for subgroup ops */
5858

59+
#if defined(HAVE_KHR_shader_subgroup_basic) && defined(HAVE_KHR_shader_subgroup_arithmetic)\
60+
&& defined(HAVE_ARB_shader_atomic_counter_ops)
61+
#define SUBGROUP_ATOMIC
62+
#endif
63+
5964
#if defined(HAVE_KHR_shader_subgroup_basic) && defined(HAVE_KHR_shader_subgroup_arithmetic)\
6065
&& defined(HAVE_KHR_shader_subgroup_ballot) && defined(HAVE_ARB_shader_atomic_counter_ops)
6166
#define SUBGROUP_STREAM_COMPACTION

0 commit comments

Comments
 (0)