Skip to content

Commit 2be2cbb

Browse files
committed
Merge pull request godotengine#107782 from allenwp/vulkan-nonlinear-color-correction-dithering
Always perform color correction and debanding on nonlinear sRGB values.
2 parents b602159 + a159151 commit 2be2cbb

File tree

15 files changed

+82
-20
lines changed

15 files changed

+82
-20
lines changed

doc/classes/ProjectSettings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2744,7 +2744,7 @@
27442744
[b]Note:[/b] This property is only read when the project starts. There is currently no way to change this setting at run-time.
27452745
</member>
27462746
<member name="rendering/anti_aliasing/quality/use_debanding" type="bool" setter="" getter="" default="false">
2747-
If [code]true[/code], uses a fast post-processing filter to make banding significantly less visible in 3D. 2D rendering is [i]not[/i] affected by debanding unless the [member Environment.background_mode] is [constant Environment.BG_CANVAS].
2747+
If [code]true[/code], uses a fast post-processing filter to make banding significantly less visible. If [member rendering/viewport/hdr_2d] is [code]false[/code], 2D rendering is [i]not[/i] affected by debanding unless the [member Environment.background_mode] is [constant Environment.BG_CANVAS]. If [member rendering/viewport/hdr_2d] is [code]true[/code], debanding will affect all 2D and 3D rendering, including canvas items.
27482748
In some cases, debanding may introduce a slightly noticeable dithering pattern. It's recommended to enable debanding only when actually needed since the dithering pattern will make lossless-compressed screenshots larger.
27492749
[b]Note:[/b] This property is only read when the project starts. To set debanding at runtime, set [member Viewport.use_debanding] on the root [Viewport] instead, or use [method RenderingServer.viewport_set_use_debanding].
27502750
</member>

doc/classes/RenderingServer.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4232,7 +4232,7 @@
42324232
<param index="0" name="viewport" type="RID" />
42334233
<param index="1" name="enable" type="bool" />
42344234
<description>
4235-
If [code]true[/code], enables debanding on the specified viewport. Equivalent to [member ProjectSettings.rendering/anti_aliasing/quality/use_debanding] or [member Viewport.use_debanding].
4235+
Equivalent to [member Viewport.use_debanding]. See also [member ProjectSettings.rendering/anti_aliasing/quality/use_debanding].
42364236
</description>
42374237
</method>
42384238
<method name="viewport_set_use_hdr_2d">

doc/classes/Viewport.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@
444444
If [code]true[/code], the viewport should render its background as transparent.
445445
</member>
446446
<member name="use_debanding" type="bool" setter="set_use_debanding" getter="is_using_debanding" default="false">
447-
If [code]true[/code], uses a fast post-processing filter to make banding significantly less visible in 3D. 2D rendering is [i]not[/i] affected by debanding unless the [member Environment.background_mode] is [constant Environment.BG_CANVAS].
447+
If [code]true[/code], uses a fast post-processing filter to make banding significantly less visible. If [member use_hdr_2d] is [code]false[/code], 2D rendering is [i]not[/i] affected by debanding unless the [member Environment.background_mode] is [constant Environment.BG_CANVAS]. If [member use_hdr_2d] is [code]true[/code], debanding will only be applied if this is the root [Viewport] and will affect all 2D and 3D rendering, including canvas items.
448448
In some cases, debanding may introduce a slightly noticeable dithering pattern. It's recommended to enable debanding only when actually needed since the dithering pattern will make lossless-compressed screenshots larger.
449449
See also [member ProjectSettings.rendering/anti_aliasing/quality/use_debanding] and [method RenderingServer.viewport_set_use_debanding].
450450
</member>

drivers/gles3/storage/texture_storage.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,8 @@ class TextureStorage : public RendererTextureStorage {
647647
virtual void render_target_do_msaa_resolve(RID p_render_target) override {}
648648
virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) override;
649649
virtual bool render_target_is_using_hdr(RID p_render_target) const override;
650+
virtual void render_target_set_use_debanding(RID p_render_target, bool p_use_debanding) override {}
651+
virtual bool render_target_is_using_debanding(RID p_render_target) const override { return false; }
650652

651653
// new
652654
void render_target_set_as_unused(RID p_render_target) override {

servers/rendering/dummy/storage/texture_storage.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ class TextureStorage : public RendererTextureStorage {
180180
virtual void render_target_do_msaa_resolve(RID p_render_target) override {}
181181
virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) override {}
182182
virtual bool render_target_is_using_hdr(RID p_render_target) const override { return false; }
183+
virtual void render_target_set_use_debanding(RID p_render_target, bool p_use_debanding) override {}
184+
virtual bool render_target_is_using_debanding(RID p_render_target) const override { return false; }
183185

184186
virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override {}
185187
virtual bool render_target_is_clear_requested(RID p_render_target) override { return false; }

servers/rendering/renderer_rd/effects/tone_mapper.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton
123123
tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0;
124124

125125
tonemap.push_constant.flags |= p_settings.use_fxaa ? TONEMAP_FLAG_USE_FXAA : 0;
126-
tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0;
126+
// When convert_to_srgb is false: postpone debanding until convert_to_srgb is true (usually during blit).
127+
tonemap.push_constant.flags |= (p_settings.use_debanding && p_settings.convert_to_srgb) ? TONEMAP_FLAG_USE_DEBANDING : 0;
127128
tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x;
128129
tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y;
129130

@@ -207,8 +208,8 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col
207208
tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale;
208209

209210
tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0;
210-
211-
tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0;
211+
// When convert_to_srgb is false: postpone debanding until convert_to_srgb is true (usually during blit).
212+
tonemap.push_constant.flags |= (p_settings.use_debanding && p_settings.convert_to_srgb) ? TONEMAP_FLAG_USE_DEBANDING : 0;
212213
tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
213214

214215
tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0;

servers/rendering/renderer_rd/renderer_compositor_rd.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID
9696
blit.push_constant.upscale = p_render_targets[i].lens_distortion.upscale;
9797
blit.push_constant.aspect_ratio = p_render_targets[i].lens_distortion.aspect_ratio;
9898
blit.push_constant.convert_to_srgb = texture_storage->render_target_is_using_hdr(p_render_targets[i].render_target);
99+
// If convert_to_srgb is false, debanding was applied earlier (usually in tonemapping).
100+
blit.push_constant.use_debanding = uint32_t(blit.push_constant.convert_to_srgb && texture_storage->render_target_is_using_debanding(p_render_targets[i].render_target));
99101

100102
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant));
101103
RD::get_singleton()->draw_list_draw(draw_list, true);
@@ -257,6 +259,7 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
257259
blit.push_constant.upscale = 1.0;
258260
blit.push_constant.aspect_ratio = 1.0;
259261
blit.push_constant.convert_to_srgb = false;
262+
blit.push_constant.use_debanding = false;
260263

261264
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant));
262265
RD::get_singleton()->draw_list_draw(draw_list, true);

servers/rendering/renderer_rd/renderer_compositor_rd.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ class RendererCompositorRD : public RendererCompositor {
7373

7474
float rotation_sin;
7575
float rotation_cos;
76-
float pad[2];
7776

7877
float eye_center[2];
7978
float k1;
@@ -83,6 +82,8 @@ class RendererCompositorRD : public RendererCompositor {
8382
float aspect_ratio;
8483
uint32_t layer;
8584
uint32_t convert_to_srgb;
85+
uint32_t use_debanding;
86+
float pad;
8687
};
8788

8889
struct Blit {

servers/rendering/renderer_rd/renderer_scene_render_rd.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
665665
tonemap.use_color_correction = false;
666666
tonemap.use_1d_color_correction = false;
667667
tonemap.color_correction_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
668+
tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(render_target);
668669

669670
if (can_use_effects && p_render_data->environment.is_valid()) {
670671
tonemap.use_bcs = environment_get_adjustments_enabled(p_render_data->environment);
@@ -674,15 +675,13 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
674675
if (environment_get_adjustments_enabled(p_render_data->environment) && environment_get_color_correction(p_render_data->environment).is_valid()) {
675676
tonemap.use_color_correction = true;
676677
tonemap.use_1d_color_correction = environment_get_use_1d_color_correction(p_render_data->environment);
677-
tonemap.color_correction_texture = texture_storage->texture_get_rd_texture(environment_get_color_correction(p_render_data->environment));
678+
tonemap.color_correction_texture = texture_storage->texture_get_rd_texture(environment_get_color_correction(p_render_data->environment), !tonemap.convert_to_srgb);
678679
}
679680
}
680681

681682
tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier();
682683
tonemap.view_count = rb->get_view_count();
683684

684-
tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(render_target);
685-
686685
RID dest_fb;
687686
if (spatial_upscaler != nullptr || use_smaa) {
688687
// If we use a spatial upscaler to upscale or SMAA to antialias we need to write our result into an intermediate buffer.
@@ -824,6 +823,7 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr
824823
tonemap.use_color_correction = false;
825824
tonemap.use_1d_color_correction = false;
826825
tonemap.color_correction_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
826+
tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(rb->get_render_target());
827827

828828
if (can_use_effects && p_render_data->environment.is_valid()) {
829829
tonemap.use_bcs = environment_get_adjustments_enabled(p_render_data->environment);
@@ -833,7 +833,7 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr
833833
if (environment_get_adjustments_enabled(p_render_data->environment) && environment_get_color_correction(p_render_data->environment).is_valid()) {
834834
tonemap.use_color_correction = true;
835835
tonemap.use_1d_color_correction = environment_get_use_1d_color_correction(p_render_data->environment);
836-
tonemap.color_correction_texture = texture_storage->texture_get_rd_texture(environment_get_color_correction(p_render_data->environment));
836+
tonemap.color_correction_texture = texture_storage->texture_get_rd_texture(environment_get_color_correction(p_render_data->environment), !tonemap.convert_to_srgb);
837837
}
838838
}
839839

@@ -843,8 +843,6 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr
843843
tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier();
844844
tonemap.view_count = rb->get_view_count();
845845

846-
tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(rb->get_render_target());
847-
848846
tone_mapper->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap);
849847

850848
RD::get_singleton()->draw_command_end_label();

servers/rendering/renderer_rd/shaders/blit.glsl

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ layout(push_constant, std140) uniform Pos {
1010

1111
float rotation_sin;
1212
float rotation_cos;
13-
vec2 pad;
1413

1514
vec2 eye_center;
1615
float k1;
@@ -20,6 +19,8 @@ layout(push_constant, std140) uniform Pos {
2019
float aspect_ratio;
2120
uint layer;
2221
bool convert_to_srgb;
22+
bool use_debanding;
23+
float pad;
2324
}
2425
data;
2526

@@ -50,7 +51,6 @@ layout(push_constant, std140) uniform Pos {
5051

5152
float rotation_sin;
5253
float rotation_cos;
53-
vec2 pad;
5454

5555
vec2 eye_center;
5656
float k1;
@@ -60,6 +60,8 @@ layout(push_constant, std140) uniform Pos {
6060
float aspect_ratio;
6161
uint layer;
6262
bool convert_to_srgb;
63+
bool use_debanding;
64+
float pad;
6365
}
6466
data;
6567

@@ -74,12 +76,27 @@ layout(binding = 0) uniform sampler2D src_rt;
7476
#endif
7577

7678
vec3 linear_to_srgb(vec3 color) {
77-
// If going to srgb, clamp from 0 to 1.
78-
color = clamp(color, vec3(0.0), vec3(1.0));
7979
const vec3 a = vec3(0.055f);
8080
return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
8181
}
8282

83+
// From https://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
84+
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
85+
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).
86+
// This dithering must be applied after encoding changes (linear/nonlinear) have been applied
87+
// as the final step before quantization from floating point to integer values.
88+
vec3 screen_space_dither(vec2 frag_coord) {
89+
// Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR.
90+
// Removed the time component to avoid passing time into this shader.
91+
vec3 dither = vec3(dot(vec2(171.0, 231.0), frag_coord));
92+
dither.rgb = fract(dither.rgb / vec3(103.0, 71.0, 97.0));
93+
94+
// Subtract 0.5 to avoid slightly brightening the whole viewport.
95+
// Use a dither strength of 100% rather than the 37.5% suggested by the original source.
96+
// Divide by 255 to align to 8-bit quantization.
97+
return (dither.rgb - 0.5) / 255.0;
98+
}
99+
83100
void main() {
84101
#ifdef APPLY_LENS_DISTORTION
85102
vec2 coords = uv * 2.0 - 1.0;
@@ -118,5 +135,10 @@ void main() {
118135

119136
if (data.convert_to_srgb) {
120137
color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion.
138+
// When convert_to_srgb is true, debanding was skipped in tonemap.glsl.
139+
if (data.use_debanding) {
140+
color.rgb += screen_space_dither(gl_FragCoord.xy);
141+
}
142+
color.rgb = clamp(color.rgb, vec3(0.0), vec3(1.0));
121143
}
122144
}

0 commit comments

Comments
 (0)