Skip to content

Commit d7b2a06

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 e12cb5a commit d7b2a06

17 files changed

+336
-13
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 ),
@@ -2901,7 +2931,10 @@ GLShader_cameraEffects::GLShader_cameraEffects( GLShaderManager *manager ) :
29012931
u_ColorModulate( this ),
29022932
u_TextureMatrix( this ),
29032933
u_ModelViewProjectionMatrix( this ),
2934+
u_ViewWidth( this ),
2935+
u_ViewHeight( this ),
29042936
u_Tonemap( this ),
2937+
u_TonemapAdaptiveExposure( this ),
29052938
u_TonemapParms( this ),
29062939
u_TonemapExposure( this ),
29072940
u_InverseGamma( this )
@@ -3114,6 +3147,10 @@ void GLShader_fxaa::SetShaderProgramUniforms( shaderProgram_t *shaderProgram )
31143147
glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 );
31153148
}
31163149

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

src/engine/renderer/gl_shader.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3821,6 +3821,18 @@ class u_Tonemap :
38213821
}
38223822
};
38233823

3824+
class u_TonemapAdaptiveExposure :
3825+
GLUniform1Bool {
3826+
public:
3827+
u_TonemapAdaptiveExposure( GLShader* shader ) :
3828+
GLUniform1Bool( shader, "u_TonemapAdaptiveExposure", true ) {
3829+
}
3830+
3831+
void SetUniform_TonemapAdaptiveExposure( bool tonemapAdaptiveExposure ) {
3832+
this->SetValue( tonemapAdaptiveExposure );
3833+
}
3834+
};
3835+
38243836
class u_TonemapParms :
38253837
GLUniform4f {
38263838
public:
@@ -3833,6 +3845,18 @@ class u_TonemapParms :
38333845
}
38343846
};
38353847

3848+
class u_TonemapParms2 :
3849+
GLUniform4f {
3850+
public:
3851+
u_TonemapParms2( GLShader* shader ) :
3852+
GLUniform4f( shader, "u_TonemapParms2", true ) {
3853+
}
3854+
3855+
void SetUniform_TonemapParms2( vec4_t tonemapParms2 ) {
3856+
this->SetValue( tonemapParms2 );
3857+
}
3858+
};
3859+
38363860
class u_TonemapExposure :
38373861
GLUniform1f {
38383862
public:
@@ -4241,6 +4265,16 @@ class GLShader_forwardLighting_directionalSun :
42414265
void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override;
42424266
};
42434267

4268+
class GLShader_luminanceReduction :
4269+
public GLShader,
4270+
public u_ViewWidth,
4271+
public u_ViewHeight,
4272+
public u_TonemapParms2 {
4273+
public:
4274+
GLShader_luminanceReduction( GLShaderManager* manager );
4275+
void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override;
4276+
};
4277+
42444278
class GLShader_shadowFill :
42454279
public GLShader,
42464280
public u_ColorMap,
@@ -4478,7 +4512,10 @@ class GLShader_cameraEffects :
44784512
public u_ColorModulate,
44794513
public u_TextureMatrix,
44804514
public u_ModelViewProjectionMatrix,
4515+
public u_ViewWidth,
4516+
public u_ViewHeight,
44814517
public u_Tonemap,
4518+
public u_TonemapAdaptiveExposure,
44824519
public u_TonemapParms,
44834520
public u_TonemapExposure,
44844521
public u_InverseGamma
@@ -4652,6 +4689,12 @@ class GLShader_fxaa :
46524689
void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override;
46534690
};
46544691

4692+
class GLShader_clearFrameData :
4693+
public GLShader {
4694+
public:
4695+
GLShader_clearFrameData( GLShaderManager* manager );
4696+
};
4697+
46554698
class GLShader_cull :
46564699
public GLShader,
46574700
public u_Frame,
@@ -4706,6 +4749,7 @@ extern ShaderKind shaderKind;
47064749

47074750
extern GLShader_generic *gl_genericShader;
47084751
extern GLShader_genericMaterial *gl_genericShaderMaterial;
4752+
extern GLShader_clearFrameData *gl_clearFrameDataShader;
47094753
extern GLShader_cull *gl_cullShader;
47104754
extern GLShader_depthReduction *gl_depthReductionShader;
47114755
extern GLShader_clearSurfaces *gl_clearSurfacesShader;
@@ -4715,6 +4759,7 @@ extern GLShader_lightMappingMaterial *gl_lightMappingShaderMaterial;
47154759
extern GLShader_forwardLighting_omniXYZ *gl_forwardLightingShader_omniXYZ;
47164760
extern GLShader_forwardLighting_projXYZ *gl_forwardLightingShader_projXYZ;
47174761
extern GLShader_forwardLighting_directionalSun *gl_forwardLightingShader_directionalSun;
4762+
extern GLShader_luminanceReduction *gl_luminanceReductionShader;
47184763
extern GLShader_shadowFill *gl_shadowFillShader;
47194764
extern GLShader_reflection *gl_reflectionShader;
47204765
extern GLShader_reflectionMaterial *gl_reflectionShaderMaterial;
@@ -4741,5 +4786,6 @@ extern GLShader_depthtile2 *gl_depthtile2Shader;
47414786
extern GLShader_lighttile *gl_lighttileShader;
47424787
extern GLShader_fxaa *gl_fxaaShader;
47434788
extern GLShaderManager gl_shaderManager;
4789+
extern GLBuffer luminanceBuffer;
47444790

47454791
#endif // GL_SHADER_H

src/engine/renderer/glsl_source/cameraEffects_fp.glsl

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,32 @@ 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+
#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_GlobalLightFactor; // 1 / tr.identityLight
39+
uniform float u_InverseGamma;
3440

35-
IN(smooth) vec2 var_TexCoords;
41+
IN(smooth) vec2 var_TexCoords;
3642

3743
DECLARE_OUTPUT(vec4)
3844

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

@@ -50,15 +60,25 @@ vec3 TonemapLottes( vec3 color ) {
5060
/ ( pow( color, vec3( u_TonemapParms[0] * u_TonemapParms[1] ) ) * u_TonemapParms[2] + u_TonemapParms[3] );
5161
}
5262

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

5871
vec4 color = texture2D(u_CurrentMap, st);
5972
color *= u_GlobalLightFactor;
6073

6174
if( u_Tonemap ) {
75+
#if defined(HAVE_ARB_explicit_uniform_location) && defined(HAVE_ARB_shader_atomic_counters)
76+
if( u_TonemapAdaptiveExposure ) {
77+
const float l = GetAverageLuminance( luminanceU ) - 8;
78+
color.rgb *= clamp( 0.18f / exp2( l * 0.8f + 0.1f ), 0.0f, 2.0f );
79+
}
80+
#endif
81+
6282
color.rgb = TonemapLottes( color.rgb * u_TonemapExposure );
6383
}
6484
color.rgb = clamp( color.rgb, vec3( 0.0f ), vec3( 1.0f ) );
@@ -76,4 +96,5 @@ void main()
7696
color.xyz = pow(color.xyz, vec3(u_InverseGamma));
7797

7898
outputColor = color;
99+
// outputColor = vec4( luminance, color.yzw );
79100
}
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)