Skip to content

Commit 01ab8df

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 96f0611 commit 01ab8df

17 files changed

+335
-12
lines changed

src.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ set(GLSLSOURCELIST
143143
${ENGINE_DIR}/renderer/glsl_source/common_cp.glsl
144144
${ENGINE_DIR}/renderer/glsl_source/shaderProfiler_vp.glsl
145145
${ENGINE_DIR}/renderer/glsl_source/shaderProfiler_fp.glsl
146+
${ENGINE_DIR}/renderer/glsl_source/clearFrameData_cp.glsl
146147
${ENGINE_DIR}/renderer/glsl_source/clearSurfaces_cp.glsl
147148
${ENGINE_DIR}/renderer/glsl_source/cull_cp.glsl
148149
${ENGINE_DIR}/renderer/glsl_source/depthReduction_cp.glsl
@@ -161,6 +162,7 @@ set(GLSLSOURCELIST
161162
${ENGINE_DIR}/renderer/glsl_source/cameraEffects_fp.glsl
162163
${ENGINE_DIR}/renderer/glsl_source/cameraEffects_vp.glsl
163164
${ENGINE_DIR}/renderer/glsl_source/computeLight_fp.glsl
165+
${ENGINE_DIR}/renderer/glsl_source/luminanceReduction_cp.glsl
164166
${ENGINE_DIR}/renderer/glsl_source/contrast_fp.glsl
165167
${ENGINE_DIR}/renderer/glsl_source/contrast_vp.glsl
166168
${ENGINE_DIR}/renderer/glsl_source/debugShadowMap_fp.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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ ShaderKind shaderKind = ShaderKind::Unknown;
4545

4646
GLShader_generic *gl_genericShader = nullptr;
4747
GLShader_genericMaterial *gl_genericShaderMaterial = nullptr;
48+
GLShader_clearFrameData *gl_clearFrameDataShader = nullptr;
4849
GLShader_cull *gl_cullShader = nullptr;
4950
GLShader_depthReduction *gl_depthReductionShader = nullptr;
5051
GLShader_clearSurfaces *gl_clearSurfacesShader = nullptr;
@@ -54,6 +55,7 @@ GLShader_lightMappingMaterial *gl_lightMappingShaderMaterial = nullpt
5455
GLShader_forwardLighting_omniXYZ *gl_forwardLightingShader_omniXYZ = nullptr;
5556
GLShader_forwardLighting_projXYZ *gl_forwardLightingShader_projXYZ = nullptr;
5657
GLShader_forwardLighting_directionalSun *gl_forwardLightingShader_directionalSun = nullptr;
58+
GLShader_luminanceReduction *gl_luminanceReductionShader = nullptr;
5759
GLShader_shadowFill *gl_shadowFillShader = nullptr;
5860
GLShader_reflection *gl_reflectionShader = nullptr;
5961
GLShader_reflectionMaterial *gl_reflectionShaderMaterial = nullptr;
@@ -80,6 +82,7 @@ GLShader_depthtile2 *gl_depthtile2Shader = nullptr;
8082
GLShader_lighttile *gl_lighttileShader = nullptr;
8183
GLShader_fxaa *gl_fxaaShader = nullptr;
8284
GLShaderManager gl_shaderManager;
85+
GLBuffer luminanceBuffer( "luminance", Util::ordinal( BufferBind::LUMINANCE ), GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT );
8386

8487
namespace // Implementation details
8588
{
@@ -405,6 +408,9 @@ static const std::vector<addedExtension_t> fragmentVertexAddedExtensions = {
405408
where the core variables have different names. */
406409
{ glConfig2.shaderDrawParametersAvailable, -1, "ARB_shader_draw_parameters" },
407410
{ glConfig2.SSBOAvailable, 430, "ARB_shader_storage_buffer_object" },
411+
{ glConfig2.shadingLanguage420PackAvailable, 420, "ARB_shading_language_420pack" },
412+
{ glConfig2.explicitUniformLocationAvailable, 430, "ARB_explicit_uniform_location" },
413+
{ glConfig2.shaderAtomicCountersAvailable, 420, "ARB_shader_atomic_counters" },
408414
/* Even though these are part of the GL_KHR_shader_subgroup extension, we need to enable
409415
the individual extensions for each feature.
410416
GL_KHR_shader_subgroup itself can't be used in the shader. */
@@ -552,6 +558,10 @@ static std::string GenVertexHeader() {
552558
AddDefine( str, "BIND_LIGHTMAP_DATA", Util::ordinal( BufferBind::LIGHTMAP_DATA ) );
553559
}
554560

561+
if ( glConfig2.adaptiveExposureAvailable ) {
562+
AddDefine( str, "BIND_LUMINANCE", Util::ordinal( BufferBind::LUMINANCE ) );
563+
}
564+
555565
return str;
556566
}
557567

@@ -592,6 +602,10 @@ static std::string GenFragmentHeader() {
592602
AddDefine( str, "BIND_LIGHTMAP_DATA", Util::ordinal( BufferBind::LIGHTMAP_DATA ) );
593603
}
594604

605+
if ( glConfig2.adaptiveExposureAvailable ) {
606+
AddDefine( str, "BIND_LUMINANCE", Util::ordinal( BufferBind::LUMINANCE ) );
607+
}
608+
595609
return str;
596610
}
597611

@@ -617,6 +631,11 @@ static std::string GenComputeHeader() {
617631
AddDefine( str, "BIND_DEBUG", Util::ordinal( BufferBind::DEBUG ) );
618632
}
619633

634+
if ( glConfig2.adaptiveExposureAvailable ) {
635+
AddDefine( str, "BIND_LUMINANCE", Util::ordinal( BufferBind::LUMINANCE ) );
636+
AddDefine( str, "BIND_LUMINANCE_STORAGE", Util::ordinal( BufferBind::LUMINANCE_STORAGE ) );
637+
}
638+
620639
if ( glConfig2.usingBindlessTextures ) {
621640
str += "layout(bindless_image) uniform;\n";
622641
}
@@ -2630,6 +2649,17 @@ void GLShader_forwardLighting_directionalSun::SetShaderProgramUniforms( shaderPr
26302649
glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 );
26312650
}
26322651

2652+
GLShader_luminanceReduction::GLShader_luminanceReduction( GLShaderManager* manager ) :
2653+
GLShader( "luminanceReduction", 0, manager, false, false, true ),
2654+
u_ViewWidth( this ),
2655+
u_ViewHeight( this ),
2656+
u_TonemapParms2( this ) {
2657+
}
2658+
2659+
void GLShader_luminanceReduction::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) {
2660+
glUniform1i( glGetUniformLocation( shaderProgram->program, "initialRenderImage" ), 0 );
2661+
}
2662+
26332663
GLShader_shadowFill::GLShader_shadowFill( GLShaderManager *manager ) :
26342664
GLShader( "shadowFill", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ),
26352665
u_ColorMap( this ),
@@ -2900,7 +2930,10 @@ GLShader_cameraEffects::GLShader_cameraEffects( GLShaderManager *manager ) :
29002930
u_ColorModulate( this ),
29012931
u_TextureMatrix( this ),
29022932
u_ModelViewProjectionMatrix( this ),
2933+
u_ViewWidth( this ),
2934+
u_ViewHeight( this ),
29032935
u_Tonemap( this ),
2936+
u_TonemapAdaptiveExposure( this ),
29042937
u_TonemapParms( this ),
29052938
u_TonemapExposure( this ),
29062939
u_InverseGamma( this )
@@ -3113,6 +3146,10 @@ void GLShader_fxaa::SetShaderProgramUniforms( shaderProgram_t *shaderProgram )
31133146
glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 );
31143147
}
31153148

3149+
GLShader_clearFrameData::GLShader_clearFrameData( GLShaderManager* manager ) :
3150+
GLShader( "clearFrameData", 0, manager, false, false, true ) {
3151+
}
3152+
31163153
GLShader_cull::GLShader_cull( GLShaderManager* manager ) :
31173154
GLShader( "cull", ATTR_POSITION, manager, false, false, true ),
31183155
u_Frame( this ),

src/engine/renderer/gl_shader.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3806,6 +3806,18 @@ class u_Tonemap :
38063806
}
38073807
};
38083808

3809+
class u_TonemapAdaptiveExposure :
3810+
GLUniform1Bool {
3811+
public:
3812+
u_TonemapAdaptiveExposure( GLShader* shader ) :
3813+
GLUniform1Bool( shader, "u_TonemapAdaptiveExposure", true ) {
3814+
}
3815+
3816+
void SetUniform_TonemapAdaptiveExposure( bool tonemapAdaptiveExposure ) {
3817+
this->SetValue( tonemapAdaptiveExposure );
3818+
}
3819+
};
3820+
38093821
class u_TonemapParms :
38103822
GLUniform4f {
38113823
public:
@@ -3818,6 +3830,18 @@ class u_TonemapParms :
38183830
}
38193831
};
38203832

3833+
class u_TonemapParms2 :
3834+
GLUniform4f {
3835+
public:
3836+
u_TonemapParms2( GLShader* shader ) :
3837+
GLUniform4f( shader, "u_TonemapParms2", true ) {
3838+
}
3839+
3840+
void SetUniform_TonemapParms2( vec4_t tonemapParms2 ) {
3841+
this->SetValue( tonemapParms2 );
3842+
}
3843+
};
3844+
38213845
class u_TonemapExposure :
38223846
GLUniform1f {
38233847
public:
@@ -4226,6 +4250,16 @@ class GLShader_forwardLighting_directionalSun :
42264250
void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override;
42274251
};
42284252

4253+
class GLShader_luminanceReduction :
4254+
public GLShader,
4255+
public u_ViewWidth,
4256+
public u_ViewHeight,
4257+
public u_TonemapParms2 {
4258+
public:
4259+
GLShader_luminanceReduction( GLShaderManager* manager );
4260+
void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override;
4261+
};
4262+
42294263
class GLShader_shadowFill :
42304264
public GLShader,
42314265
public u_ColorMap,
@@ -4462,7 +4496,10 @@ class GLShader_cameraEffects :
44624496
public u_ColorModulate,
44634497
public u_TextureMatrix,
44644498
public u_ModelViewProjectionMatrix,
4499+
public u_ViewWidth,
4500+
public u_ViewHeight,
44654501
public u_Tonemap,
4502+
public u_TonemapAdaptiveExposure,
44664503
public u_TonemapParms,
44674504
public u_TonemapExposure,
44684505
public u_InverseGamma
@@ -4636,6 +4673,12 @@ class GLShader_fxaa :
46364673
void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override;
46374674
};
46384675

4676+
class GLShader_clearFrameData :
4677+
public GLShader {
4678+
public:
4679+
GLShader_clearFrameData( GLShaderManager* manager );
4680+
};
4681+
46394682
class GLShader_cull :
46404683
public GLShader,
46414684
public u_Frame,
@@ -4690,6 +4733,7 @@ extern ShaderKind shaderKind;
46904733

46914734
extern GLShader_generic *gl_genericShader;
46924735
extern GLShader_genericMaterial *gl_genericShaderMaterial;
4736+
extern GLShader_clearFrameData *gl_clearFrameDataShader;
46934737
extern GLShader_cull *gl_cullShader;
46944738
extern GLShader_depthReduction *gl_depthReductionShader;
46954739
extern GLShader_clearSurfaces *gl_clearSurfacesShader;
@@ -4699,6 +4743,7 @@ extern GLShader_lightMappingMaterial *gl_lightMappingShaderMaterial;
46994743
extern GLShader_forwardLighting_omniXYZ *gl_forwardLightingShader_omniXYZ;
47004744
extern GLShader_forwardLighting_projXYZ *gl_forwardLightingShader_projXYZ;
47014745
extern GLShader_forwardLighting_directionalSun *gl_forwardLightingShader_directionalSun;
4746+
extern GLShader_luminanceReduction *gl_luminanceReductionShader;
47024747
extern GLShader_shadowFill *gl_shadowFillShader;
47034748
extern GLShader_reflection *gl_reflectionShader;
47044749
extern GLShader_reflectionMaterial *gl_reflectionShaderMaterial;
@@ -4725,5 +4770,6 @@ extern GLShader_depthtile2 *gl_depthtile2Shader;
47254770
extern GLShader_lighttile *gl_lighttileShader;
47264771
extern GLShader_fxaa *gl_fxaaShader;
47274772
extern GLShaderManager gl_shaderManager;
4773+
extern GLBuffer luminanceBuffer;
47284774

47294775
#endif // GL_SHADER_H

src/engine/renderer/glsl_source/cameraEffects_fp.glsl

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,31 @@ 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_InverseGamma;
31+
#if defined(HAVE_ARB_explicit_uniform_location) && defined(HAVE_ARB_shader_atomic_counters)
32+
layout(std140, binding = BIND_LUMINANCE) uniform ub_LuminanceUBO {
33+
uint luminanceU;
34+
};
35+
#endif
36+
37+
uniform vec4 u_ColorModulate;
38+
uniform float u_InverseGamma;
3339

34-
IN(smooth) vec2 var_TexCoords;
40+
IN(smooth) vec2 var_TexCoords;
3541

3642
DECLARE_OUTPUT(vec4)
3743

44+
uniform uint u_ViewWidth;
45+
uniform uint u_ViewHeight;
46+
47+
uniform bool u_Tonemap;
48+
uniform bool u_TonemapAdaptiveExposure;
3849
/* x: contrast
3950
y: highlightsCompressionSpeed
4051
z: shoulderClip
4152
w: highlightsCompression */
42-
uniform bool u_Tonemap;
4353
uniform vec4 u_TonemapParms;
4454
uniform float u_TonemapExposure;
4555

@@ -49,14 +59,24 @@ vec3 TonemapLottes( vec3 color ) {
4959
/ ( pow( color, vec3( u_TonemapParms[0] * u_TonemapParms[1] ) ) * u_TonemapParms[2] + u_TonemapParms[3] );
5060
}
5161

52-
void main()
53-
{
62+
float GetAverageLuminance( const in uint luminance ) {
63+
return float( luminanceU ) / ( 256.0f * u_ViewWidth * u_ViewHeight );
64+
}
65+
66+
void main() {
5467
// calculate the screen texcoord in the 0.0 to 1.0 range
5568
vec2 st = gl_FragCoord.st / r_FBufSize;
5669

5770
vec4 color = texture2D(u_CurrentMap, st);
5871

5972
if( u_Tonemap ) {
73+
#if defined(HAVE_ARB_explicit_uniform_location) && defined(HAVE_ARB_shader_atomic_counters)
74+
if( u_TonemapAdaptiveExposure ) {
75+
const float l = GetAverageLuminance( luminanceU ) - 8;
76+
color.rgb *= clamp( 0.18f / exp2( l * 0.8f + 0.1f ), 0.0f, 2.0f );
77+
}
78+
#endif
79+
6080
color.rgb = TonemapLottes( color.rgb * u_TonemapExposure );
6181
}
6282
color.rgb = clamp( color.rgb, vec3( 0.0f ), vec3( 1.0f ) );
@@ -74,4 +94,5 @@ void main()
7494
color.xyz = pow(color.xyz, vec3(u_InverseGamma));
7595

7696
outputColor = color;
97+
// outputColor = vec4( luminance, color.yzw );
7798
}
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)