Skip to content

Commit 90becba

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 32f6889 commit 90becba

18 files changed

+337
-13
lines changed

libs/crunch

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
{
@@ -429,6 +432,9 @@ static const std::vector<addedExtension_t> fragmentVertexAddedExtensions = {
429432
where the core variables have different names. */
430433
{ glConfig2.shaderDrawParametersAvailable, -1, "ARB_shader_draw_parameters" },
431434
{ glConfig2.SSBOAvailable, 430, "ARB_shader_storage_buffer_object" },
435+
{ glConfig2.shadingLanguage420PackAvailable, 420, "ARB_shading_language_420pack" },
436+
{ glConfig2.explicitUniformLocationAvailable, 430, "ARB_explicit_uniform_location" },
437+
{ glConfig2.shaderAtomicCountersAvailable, 420, "ARB_shader_atomic_counters" },
432438
/* Even though these are part of the GL_KHR_shader_subgroup extension, we need to enable
433439
the individual extensions for each feature.
434440
GL_KHR_shader_subgroup itself can't be used in the shader. */
@@ -576,6 +582,10 @@ static std::string GenVertexHeader() {
576582
AddDefine( str, "BIND_LIGHTMAP_DATA", Util::ordinal( BufferBind::LIGHTMAP_DATA ) );
577583
}
578584

585+
if ( glConfig2.adaptiveExposureAvailable ) {
586+
AddDefine( str, "BIND_LUMINANCE", Util::ordinal( BufferBind::LUMINANCE ) );
587+
}
588+
579589
return str;
580590
}
581591

@@ -616,6 +626,10 @@ static std::string GenFragmentHeader() {
616626
AddDefine( str, "BIND_LIGHTMAP_DATA", Util::ordinal( BufferBind::LIGHTMAP_DATA ) );
617627
}
618628

629+
if ( glConfig2.adaptiveExposureAvailable ) {
630+
AddDefine( str, "BIND_LUMINANCE", Util::ordinal( BufferBind::LUMINANCE ) );
631+
}
632+
619633
return str;
620634
}
621635

@@ -641,6 +655,11 @@ static std::string GenComputeHeader() {
641655
AddDefine( str, "BIND_DEBUG", Util::ordinal( BufferBind::DEBUG ) );
642656
}
643657

658+
if ( glConfig2.adaptiveExposureAvailable ) {
659+
AddDefine( str, "BIND_LUMINANCE", Util::ordinal( BufferBind::LUMINANCE ) );
660+
AddDefine( str, "BIND_LUMINANCE_STORAGE", Util::ordinal( BufferBind::LUMINANCE_STORAGE ) );
661+
}
662+
644663
if ( glConfig2.usingBindlessTextures ) {
645664
str += "layout(bindless_image) uniform;\n";
646665
}
@@ -2772,6 +2791,17 @@ void GLShader_forwardLighting_directionalSun::SetShaderProgramUniforms( ShaderPr
27722791
glUniform1i( glGetUniformLocation( shaderProgram->id, "u_HeightMap" ), 15 );
27732792
}
27742793

2794+
GLShader_luminanceReduction::GLShader_luminanceReduction( GLShaderManager* manager ) :
2795+
GLShader( "luminanceReduction", 0, manager, false, false, true ),
2796+
u_ViewWidth( this ),
2797+
u_ViewHeight( this ),
2798+
u_TonemapParms2( this ) {
2799+
}
2800+
2801+
void GLShader_luminanceReduction::SetShaderProgramUniforms( ShaderProgramDescriptor* shaderProgram ) {
2802+
glUniform1i( glGetUniformLocation( shaderProgram->id, "initialRenderImage" ), 0 );
2803+
}
2804+
27752805
GLShader_shadowFill::GLShader_shadowFill( GLShaderManager *manager ) :
27762806
GLShader( "shadowFill", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ),
27772807
u_ColorMap( this ),
@@ -3043,7 +3073,10 @@ GLShader_cameraEffects::GLShader_cameraEffects( GLShaderManager *manager ) :
30433073
u_ColorModulate( this ),
30443074
u_TextureMatrix( this ),
30453075
u_ModelViewProjectionMatrix( this ),
3076+
u_ViewWidth( this ),
3077+
u_ViewHeight( this ),
30463078
u_Tonemap( this ),
3079+
u_TonemapAdaptiveExposure( this ),
30473080
u_TonemapParms( this ),
30483081
u_TonemapExposure( this ),
30493082
u_InverseGamma( this )
@@ -3256,6 +3289,10 @@ void GLShader_fxaa::SetShaderProgramUniforms( ShaderProgramDescriptor *shaderPro
32563289
glUniform1i( glGetUniformLocation( shaderProgram->id, "u_ColorMap" ), 0 );
32573290
}
32583291

3292+
GLShader_clearFrameData::GLShader_clearFrameData( GLShaderManager* manager ) :
3293+
GLShader( "clearFrameData", 0, manager, false, false, true ) {
3294+
}
3295+
32593296
GLShader_cull::GLShader_cull( GLShaderManager* manager ) :
32603297
GLShader( "cull", ATTR_POSITION, manager, false, false, true ),
32613298
u_Frame( this ),

src/engine/renderer/gl_shader.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3934,6 +3934,18 @@ class u_Tonemap :
39343934
}
39353935
};
39363936

3937+
class u_TonemapAdaptiveExposure :
3938+
GLUniform1Bool {
3939+
public:
3940+
u_TonemapAdaptiveExposure( GLShader* shader ) :
3941+
GLUniform1Bool( shader, "u_TonemapAdaptiveExposure", true ) {
3942+
}
3943+
3944+
void SetUniform_TonemapAdaptiveExposure( bool tonemapAdaptiveExposure ) {
3945+
this->SetValue( tonemapAdaptiveExposure );
3946+
}
3947+
};
3948+
39373949
class u_TonemapParms :
39383950
GLUniform4f {
39393951
public:
@@ -3946,6 +3958,18 @@ class u_TonemapParms :
39463958
}
39473959
};
39483960

3961+
class u_TonemapParms2 :
3962+
GLUniform4f {
3963+
public:
3964+
u_TonemapParms2( GLShader* shader ) :
3965+
GLUniform4f( shader, "u_TonemapParms2", true ) {
3966+
}
3967+
3968+
void SetUniform_TonemapParms2( vec4_t tonemapParms2 ) {
3969+
this->SetValue( tonemapParms2 );
3970+
}
3971+
};
3972+
39493973
class u_TonemapExposure :
39503974
GLUniform1f {
39513975
public:
@@ -4354,6 +4378,16 @@ class GLShader_forwardLighting_directionalSun :
43544378
void SetShaderProgramUniforms( ShaderProgramDescriptor *shaderProgram ) override;
43554379
};
43564380

4381+
class GLShader_luminanceReduction :
4382+
public GLShader,
4383+
public u_ViewWidth,
4384+
public u_ViewHeight,
4385+
public u_TonemapParms2 {
4386+
public:
4387+
GLShader_luminanceReduction( GLShaderManager* manager );
4388+
void SetShaderProgramUniforms( ShaderProgramDescriptor* shaderProgram ) override;
4389+
};
4390+
43574391
class GLShader_shadowFill :
43584392
public GLShader,
43594393
public u_ColorMap,
@@ -4591,7 +4625,10 @@ class GLShader_cameraEffects :
45914625
public u_ColorModulate,
45924626
public u_TextureMatrix,
45934627
public u_ModelViewProjectionMatrix,
4628+
public u_ViewWidth,
4629+
public u_ViewHeight,
45944630
public u_Tonemap,
4631+
public u_TonemapAdaptiveExposure,
45954632
public u_TonemapParms,
45964633
public u_TonemapExposure,
45974634
public u_InverseGamma
@@ -4765,6 +4802,12 @@ class GLShader_fxaa :
47654802
void SetShaderProgramUniforms( ShaderProgramDescriptor *shaderProgram ) override;
47664803
};
47674804

4805+
class GLShader_clearFrameData :
4806+
public GLShader {
4807+
public:
4808+
GLShader_clearFrameData( GLShaderManager* manager );
4809+
};
4810+
47684811
class GLShader_cull :
47694812
public GLShader,
47704813
public u_Frame,
@@ -4819,6 +4862,7 @@ extern ShaderKind shaderKind;
48194862

48204863
extern GLShader_generic *gl_genericShader;
48214864
extern GLShader_genericMaterial *gl_genericShaderMaterial;
4865+
extern GLShader_clearFrameData *gl_clearFrameDataShader;
48224866
extern GLShader_cull *gl_cullShader;
48234867
extern GLShader_depthReduction *gl_depthReductionShader;
48244868
extern GLShader_clearSurfaces *gl_clearSurfacesShader;
@@ -4828,6 +4872,7 @@ extern GLShader_lightMappingMaterial *gl_lightMappingShaderMaterial;
48284872
extern GLShader_forwardLighting_omniXYZ *gl_forwardLightingShader_omniXYZ;
48294873
extern GLShader_forwardLighting_projXYZ *gl_forwardLightingShader_projXYZ;
48304874
extern GLShader_forwardLighting_directionalSun *gl_forwardLightingShader_directionalSun;
4875+
extern GLShader_luminanceReduction *gl_luminanceReductionShader;
48314876
extern GLShader_shadowFill *gl_shadowFillShader;
48324877
extern GLShader_reflection *gl_reflectionShader;
48334878
extern GLShader_reflectionMaterial *gl_reflectionShaderMaterial;
@@ -4854,5 +4899,6 @@ extern GLShader_depthtile2 *gl_depthtile2Shader;
48544899
extern GLShader_lighttile *gl_lighttileShader;
48554900
extern GLShader_fxaa *gl_fxaaShader;
48564901
extern GLShaderManager gl_shaderManager;
4902+
extern GLBuffer luminanceBuffer;
48574903

48584904
#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,24 +25,34 @@ 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

3945
// Tone mapping is not available when high-precision float framebuffer isn't enabled or supported.
4046
#if defined(r_highPrecisionRendering) && defined(HAVE_ARB_texture_float)
47+
uniform uint u_ViewWidth;
48+
uniform uint u_ViewHeight;
49+
50+
uniform bool u_Tonemap;
51+
uniform bool u_TonemapAdaptiveExposure;
4152
/* x: contrast
4253
y: highlightsCompressionSpeed
4354
z: shoulderClip
4455
w: highlightsCompression */
45-
uniform bool u_Tonemap;
4656
uniform vec4 u_TonemapParms;
4757
uniform float u_TonemapExposure;
4858

@@ -53,8 +63,11 @@ vec3 TonemapLottes( vec3 color ) {
5363
}
5464
#endif
5565

56-
void main()
57-
{
66+
float GetAverageLuminance( const in uint luminance ) {
67+
return float( luminanceU ) / ( 256.0f * u_ViewWidth * u_ViewHeight );
68+
}
69+
70+
void main() {
5871
// calculate the screen texcoord in the 0.0 to 1.0 range
5972
vec2 st = gl_FragCoord.st / r_FBufSize;
6073

@@ -63,6 +76,13 @@ void main()
6376

6477
#if defined(r_highPrecisionRendering) && defined(HAVE_ARB_texture_float)
6578
if( u_Tonemap ) {
79+
#if defined(HAVE_ARB_explicit_uniform_location) && defined(HAVE_ARB_shader_atomic_counters)
80+
if( u_TonemapAdaptiveExposure ) {
81+
const float l = GetAverageLuminance( luminanceU ) - 8;
82+
color.rgb *= clamp( 0.18f / exp2( l * 0.8f + 0.1f ), 0.0f, 2.0f );
83+
}
84+
#endif
85+
6686
color.rgb = TonemapLottes( color.rgb * u_TonemapExposure );
6787
}
6888
#endif
@@ -82,4 +102,5 @@ void main()
82102
color.xyz = pow(color.xyz, vec3(u_InverseGamma));
83103

84104
outputColor = color;
105+
// outputColor = vec4( luminance, color.yzw );
85106
}
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)