From 57eb762bae0a24a4fb33e825e57f1e100bd9d354 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Thu, 3 Aug 2023 14:10:01 +0200 Subject: [PATCH] Add option to enable HDR rendering in 2D This is needed to allow 2D to fully make use of 3D effects (e.g. glow), and can be used to substantially improve quality of 2D rendering at the cost of performance Additionally, the 2D rendering pipeline is done in linear space (we skip linear_to_srgb conversion in 3D tonemapping) so the entire Viewport can be kept linear. This is necessary for proper HDR screen support in the future. --- doc/classes/ProjectSettings.xml | 3 + doc/classes/RenderingServer.xml | 9 ++ doc/classes/Viewport.xml | 4 + .../gles3/shaders/canvas_uniforms_inc.glsl | 2 +- drivers/gles3/storage/texture_storage.h | 2 + editor/editor_node.cpp | 3 + editor/plugins/node_3d_editor_plugin.cpp | 3 + scene/main/scene_tree.cpp | 3 + scene/main/viewport.cpp | 15 +++ scene/main/viewport.h | 4 + .../rendering/dummy/storage/texture_storage.h | 2 + .../renderer_rd/effects/tone_mapper.cpp | 26 +++--- .../renderer_rd/effects/tone_mapper.h | 25 +++-- .../rendering/renderer_rd/environment/fog.cpp | 2 +- .../rendering/renderer_rd/environment/sky.cpp | 2 +- .../render_forward_clustered.cpp | 3 +- .../scene_shader_forward_clustered.cpp | 2 +- .../forward_mobile/render_forward_mobile.cpp | 3 +- .../scene_shader_forward_mobile.cpp | 2 +- .../renderer_rd/renderer_canvas_render_rd.cpp | 73 ++++++++++----- .../renderer_rd/renderer_canvas_render_rd.h | 3 + .../renderer_rd/renderer_compositor_rd.cpp | 4 +- .../renderer_rd/renderer_compositor_rd.h | 2 +- .../renderer_rd/renderer_scene_render_rd.cpp | 4 + .../rendering/renderer_rd/shaders/blit.glsl | 13 ++- .../rendering/renderer_rd/shaders/canvas.glsl | 15 ++- .../shaders/canvas_uniforms_inc.glsl | 2 +- .../renderer_rd/shaders/effects/copy.glsl | 2 +- .../renderer_rd/shaders/effects/tonemap.glsl | 48 ++++++---- .../storage_rd/material_storage.cpp | 8 +- .../renderer_rd/storage_rd/material_storage.h | 4 +- .../storage_rd/particles_storage.cpp | 2 +- .../storage_rd/texture_storage.cpp | 93 +++++++++++++++---- .../renderer_rd/storage_rd/texture_storage.h | 7 +- servers/rendering/renderer_viewport.cpp | 11 +++ servers/rendering/renderer_viewport.h | 3 + servers/rendering/rendering_server_default.h | 1 + servers/rendering/storage/texture_storage.h | 2 + servers/rendering_server.cpp | 1 + servers/rendering_server.h | 1 + 40 files changed, 309 insertions(+), 105 deletions(-) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index d240b6ef486..bf1fd8bc361 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2650,6 +2650,9 @@ The default compression factor for lossless WebP. Decompression speed is mostly unaffected by the compression factor. Supported values are 0 to 100. + + If [code]true[/code], enables [member Viewport.use_hdr_2d] on the root viewport. This allows 2D rendering to take advantage of effects requiring high dynamic range (e.g. 2D glow). + If [code]true[/code], enables [member Viewport.transparent_bg] on the root viewport. This allows per-pixel transparency to be effective after also enabling [member display/window/size/transparent] and [member display/window/per_pixel_transparency/allowed]. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 02c1286392c..e360bc2a5fa 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3756,6 +3756,15 @@ If [code]true[/code], enables debanding on the specified viewport. Equivalent to [member ProjectSettings.rendering/anti_aliasing/quality/use_debanding]. + + + + + + If [code]true[/code], 2D rendering will use a high dynamic range (HDR) format framebuffer matching the bit depth of the 3D framebuffer. When using the Forward+ renderer this will be a [code]RGBA16[/code] framebuffer, while when using the Mobile renderer it will be a [code]RGB10_A2[/code] framebuffer. Additionally, 2D rendering will take place in linear color space and will be converted to sRGB space immediately before blitting to the screen (if the Viewport is attached to the screen). Practically speaking, this means that the end result of the Viewport will not be clamped into the [code]0-1[/code] range and can be used in 3D rendering without color space adjustments. This allows 2D rendering to take advantage of effects requiring high dynamic range (e.g. 2D glow) as well as substantially improves the appearance of effects requiring highly detailed gradients. This setting has the same effect as [member Viewport.use_hdr_2d]. + [b]Note:[/b] This setting will have no effect when using the GL Compatibility renderer as the GL Compatibility renderer always renders in low dynamic range for performance reasons. + + diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 9a5e7ed6f64..761506831f4 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -348,6 +348,10 @@ 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]. See also [member ProjectSettings.rendering/anti_aliasing/quality/use_debanding]. 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. + + If [code]true[/code], 2D rendering will use an high dynamic range (HDR) format framebuffer matching the bit depth of the 3D framebuffer. When using the Forward+ renderer this will be a [code]RGBA16[/code] framebuffer, while when using the Mobile renderer it will be a [code]RGB10_A2[/code] framebuffer. Additionally, 2D rendering will take place in linear color space and will be converted to sRGB space immediately before blitting to the screen (if the Viewport is attached to the screen). Practically speaking, this means that the end result of the Viewport will not be clamped into the [code]0-1[/code] range and can be used in 3D rendering without color space adjustments. This allows 2D rendering to take advantage of effects requiring high dynamic range (e.g. 2D glow) as well as substantially improves the appearance of effects requiring highly detailed gradients. + [b]Note:[/b] This setting will have no effect when using the GL Compatibility renderer as the GL Compatibility renderer always renders in low dynamic range for performance reasons. + If [code]true[/code], [OccluderInstance3D] nodes will be usable for occlusion culling in 3D for this viewport. For the root viewport, [member ProjectSettings.rendering/occlusion_culling/use_occlusion_culling] must be set to [code]true[/code] instead. [b]Note:[/b] Enabling occlusion culling has a cost on the CPU. Only enable occlusion culling if you actually plan to use it, and think whether your scene can actually benefit from occlusion culling. Large, open scenes with few or no objects blocking the view will generally not benefit much from occlusion culling. Large open scenes generally benefit more from mesh LOD and visibility ranges ([member GeometryInstance3D.visibility_range_begin] and [member GeometryInstance3D.visibility_range_end]) compared to occlusion culling. diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl index d53c0fcb265..21fd4d3d9dd 100644 --- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl +++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl @@ -12,7 +12,7 @@ #define FLAGS_CLIP_RECT_UV uint(1 << 9) #define FLAGS_TRANSPOSE_RECT uint(1 << 10) -#define FLAGS_USING_LIGHT_MASK uint(1 << 11) +// (1 << 11) is for FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR in RD backends, unused here. #define FLAGS_NINEPACH_DRAW_CENTER uint(1 << 12) #define FLAGS_USING_PARTICLES uint(1 << 13) diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index bad2b31a315..c25dbef288d 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -629,6 +629,8 @@ public: void render_target_clear_used(RID p_render_target); virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override; virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override; + virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) override {} + virtual bool render_target_is_using_hdr(RID p_render_target) const override { return false; } // new void render_target_set_as_unused(RID p_render_target) override { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index e0a014ac1af..204eaaf12f7 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -496,6 +496,9 @@ void EditorNode::_update_from_settings() { Viewport::MSAA msaa = Viewport::MSAA(int(GLOBAL_GET("rendering/anti_aliasing/quality/msaa_2d"))); scene_root->set_msaa_2d(msaa); + bool use_hdr_2d = GLOBAL_GET("rendering/viewport/hdr_2d"); + scene_root->set_use_hdr_2d(use_hdr_2d); + float mesh_lod_threshold = GLOBAL_GET("rendering/mesh_lod/lod_change/threshold_pixels"); scene_root->set_mesh_lod_threshold(mesh_lod_threshold); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 68d3661d10a..151f11d9cbc 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -2658,6 +2658,9 @@ void Node3DEditorViewport::_project_settings_changed() { const bool transparent_background = GLOBAL_GET("rendering/viewport/transparent_background"); viewport->set_transparent_background(transparent_background); + const bool use_hdr_2d = GLOBAL_GET("rendering/viewport/hdr_2d"); + viewport->set_use_hdr_2d(use_hdr_2d); + const bool use_debanding = GLOBAL_GET("rendering/anti_aliasing/quality/use_debanding"); viewport->set_use_debanding(use_debanding); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index db9c1efa68e..d8c5e9c0078 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1733,6 +1733,9 @@ SceneTree::SceneTree() { const bool transparent_background = GLOBAL_DEF("rendering/viewport/transparent_background", false); root->set_transparent_background(transparent_background); + const bool use_hdr_2d = GLOBAL_DEF_RST_BASIC("rendering/viewport/hdr_2d", false); + root->set_use_hdr_2d(use_hdr_2d); + const int ssaa_mode = GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), 0); root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode)); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index c0e54e4e2a3..405b2216363 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1177,6 +1177,17 @@ bool Viewport::has_transparent_background() const { return transparent_bg; } +void Viewport::set_use_hdr_2d(bool p_enable) { + ERR_MAIN_THREAD_GUARD; + use_hdr_2d = p_enable; + RS::get_singleton()->viewport_set_use_hdr_2d(viewport, p_enable); +} + +bool Viewport::is_using_hdr_2d() const { + ERR_READ_THREAD_GUARD_V(false); + return use_hdr_2d; +} + void Viewport::set_world_2d(const Ref &p_world_2d) { ERR_MAIN_THREAD_GUARD; if (world_2d == p_world_2d) { @@ -4271,6 +4282,8 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("get_visible_rect"), &Viewport::get_visible_rect); ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background); ClassDB::bind_method(D_METHOD("has_transparent_background"), &Viewport::has_transparent_background); + ClassDB::bind_method(D_METHOD("set_use_hdr_2d", "enable"), &Viewport::set_use_hdr_2d); + ClassDB::bind_method(D_METHOD("is_using_hdr_2d"), &Viewport::is_using_hdr_2d); ClassDB::bind_method(D_METHOD("set_msaa_2d", "msaa"), &Viewport::set_msaa_2d); ClassDB::bind_method(D_METHOD("get_msaa_2d"), &Viewport::get_msaa_2d); @@ -4435,6 +4448,8 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mesh_lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_mesh_lod_threshold", "get_mesh_lod_threshold"); ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Lighting,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr_2d"), "set_use_hdr_2d", "is_using_hdr_2d"); + #ifndef _3D_DISABLED ADD_GROUP("Scaling 3D", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast)"), "set_scaling_3d_mode", "get_scaling_3d_mode"); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 7cfad421194..3ff4003b3ea 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -243,6 +243,7 @@ private: Rect2 last_vp_rect; bool transparent_bg = false; + bool use_hdr_2d = false; bool gen_mipmaps = false; bool snap_controls_to_pixels = true; @@ -526,6 +527,9 @@ public: void set_transparent_background(bool p_enable); bool has_transparent_background() const; + void set_use_hdr_2d(bool p_enable); + bool is_using_hdr_2d() const; + Ref get_texture() const; void set_positional_shadow_atlas_size(int p_size); diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index 71a1801de96..d9bde5903c6 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -177,6 +177,8 @@ public: virtual void render_target_set_as_unused(RID p_render_target) override {} virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override {} virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override { return RS::VIEWPORT_MSAA_DISABLED; } + virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) override {} + virtual bool render_target_is_using_hdr(RID p_render_target) const override { return false; } virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override {} virtual bool render_target_is_clear_requested(RID p_render_target) override { return false; } diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp index 821960bb3bb..9c8e8dd2313 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp +++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp @@ -89,12 +89,12 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); - tonemap.push_constant.use_bcs = p_settings.use_bcs; + tonemap.push_constant.flags |= p_settings.use_bcs ? TONEMAP_FLAG_USE_BCS : 0; tonemap.push_constant.bcs[0] = p_settings.brightness; tonemap.push_constant.bcs[1] = p_settings.contrast; tonemap.push_constant.bcs[2] = p_settings.saturation; - tonemap.push_constant.use_glow = p_settings.use_glow; + tonemap.push_constant.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0; tonemap.push_constant.glow_intensity = p_settings.glow_intensity; tonemap.push_constant.glow_map_strength = p_settings.glow_map_strength; tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something @@ -114,19 +114,21 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton } tonemap.push_constant.tonemapper = p_settings.tonemap_mode; - tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; + tonemap.push_constant.flags |= p_settings.use_auto_exposure ? TONEMAP_FLAG_USE_AUTO_EXPOSURE : 0; tonemap.push_constant.exposure = p_settings.exposure; tonemap.push_constant.white = p_settings.white; tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale; tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; - tonemap.push_constant.use_color_correction = p_settings.use_color_correction; + tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0; - tonemap.push_constant.use_fxaa = p_settings.use_fxaa; - tonemap.push_constant.use_debanding = p_settings.use_debanding; + tonemap.push_constant.flags |= p_settings.use_fxaa ? TONEMAP_FLAG_USE_FXAA : 0; + tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0; tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x; tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; + tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0; + if (p_settings.view_count > 1) { // Use MULTIVIEW versions mode += 6; @@ -185,13 +187,13 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); - tonemap.push_constant.use_bcs = p_settings.use_bcs; + tonemap.push_constant.flags |= p_settings.use_bcs ? TONEMAP_FLAG_USE_BCS : 0; tonemap.push_constant.bcs[0] = p_settings.brightness; tonemap.push_constant.bcs[1] = p_settings.contrast; tonemap.push_constant.bcs[2] = p_settings.saturation; ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses."); - tonemap.push_constant.use_glow = p_settings.use_glow; + tonemap.push_constant.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0; int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS; if (p_settings.view_count > 1) { @@ -200,16 +202,18 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col } tonemap.push_constant.tonemapper = p_settings.tonemap_mode; - tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; + tonemap.push_constant.flags |= p_settings.use_auto_exposure ? TONEMAP_FLAG_USE_AUTO_EXPOSURE : 0; tonemap.push_constant.exposure = p_settings.exposure; tonemap.push_constant.white = p_settings.white; tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale; - tonemap.push_constant.use_color_correction = p_settings.use_color_correction; + tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0; - tonemap.push_constant.use_debanding = p_settings.use_debanding; + tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0; tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; + tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0; + RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.h b/servers/rendering/renderer_rd/effects/tone_mapper.h index afd2f8e4013..a1a99f931fc 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.h +++ b/servers/rendering/renderer_rd/effects/tone_mapper.h @@ -59,14 +59,23 @@ private: TONEMAP_MODE_MAX }; + enum { + TONEMAP_FLAG_USE_BCS = (1 << 0), + TONEMAP_FLAG_USE_GLOW = (1 << 1), + TONEMAP_FLAG_USE_AUTO_EXPOSURE = (1 << 2), + TONEMAP_FLAG_USE_COLOR_CORRECTION = (1 << 3), + TONEMAP_FLAG_USE_FXAA = (1 << 4), + TONEMAP_FLAG_USE_DEBANDING = (1 << 5), + TONEMAP_FLAG_CONVERT_TO_SRGB = (1 << 6), + }; + struct TonemapPushConstant { float bcs[3]; // 12 - 12 - uint32_t use_bcs; // 4 - 16 + uint32_t flags; // 4 - 16 - uint32_t use_glow; // 4 - 20 - uint32_t use_auto_exposure; // 4 - 24 - uint32_t use_color_correction; // 4 - 28 - uint32_t tonemapper; // 4 - 32 + float pixel_size[2]; // 8 - 24 + uint32_t tonemapper; // 4 - 28 + uint32_t pad; // 4 - 32 uint32_t glow_texture_size[2]; // 8 - 40 float glow_intensity; // 4 - 44 @@ -79,10 +88,6 @@ private: float white; // 4 - 88 float auto_exposure_scale; // 4 - 92 float luminance_multiplier; // 4 - 96 - - float pixel_size[2]; // 8 - 104 - uint32_t use_fxaa; // 4 - 108 - uint32_t use_debanding; // 4 - 112 }; /* tonemap actually writes to a framebuffer, which is @@ -141,6 +146,8 @@ public: bool use_debanding = false; Vector2i texture_size; uint32_t view_count = 1; + + bool convert_to_srgb = false; }; void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 98d826b1f99..8402cc74446 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -143,7 +143,7 @@ Vector3 Fog::fog_volume_get_size(RID p_fog_volume) const { bool Fog::FogMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { uniform_set_updated = true; - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, Fog::get_singleton()->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL, true); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, Fog::get_singleton()->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL, true, true); } Fog::FogMaterialData::~FogMaterialData() { diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index ebf3c5f6199..431bf9cb846 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -185,7 +185,7 @@ bool SkyRD::SkyMaterialData::update_parameters(const HashMapuniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL, true); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL, true, true); } SkyRD::SkyMaterialData::~SkyMaterialData() { diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 7bca1dc3be9..9b05bf0c647 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1769,7 +1769,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co case RS::ENV_BG_CANVAS: { if (!is_reflection_probe) { RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target()); - copy_effects->copy_to_fb_rect(texture, color_only_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true); + bool convert_to_linear = !RendererRD::TextureStorage::get_singleton()->render_target_is_using_hdr(rb->get_render_target()); + copy_effects->copy_to_fb_rect(texture, color_only_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, convert_to_linear); } keep_color = true; } break; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 298a6c07528..12f8f6a366c 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -436,7 +436,7 @@ void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) { bool SceneShaderForwardClustered::MaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, RD::BARRIER_MASK_RASTER); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true, RD::BARRIER_MASK_RASTER); } SceneShaderForwardClustered::MaterialData::~MaterialData() { diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 2053c3a9a62..1ea1997f3e2 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -803,7 +803,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (rb_data.is_valid()) { RID dest_framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS); RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target()); - copy_effects->copy_to_fb_rect(texture, dest_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true); + bool convert_to_linear = !RendererRD::TextureStorage::get_singleton()->render_target_is_using_hdr(rb->get_render_target()); + copy_effects->copy_to_fb_rect(texture, dest_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, convert_to_linear); } keep_color = true; } break; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index e4498ac533f..32d2289f75c 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -388,7 +388,7 @@ void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) { bool SceneShaderForwardMobile::MaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, RD::BARRIER_MASK_RASTER); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true, RD::BARRIER_MASK_RASTER); } SceneShaderForwardMobile::MaterialData::~MaterialData() { diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index eb33f296d04..773ea9098ac 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -363,7 +363,7 @@ void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RI bool use_normal; bool use_specular; - bool success = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_uniform_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, uniform_set, size, specular_shininess, use_normal, use_specular); + bool success = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_uniform_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, bool(push_constant.flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR), uniform_set, size, specular_shininess, use_normal, use_specular); //something odd happened if (!success) { _bind_canvas_texture(p_draw_list, default_canvas_texture, p_base_filter, p_base_repeat, r_last_texture, push_constant, r_texpixel_size); @@ -421,6 +421,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend _update_transform_2d_to_mat2x3(base_transform, push_constant.world); Color base_color = p_item->final_modulate; + bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_render_target); for (int i = 0; i < 4; i++) { push_constant.modulation[i] = 0; @@ -441,6 +442,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend push_constant.lights[3] = 0; uint32_t base_flags = 0; + base_flags |= use_linear_colors ? FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR : 0; uint16_t light_count = 0; PipelineLightMode light_mode; @@ -566,10 +568,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend push_constant.flags |= FLAGS_USE_LCD; } - push_constant.modulation[0] = rect->modulate.r * base_color.r; - push_constant.modulation[1] = rect->modulate.g * base_color.g; - push_constant.modulation[2] = rect->modulate.b * base_color.b; - push_constant.modulation[3] = rect->modulate.a * base_color.a; + Color modulated = rect->modulate * base_color; + if (use_linear_colors) { + modulated = modulated.srgb_to_linear(); + } + + push_constant.modulation[0] = modulated.r; + push_constant.modulation[1] = modulated.g; + push_constant.modulation[2] = modulated.b; + push_constant.modulation[3] = modulated.a; push_constant.src_rect[0] = src_rect.position.x; push_constant.src_rect[1] = src_rect.position.y; @@ -618,10 +625,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend } } - push_constant.modulation[0] = np->color.r * base_color.r; - push_constant.modulation[1] = np->color.g * base_color.g; - push_constant.modulation[2] = np->color.b * base_color.b; - push_constant.modulation[3] = np->color.a * base_color.a; + Color modulated = np->color * base_color; + if (use_linear_colors) { + modulated = modulated.srgb_to_linear(); + } + + push_constant.modulation[0] = modulated.r; + push_constant.modulation[1] = modulated.g; + push_constant.modulation[2] = modulated.b; + push_constant.modulation[3] = modulated.a; push_constant.src_rect[0] = src_rect.position.x; push_constant.src_rect[1] = src_rect.position.y; @@ -676,10 +688,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend _bind_canvas_texture(p_draw_list, polygon->texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size); - push_constant.modulation[0] = base_color.r; - push_constant.modulation[1] = base_color.g; - push_constant.modulation[2] = base_color.b; - push_constant.modulation[3] = base_color.a; + Color color = base_color; + if (use_linear_colors) { + color = color.srgb_to_linear(); + } + + push_constant.modulation[0] = color.r; + push_constant.modulation[1] = color.g; + push_constant.modulation[2] = color.b; + push_constant.modulation[3] = color.a; for (int j = 0; j < 4; j++) { push_constant.src_rect[j] = 0; @@ -718,6 +735,9 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend push_constant.uvs[j * 2 + 0] = primitive->uvs[j].x; push_constant.uvs[j * 2 + 1] = primitive->uvs[j].y; Color col = primitive->colors[j] * base_color; + if (use_linear_colors) { + col = col.srgb_to_linear(); + } push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r); push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b); } @@ -732,6 +752,9 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend push_constant.uvs[j * 2 + 0] = primitive->uvs[j + 1].x; push_constant.uvs[j * 2 + 1] = primitive->uvs[j + 1].y; Color col = primitive->colors[j + 1] * base_color; + if (use_linear_colors) { + col = col.srgb_to_linear(); + } push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r); push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b); } @@ -849,10 +872,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh); static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP }; - push_constant.modulation[0] = base_color.r * modulate.r; - push_constant.modulation[1] = base_color.g * modulate.g; - push_constant.modulation[2] = base_color.b * modulate.b; - push_constant.modulation[3] = base_color.a * modulate.a; + Color modulated = modulate * base_color; + if (use_linear_colors) { + modulated = modulated.srgb_to_linear(); + } + + push_constant.modulation[0] = modulated.r; + push_constant.modulation[1] = modulated.g; + push_constant.modulation[2] = modulated.b; + push_constant.modulation[3] = modulated.a; for (int j = 0; j < 4; j++) { push_constant.src_rect[j] = 0; @@ -1113,8 +1141,9 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) { pipeline_variants = &material_data->shader_data->pipeline_variants; // Update uniform set. - if (material_data->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_data->uniform_set)) { // Material may not have a uniform set. - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, MATERIAL_UNIFORM_SET); + RID uniform_set = texture_storage->render_target_is_using_hdr(p_to_render_target) ? material_data->uniform_set : material_data->uniform_set_srgb; + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { // Material may not have a uniform set. + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set, MATERIAL_UNIFORM_SET); material_data->set_as_used(); } } else { @@ -2235,12 +2264,14 @@ RendererRD::MaterialStorage::ShaderData *RendererCanvasRenderRD::_create_shader_ bool RendererCanvasRenderRD::CanvasMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { RendererCanvasRenderRD *canvas_singleton = static_cast(RendererCanvasRender::singleton); - - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false); + bool uniform_set_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, true, false, RD::BARRIER_MASK_ALL_BARRIERS); + bool uniform_set_srgb_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set_srgb, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false, false, RD::BARRIER_MASK_ALL_BARRIERS); + return uniform_set_changed || uniform_set_srgb_changed; } RendererCanvasRenderRD::CanvasMaterialData::~CanvasMaterialData() { free_parameters_uniform_set(uniform_set); + free_parameters_uniform_set(uniform_set_srgb); } RendererRD::MaterialStorage::MaterialData *RendererCanvasRenderRD::_create_material_func(CanvasShaderData *p_shader) { diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 1116bed6e44..af8736a445a 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -75,6 +75,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender { FLAGS_CLIP_RECT_UV = (1 << 9), FLAGS_TRANSPOSE_RECT = (1 << 10), + FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR = (1 << 11), + FLAGS_NINEPACH_DRAW_CENTER = (1 << 12), FLAGS_USING_PARTICLES = (1 << 13), @@ -195,6 +197,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { struct CanvasMaterialData : public RendererRD::MaterialStorage::MaterialData { CanvasShaderData *shader_data = nullptr; RID uniform_set; + RID uniform_set_srgb; virtual void set_render_priority(int p_priority) {} virtual void set_next_pass(RID p_pass) {} diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 870da3c321c..4ccd2aa3228 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -81,6 +81,7 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID blit.push_constant.k2 = p_render_targets[i].lens_distortion.k2; blit.push_constant.upscale = p_render_targets[i].lens_distortion.upscale; blit.push_constant.aspect_ratio = p_render_targets[i].lens_distortion.aspect_ratio; + blit.push_constant.convert_to_srgb = texture_storage->render_target_is_using_hdr(p_render_targets[i].render_target); RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant)); RD::get_singleton()->draw_list_draw(draw_list, true); @@ -171,7 +172,7 @@ void RendererCompositorRD::set_boot_image(const Ref &p_image, const Color RID texture = texture_storage->texture_allocate(); texture_storage->texture_2d_initialize(texture, p_image); - RID rd_texture = texture_storage->texture_get_rd_texture(texture); + RID rd_texture = texture_storage->texture_get_rd_texture(texture, false); RD::SamplerState sampler_state; sampler_state.min_filter = p_use_filter ? RD::SAMPLER_FILTER_LINEAR : RD::SAMPLER_FILTER_NEAREST; @@ -237,6 +238,7 @@ void RendererCompositorRD::set_boot_image(const Ref &p_image, const Color blit.push_constant.k2 = 0; blit.push_constant.upscale = 1.0; blit.push_constant.aspect_ratio = 1.0; + blit.push_constant.convert_to_srgb = false; RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant)); RD::get_singleton()->draw_list_draw(draw_list, true); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 14fb4e6340f..705fb9e8e54 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -80,7 +80,7 @@ protected: float upscale; float aspect_ratio; uint32_t layer; - uint32_t pad1; + uint32_t convert_to_srgb; }; struct Blit { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 646bdc54368..07947f29e52 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -552,6 +552,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier(); tonemap.view_count = rb->get_view_count(); + tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(render_target); + RID dest_fb; if (fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR) { // If we use FSR to upscale we need to write our result into an intermediate buffer. @@ -647,6 +649,8 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier(); tonemap.view_count = rb->get_view_count(); + tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(rb->get_render_target()); + tone_mapper->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap); RD::get_singleton()->draw_command_end_label(); diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl index 14f190a49f5..d451647bec6 100644 --- a/servers/rendering/renderer_rd/shaders/blit.glsl +++ b/servers/rendering/renderer_rd/shaders/blit.glsl @@ -45,7 +45,7 @@ layout(push_constant, std140) uniform Pos { float upscale; float aspect_ratio; uint layer; - uint pad1; + bool convert_to_srgb; } data; @@ -59,6 +59,13 @@ layout(binding = 0) uniform sampler2DArray src_rt; layout(binding = 0) uniform sampler2D src_rt; #endif +vec3 linear_to_srgb(vec3 color) { + // If going to srgb, clamp from 0 to 1. + color = clamp(color, vec3(0.0), vec3(1.0)); + const vec3 a = vec3(0.055f); + 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))); +} + void main() { #ifdef APPLY_LENS_DISTORTION vec2 coords = uv * 2.0 - 1.0; @@ -94,4 +101,8 @@ void main() { #else color = texture(src_rt, uv); #endif + + if (data.convert_to_srgb) { + color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion. + } } diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 6270450c15e..31c5aadc889 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -36,6 +36,12 @@ layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ #GLOBALS +#ifdef USE_ATTRIBUTES +vec3 srgb_to_linear(vec3 color) { + return mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), color.rgb * (1.0 / 12.92), lessThan(color.rgb, vec3(0.04045))); +} +#endif + void main() { vec4 instance_custom = vec4(0.0); #ifdef USE_PRIMITIVE @@ -65,7 +71,11 @@ void main() { #elif defined(USE_ATTRIBUTES) vec2 vertex = vertex_attrib; - vec4 color = color_attrib * draw_data.modulation; + vec4 color = color_attrib; + if (bool(draw_data.flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR)) { + color.rgb = srgb_to_linear(color.rgb); + } + color *= draw_data.modulation; vec2 uv = uv_attrib; uvec4 bones = bone_attrib; @@ -563,9 +573,6 @@ void main() { } vec4 base_color = color; - if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) { - color = vec4(0.0); //invisible by default due to using light mask - } #ifdef MODE_LIGHT_ONLY float light_only_alpha = 0.0; diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index 2dd5abb75f6..7ac7cf9c07f 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -12,7 +12,7 @@ #define FLAGS_CLIP_RECT_UV (1 << 9) #define FLAGS_TRANSPOSE_RECT (1 << 10) -#define FLAGS_USING_LIGHT_MASK (1 << 11) +#define FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 11) #define FLAGS_NINEPACH_DRAW_CENTER (1 << 12) #define FLAGS_USING_PARTICLES (1 << 13) diff --git a/servers/rendering/renderer_rd/shaders/effects/copy.glsl b/servers/rendering/renderer_rd/shaders/effects/copy.glsl index 3a828610578..2b3d27b0003 100644 --- a/servers/rendering/renderer_rd/shaders/effects/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/copy.glsl @@ -57,7 +57,7 @@ layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffe #elif defined(DST_IMAGE_8BIT) layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; #else -layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +layout(rgba16f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; #endif #ifdef MODE_GAUSSIAN_BLUR diff --git a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl index 52aee8b6483..29abff29114 100644 --- a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl @@ -57,14 +57,21 @@ layout(set = 3, binding = 0) uniform sampler2D source_color_correction; layout(set = 3, binding = 0) uniform sampler3D source_color_correction; #endif +#define FLAG_USE_BCS (1 << 0) +#define FLAG_USE_GLOW (1 << 1) +#define FLAG_USE_AUTO_EXPOSURE (1 << 2) +#define FLAG_USE_COLOR_CORRECTION (1 << 3) +#define FLAG_USE_FXAA (1 << 4) +#define FLAG_USE_DEBANDING (1 << 5) +#define FLAG_CONVERT_TO_SRGB (1 << 6) + layout(push_constant, std430) uniform Params { vec3 bcs; - bool use_bcs; + uint flags; - bool use_glow; - bool use_auto_exposure; - bool use_color_correction; + vec2 pixel_size; uint tonemapper; + uint pad; uvec2 glow_texture_size; float glow_intensity; @@ -77,10 +84,6 @@ layout(push_constant, std430) uniform Params { float white; float auto_exposure_scale; float luminance_multiplier; - - vec2 pixel_size; - bool use_fxaa; - bool use_debanding; } params; @@ -318,10 +321,12 @@ vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blendi if (params.glow_mode == GLOW_MODE_ADD) { return color + glow; } else if (params.glow_mode == GLOW_MODE_SCREEN) { - //need color clamping + // Needs color clamping. + glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f)); return max((color + glow) - (color * glow), vec3(0.0)); } else if (params.glow_mode == GLOW_MODE_SOFTLIGHT) { - //need color clamping + // Needs color clamping. + glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f)); glow = glow * vec3(0.5f) + vec3(0.5f); color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r))); @@ -439,7 +444,7 @@ void main() { float exposure = params.exposure; #ifndef SUBPASS - if (params.use_auto_exposure) { + if (bool(params.flags & FLAG_USE_AUTO_EXPOSURE)) { exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r * params.luminance_multiplier / params.auto_exposure_scale); } #endif @@ -448,12 +453,12 @@ void main() { // Early Tonemap & SRGB Conversion #ifndef SUBPASS - if (params.use_fxaa) { + if (bool(params.flags & FLAG_USE_FXAA)) { // FXAA must be performed before glow to preserve the "bleed" effect of glow. color.rgb = do_fxaa(color.rgb, exposure, uv_interp); } - if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) { + if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode == GLOW_MODE_MIX) { vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier; if (params.glow_map_strength > 0.001) { glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); @@ -464,11 +469,12 @@ void main() { color.rgb = apply_tonemapping(color.rgb, params.white); - color.rgb = linear_to_srgb(color.rgb); // regular linear -> SRGB conversion - + if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) { + color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion. + } #ifndef SUBPASS // Glow - if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) { + if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode != GLOW_MODE_MIX) { vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier; if (params.glow_map_strength > 0.001) { glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); @@ -476,7 +482,9 @@ void main() { // high dynamic range -> SRGB glow = apply_tonemapping(glow, params.white); - glow = linear_to_srgb(glow); + if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) { + glow = linear_to_srgb(glow); + } color.rgb = apply_glow(color.rgb, glow); } @@ -484,15 +492,15 @@ void main() { // Additional effects - if (params.use_bcs) { + if (bool(params.flags & FLAG_USE_BCS)) { color.rgb = apply_bcs(color.rgb, params.bcs); } - if (params.use_color_correction) { + if (bool(params.flags & FLAG_USE_COLOR_CORRECTION)) { color.rgb = apply_color_correction(color.rgb); } - if (params.use_debanding) { + if (bool(params.flags & FLAG_USE_DEBANDING)) { // Debanding should be done at the end of tonemapping, but before writing to the LDR buffer. // Otherwise, we're adding noise to an already-quantized image. color.rgb += screen_space_dither(gl_FragCoord.xy); diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index d055f010096..a96893570e8 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -751,7 +751,7 @@ MaterialStorage::MaterialData::~MaterialData() { } } -void MaterialStorage::MaterialData::update_textures(const HashMap &p_parameters, const HashMap> &p_default_textures, const Vector &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { +void MaterialStorage::MaterialData::update_textures(const HashMap &p_parameters, const HashMap> &p_default_textures, const Vector &p_texture_uniforms, RID *p_textures, bool p_use_linear_color, bool p_3d_material) { TextureStorage *texture_storage = TextureStorage::get_singleton(); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -917,7 +917,7 @@ void MaterialStorage::MaterialData::update_textures(const HashMaprd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture; #ifdef TOOLS_ENABLED - if (tex->detect_3d_callback && p_use_linear_color) { + if (tex->detect_3d_callback && p_3d_material) { tex->detect_3d_callback(tex->detect_3d_callback_ud); } if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) { @@ -986,7 +986,7 @@ void MaterialStorage::MaterialData::free_parameters_uniform_set(RID p_uniform_se } } -bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap &p_uniforms, const uint32_t *p_uniform_offsets, const Vector &p_texture_uniforms, const HashMap> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, uint32_t p_barrier) { +bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap &p_uniforms, const uint32_t *p_uniform_offsets, const Vector &p_texture_uniforms, const HashMap> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material, uint32_t p_barrier) { if ((uint32_t)ubo_data.size() != p_ubo_size) { p_uniform_dirty = true; if (uniform_buffer.is_valid()) { @@ -1033,7 +1033,7 @@ bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap< } if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, p_default_texture_params, p_texture_uniforms, texture_cache.ptrw(), p_use_linear_color); + update_textures(p_parameters, p_default_texture_params, p_texture_uniforms, texture_cache.ptrw(), p_use_linear_color, p_3d_material); } if (p_ubo_size == 0 && (p_texture_uniforms.size() == 0)) { diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h index b6da3df783f..ae97f43a3c4 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h @@ -78,7 +78,7 @@ public: struct MaterialData { Vector render_target_cache; void update_uniform_buffer(const HashMap &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color); - void update_textures(const HashMap &p_parameters, const HashMap> &p_default_textures, const Vector &p_texture_uniforms, RID *p_textures, bool p_use_linear_color); + void update_textures(const HashMap &p_parameters, const HashMap> &p_default_textures, const Vector &p_texture_uniforms, RID *p_textures, bool p_use_linear_color, bool p_3d_material); void set_as_used(); virtual void set_render_priority(int p_priority) = 0; @@ -87,7 +87,7 @@ public: virtual ~MaterialData(); //to be used internally by update_parameters, in the most common configuration of material parameters - bool update_parameters_uniform_set(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap &p_uniforms, const uint32_t *p_uniform_offsets, const Vector &p_texture_uniforms, const HashMap> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); + bool update_parameters_uniform_set(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap &p_uniforms, const uint32_t *p_uniform_offsets, const Vector &p_texture_uniforms, const HashMap> &p_default_texture_params, uint32_t p_ubo_size, RID &r_uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, bool p_3d_material, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); void free_parameters_uniform_set(RID p_uniform_set); private: diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 8f647be5c99..0a91672544d 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -1629,7 +1629,7 @@ MaterialStorage::ShaderData *ParticlesStorage::_create_particles_shader_func() { } bool ParticlesStorage::ParticleProcessMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3, true); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3, true, false); } ParticlesStorage::ParticleProcessMaterialData::~ParticleProcessMaterialData() { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index d84f6e68506..f009318d245 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -46,9 +46,11 @@ void TextureStorage::CanvasTexture::clear_sets() { } for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { - if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j])) { - RD::get_singleton()->free(uniform_sets[i][j]); - uniform_sets[i][j] = RID(); + for (int k = 0; k < 2; k++) { + if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j][k])) { + RD::get_singleton()->free(uniform_sets[i][j][k]); + uniform_sets[i][j][k] = RID(); + } } } } @@ -641,7 +643,7 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS: ct->clear_sets(); } -bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) { +bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) { MaterialStorage *material_storage = MaterialStorage::get_singleton(); CanvasTexture *ct = nullptr; @@ -674,7 +676,7 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte RS::CanvasItemTextureRepeat repeat = ct->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? ct->texture_repeat : p_base_repeat; ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, false); - RID uniform_set = ct->uniform_sets[filter][repeat]; + RID uniform_set = ct->uniform_sets[filter][repeat][int(p_use_srgb)]; if (!RD::get_singleton()->uniform_set_is_valid(uniform_set)) { //create and update Vector uniforms; @@ -688,7 +690,7 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE)); ct->size_cache = Size2i(1, 1); } else { - u.append_id(t->rd_texture); + u.append_id(t->rd_texture_srgb.is_valid() && (p_use_srgb) ? t->rd_texture_srgb : t->rd_texture); ct->size_cache = Size2i(t->width_2d, t->height_2d); if (t->render_target) { t->render_target->was_used = true; @@ -741,7 +743,7 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte } uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, p_base_set); - ct->uniform_sets[filter][repeat] = uniform_set; + ct->uniform_sets[filter][repeat][int(p_use_srgb)] = uniform_set; ct->cleared_cache = false; } @@ -1268,7 +1270,35 @@ Ref TextureStorage::texture_2d_get(RID p_texture) const { #endif Vector data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0); ERR_FAIL_COND_V(data.size() == 0, Ref()); - Ref image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); + Ref image; + + // Expand RGB10_A2 into RGBAH. This is needed for capturing viewport data + // when using the mobile renderer with HDR mode on. + if (tex->rd_format == RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32) { + Vector new_data; + new_data.resize(data.size() * 2); + uint16_t *ndp = (uint16_t *)new_data.ptr(); + + uint32_t *ptr = (uint32_t *)data.ptr(); + uint32_t num_pixels = data.size() / 4; + + for (uint32_t ofs = 0; ofs < num_pixels; ofs++) { + uint32_t px = ptr[ofs]; + uint32_t r = (px & 0x3FF); + uint32_t g = ((px >> 10) & 0x3FF); + uint32_t b = ((px >> 20) & 0x3FF); + uint32_t a = ((px >> 30) & 0x3); + + ndp[ofs * 4 + 0] = Math::make_half_float(float(r) / 1023.0); + ndp[ofs * 4 + 1] = Math::make_half_float(float(g) / 1023.0); + ndp[ofs * 4 + 2] = Math::make_half_float(float(b) / 1023.0); + ndp[ofs * 4 + 3] = Math::make_half_float(float(a) / 3.0); + } + image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, new_data); + } else { + image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); + } + ERR_FAIL_COND_V(image->is_empty(), Ref()); if (tex->format != tex->validated_format) { image->convert(tex->format); @@ -3020,10 +3050,15 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { if (rt->size.width == 0 || rt->size.height == 0) { return; } - //until we implement support for HDR monitors (and render target is attached to screen), this is enough. - rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM; - rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; - rt->image_format = rt->is_transparent ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8; + if (rt->use_hdr) { + rt->color_format = RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format(); + rt->color_format_srgb = rt->color_format; + rt->image_format = rt->is_transparent ? Image::FORMAT_RGBAH : Image::FORMAT_RGBH; + } else { + rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + rt->image_format = rt->is_transparent ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8; + } RD::TextureFormat rd_color_attachment_format; RD::TextureView rd_view; @@ -3106,6 +3141,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { tex->rd_format = rt->color_format; tex->rd_format_srgb = rt->color_format_srgb; tex->format = rt->image_format; + tex->validated_format = rt->use_hdr ? Image::FORMAT_RGBAH : Image::FORMAT_RGBA8; Vector proxies = tex->proxies; //make a copy, since update may change it for (int i = 0; i < proxies.size(); i++) { @@ -3328,6 +3364,25 @@ RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) con return rt->msaa; } +void TextureStorage::render_target_set_use_hdr(RID p_render_target, bool p_use_hdr) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + if (p_use_hdr == rt->use_hdr) { + return; + } + + rt->use_hdr = p_use_hdr; + _update_render_target(rt); +} + +bool TextureStorage::render_target_is_using_hdr(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, false); + + return rt->use_hdr; +} + RID TextureStorage::render_target_get_rd_framebuffer(RID p_render_target) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); @@ -3404,7 +3459,7 @@ bool TextureStorage::render_target_is_clear_requested(RID p_render_target) { Color TextureStorage::render_target_get_clear_request_color(RID p_render_target) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, Color()); - return rt->clear_color; + return rt->use_hdr ? rt->clear_color.srgb_to_linear() : rt->clear_color; } void TextureStorage::render_target_disable_clear_request(RID p_render_target) { @@ -3420,7 +3475,7 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) { return; } Vector clear_colors; - clear_colors.push_back(rt->clear_color); + clear_colors.push_back(rt->use_hdr ? rt->clear_color.srgb_to_linear() : rt->clear_color); RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors); RD::get_singleton()->draw_list_end(); rt->clear_requested = false; @@ -3735,7 +3790,7 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons // TODO figure out stereo support here if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { - copy_effects->copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true); + copy_effects->copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, !rt->use_hdr, true); } else { copy_effects->copy_to_fb_rect(rt->color, rt->backbuffer_fb, region, false, false, false, false, RID(), false, true); } @@ -3759,7 +3814,7 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons RID mipmap = rt->backbuffer_mipmaps[i]; if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { - copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, true); + copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, !rt->use_hdr); } else { copy_effects->gaussian_blur_raster(prev_texture, mipmap, region, texture_size); } @@ -3789,9 +3844,9 @@ void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const } } - //single texture copy for backbuffer + // Single texture copy for backbuffer. if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { - copy_effects->set_color(rt->backbuffer_mipmap0, p_color, region, true); + copy_effects->set_color(rt->backbuffer_mipmap0, p_color, region, !rt->use_hdr); } else { copy_effects->set_color_raster(rt->backbuffer_mipmap0, p_color, region); } @@ -3833,7 +3888,7 @@ void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target, RID mipmap = rt->backbuffer_mipmaps[i]; if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { - copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, true); + copy_effects->gaussian_blur(prev_texture, mipmap, region, texture_size, !rt->use_hdr); } else { copy_effects->gaussian_blur_raster(prev_texture, mipmap, region, texture_size); } diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 6df6faa40ab..2137c5f3838 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -96,7 +96,7 @@ private: RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; - RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX]; + RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX][2]; Size2i size_cache = Size2i(1, 1); bool use_normal_cache = false; @@ -341,6 +341,7 @@ private: Image::Format image_format = Image::FORMAT_L8; bool is_transparent = false; + bool use_hdr = false; bool sdf_enabled = false; @@ -474,7 +475,7 @@ public: virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override; virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override; - bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular); + bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular); /* Texture API */ @@ -717,6 +718,8 @@ public: virtual void render_target_set_as_unused(RID p_render_target) override; virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override; virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override; + virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr) override; + virtual bool render_target_is_using_hdr(RID p_render_target) const override; void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps); void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color); diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 7a829826d2b..75371de814d 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -1163,6 +1163,17 @@ void RendererViewport::viewport_set_msaa_3d(RID p_viewport, RS::ViewportMSAA p_m _configure_3d_render_buffers(viewport); } +void RendererViewport::viewport_set_use_hdr_2d(RID p_viewport, bool p_use_hdr_2d) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + if (viewport->use_hdr_2d == p_use_hdr_2d) { + return; + } + viewport->use_hdr_2d = p_use_hdr_2d; + RSG::texture_storage->render_target_set_use_hdr(viewport->render_target, p_use_hdr_2d); +} + void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) { Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index c004d05b23c..92c5929796b 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -116,6 +116,7 @@ public: RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; bool transparent_bg = false; + bool use_hdr_2d = false; uint32_t canvas_cull_mask = 0xffffffff; @@ -157,6 +158,7 @@ public: update_mode = RS::VIEWPORT_UPDATE_WHEN_VISIBLE; clear_mode = RS::VIEWPORT_CLEAR_ALWAYS; transparent_bg = false; + use_hdr_2d = false; viewport_to_screen = DisplayServer::INVALID_WINDOW_ID; shadow_atlas_size = 0; @@ -250,6 +252,7 @@ public: void viewport_remove_canvas(RID p_viewport, RID p_canvas); void viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset); void viewport_set_transparent_background(RID p_viewport, bool p_enabled); + void viewport_set_use_hdr_2d(RID p_viewport, bool p_use_hdr_2d); void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform); void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index e9b40eb0821..9ad21753322 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -629,6 +629,7 @@ public: FUNC2(viewport_remove_canvas, RID, RID) FUNC3(viewport_set_canvas_transform, RID, RID, const Transform2D &) FUNC2(viewport_set_transparent_background, RID, bool) + FUNC2(viewport_set_use_hdr_2d, RID, bool) FUNC2(viewport_set_snap_2d_transforms_to_pixel, RID, bool) FUNC2(viewport_set_snap_2d_vertices_to_pixel, RID, bool) diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index c3a257595c2..6332dd578ef 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -151,6 +151,8 @@ public: virtual void render_target_set_as_unused(RID p_render_target) = 0; virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) = 0; virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const = 0; + virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr) = 0; + virtual bool render_target_is_using_hdr(RID p_render_target) const = 0; virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0; virtual bool render_target_is_clear_requested(RID p_render_target) = 0; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 48b38cf2b78..45ba0b3c089 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2231,6 +2231,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_positional_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &RenderingServer::viewport_set_positional_shadow_atlas_quadrant_subdivision); ClassDB::bind_method(D_METHOD("viewport_set_msaa_3d", "viewport", "msaa"), &RenderingServer::viewport_set_msaa_3d); ClassDB::bind_method(D_METHOD("viewport_set_msaa_2d", "viewport", "msaa"), &RenderingServer::viewport_set_msaa_2d); + ClassDB::bind_method(D_METHOD("viewport_set_use_hdr_2d", "viewport", "enabled"), &RenderingServer::viewport_set_use_hdr_2d); ClassDB::bind_method(D_METHOD("viewport_set_screen_space_aa", "viewport", "mode"), &RenderingServer::viewport_set_screen_space_aa); ClassDB::bind_method(D_METHOD("viewport_set_use_taa", "viewport", "enable"), &RenderingServer::viewport_set_use_taa); ClassDB::bind_method(D_METHOD("viewport_set_use_debanding", "viewport", "enable"), &RenderingServer::viewport_set_use_debanding); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 618ceb3091f..1528a957ce4 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -863,6 +863,7 @@ public: virtual void viewport_remove_canvas(RID p_viewport, RID p_canvas) = 0; virtual void viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) = 0; virtual void viewport_set_transparent_background(RID p_viewport, bool p_enabled) = 0; + virtual void viewport_set_use_hdr_2d(RID p_viewport, bool p_use_hdr) = 0; virtual void viewport_set_snap_2d_transforms_to_pixel(RID p_viewport, bool p_enabled) = 0; virtual void viewport_set_snap_2d_vertices_to_pixel(RID p_viewport, bool p_enabled) = 0;