From 5335a0368ca437df085320871ab59f36e88c3506 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Mon, 16 Aug 2021 03:16:01 +0200 Subject: [PATCH] Add a Viewport property to use full floating-point precision in HDR This is only available on the GLES3 backend. This can be useful for advanced shaders, but it should generally not be enabled otherwise as full precision has a performance cost. For general-purpose rendering, the built-in debanding filter should be used to reduce banding instead. --- doc/classes/ProjectSettings.xml | 7 ++++++- doc/classes/Viewport.xml | 8 +++++++- drivers/gles3/rasterizer_storage_gles3.cpp | 23 ++++++++++++++++------ editor/plugins/spatial_editor_plugin.cpp | 5 ++++- scene/main/scene_tree.cpp | 9 +++++++-- scene/main/viewport.cpp | 20 ++++++++++++++++++- scene/main/viewport.h | 4 ++++ servers/visual/rasterizer.h | 1 + servers/visual/visual_server_raster.h | 1 + servers/visual/visual_server_viewport.cpp | 7 +++++++ servers/visual/visual_server_viewport.h | 1 + servers/visual/visual_server_wrap_mt.h | 1 + servers/visual_server.h | 1 + 13 files changed, 76 insertions(+), 12 deletions(-) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 77080561bb63..c93711574289 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1267,12 +1267,17 @@ [b]Note:[/b] Generally you should only use this option if you encounter bugs when it is set to [code]false[/code], i.e. there are problems with the default method. - If [code]true[/code], allocates the main framebuffer with high dynamic range. High dynamic range allows the use of [Color] values greater than 1. + If [code]true[/code], allocates the root [Viewport]'s framebuffer with high dynamic range. High dynamic range allows the use of [Color] values greater than 1. [b]Note:[/b] Only available on the GLES3 backend. Lower-end override for [member rendering/quality/depth/hdr] on mobile devices, due to performance concerns or driver support. + + If [code]true[/code], allocates the root [Viewport]'s framebuffer with full floating-point precision (32-bit) instead of half floating-point precision (16-bit). Only effective when [member rendering/quality/depth/hdr] is also enabled. + [b]Note:[/b] Enabling this setting does not improve rendering quality. Using full floating-point precision is slower, and is generally only needed for advanced shaders that require a high level of precision. To reduce banding, enable [member rendering/quality/filters/use_debanding] instead. + [b]Note:[/b] Only available on the GLES3 backend. + Disables depth pre-pass for some GPU vendors (usually mobile), as their architecture already does this. diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index bac34471c199..b98bc07e402d 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -224,8 +224,9 @@ - If [code]true[/code], the viewport rendering will receive benefits from High Dynamic Range algorithm. High Dynamic Range allows the viewport to receive values that are outside the 0-1 range. In Godot HDR uses 16 bits, meaning it does not store the full range of a floating point number. + If [code]true[/code], the viewport rendering will receive benefits from High Dynamic Range algorithm. High Dynamic Range allows the viewport to receive values that are outside the 0-1 range. In Godot, HDR uses half floating-point precision (16-bit) by default. To use full floating-point precision (32-bit), enable [member use_32_bpc_depth]. [b]Note:[/b] Requires [member usage] to be set to [constant USAGE_3D] or [constant USAGE_3D_NO_EFFECTS], since HDR is not supported for 2D. + [b]Note:[/b] Only available on the GLES3 backend. If [code]true[/code], the result after 3D rendering will not have a linear to sRGB color conversion applied. This is important when the viewport is used as a render target where the result is used as a texture on a 3D object rendered in another viewport. It is also important if the viewport is used to create data that is not color based (noise, heightmaps, pickmaps, etc.). Do not enable this when the viewport is used as a texture on a 2D object or if the viewport is your final output. @@ -283,6 +284,11 @@ The rendering mode of viewport. + + If [code]true[/code], allocates the viewport's framebuffer with full floating-point precision (32-bit) instead of half floating-point precision (16-bit). Only effective when [member hdr] is also enabled. + [b]Note:[/b] Enabling this setting does not improve rendering quality. Using full floating-point precision is slower, and is generally only needed for advanced shaders that require a high level of precision. To reduce banding, enable [member debanding] instead. + [b]Note:[/b] Only available on the GLES3 backend. + The custom [World] which can be used as 3D environment source. diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index eedae2406f31..b246397dcd00 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -6873,8 +6873,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { GLuint color_type; Image::Format image_format; - bool hdr = rt->flags[RENDER_TARGET_HDR] && config.framebuffer_half_float_supported; - //hdr = false; + const bool hdr = rt->flags[RENDER_TARGET_HDR] && config.framebuffer_half_float_supported; if (!hdr || rt->flags[RENDER_TARGET_NO_3D]) { if (rt->flags[RENDER_TARGET_NO_3D_EFFECTS] && !rt->flags[RENDER_TARGET_TRANSPARENT]) { @@ -6891,10 +6890,21 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { image_format = Image::FORMAT_RGBA8; } } else { - color_internal_format = GL_RGBA16F; - color_format = GL_RGBA; - color_type = GL_HALF_FLOAT; - image_format = Image::FORMAT_RGBAH; + // HDR enabled. + if (rt->flags[RENDER_TARGET_USE_32_BPC_DEPTH]) { + // 32 bpc. Can be useful for advanced shaders, but should not be used + // for general-purpose rendering as it's slower. + color_internal_format = GL_RGBA32F; + color_format = GL_RGBA; + color_type = GL_FLOAT; + image_format = Image::FORMAT_RGBAF; + } else { + // 16 bpc. This is the default HDR mode. + color_internal_format = GL_RGBA16F; + color_format = GL_RGBA; + color_type = GL_HALF_FLOAT; + image_format = Image::FORMAT_RGBAH; + } } { @@ -7436,6 +7446,7 @@ void RasterizerStorageGLES3::render_target_set_flag(RID p_render_target, RenderT switch (p_flag) { case RENDER_TARGET_HDR: + case RENDER_TARGET_USE_32_BPC_DEPTH: case RENDER_TARGET_NO_3D: case RENDER_TARGET_NO_SAMPLING: case RENDER_TARGET_NO_3D_EFFECTS: { diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 18c62bc6695a..ffad6a3d8d28 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2520,9 +2520,12 @@ void SpatialEditorViewport::_notification(int p_what) { float sharpen_intensity = ProjectSettings::get_singleton()->get("rendering/quality/filters/sharpen_intensity"); viewport->set_sharpen_intensity(sharpen_intensity); - bool hdr = ProjectSettings::get_singleton()->get("rendering/quality/depth/hdr"); + const bool hdr = ProjectSettings::get_singleton()->get("rendering/quality/depth/hdr"); viewport->set_hdr(hdr); + const bool use_32_bpc_depth = ProjectSettings::get_singleton()->get("rendering/quality/depth/use_32_bpc_depth"); + viewport->set_use_32_bpc_depth(use_32_bpc_depth); + bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); info_label->set_visible(show_info); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 3b219e9f0381..7c5cbff60d4a 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -2069,12 +2069,17 @@ SceneTree::SceneTree() { const float sharpen_intensity = GLOBAL_GET("rendering/quality/filters/sharpen_intensity"); root->set_sharpen_intensity(sharpen_intensity); - GLOBAL_DEF_RST("rendering/quality/depth/hdr", true); + GLOBAL_DEF("rendering/quality/depth/hdr", true); GLOBAL_DEF("rendering/quality/depth/hdr.mobile", false); - bool hdr = GLOBAL_GET("rendering/quality/depth/hdr"); + const bool hdr = GLOBAL_GET("rendering/quality/depth/hdr"); root->set_hdr(hdr); + GLOBAL_DEF("rendering/quality/depth/use_32_bpc_depth", false); + + const bool use_32_bpc_depth = GLOBAL_GET("rendering/quality/depth/use_32_bpc_depth"); + root->set_use_32_bpc_depth(use_32_bpc_depth); + VS::get_singleton()->scenario_set_reflection_atlas_size(root->get_world()->get_scenario(), ref_atlas_size, ref_atlas_subdiv); { //load default fallback environment diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 01a2ba963475..b92787e63962 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3013,6 +3013,19 @@ bool Viewport::get_hdr() const { return hdr; } +void Viewport::set_use_32_bpc_depth(bool p_enable) { + if (use_32_bpc_depth == p_enable) { + return; + } + + use_32_bpc_depth = p_enable; + VS::get_singleton()->viewport_set_use_32_bpc_depth(viewport, p_enable); +} + +bool Viewport::is_using_32_bpc_depth() const { + return use_32_bpc_depth; +} + void Viewport::set_usage(Usage p_usage) { usage = p_usage; VS::get_singleton()->viewport_set_usage(viewport, VS::ViewportUsage(p_usage)); @@ -3075,7 +3088,7 @@ bool Viewport::is_handling_input_locally() const { } void Viewport::_validate_property(PropertyInfo &property) const { - if (VisualServer::get_singleton()->is_low_end() && property.name == "hdr") { + if (VisualServer::get_singleton()->is_low_end() && (property.name == "hdr" || property.name == "use_32_bpc_depth")) { property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; } } @@ -3138,6 +3151,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hdr", "enable"), &Viewport::set_hdr); ClassDB::bind_method(D_METHOD("get_hdr"), &Viewport::get_hdr); + ClassDB::bind_method(D_METHOD("set_use_32_bpc_depth", "enable"), &Viewport::set_use_32_bpc_depth); + ClassDB::bind_method(D_METHOD("get_use_32_bpc_depth"), &Viewport::is_using_32_bpc_depth); + ClassDB::bind_method(D_METHOD("set_usage", "usage"), &Viewport::set_usage); ClassDB::bind_method(D_METHOD("get_usage"), &Viewport::get_usage); @@ -3229,6 +3245,7 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debanding"), "set_use_debanding", "get_use_debanding"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "sharpen_intensity"), "set_sharpen_intensity", "get_sharpen_intensity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "get_hdr"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_32_bpc_depth"), "set_use_32_bpc_depth", "get_use_32_bpc_depth"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_3d_linear"), "set_keep_3d_linear", "get_keep_3d_linear"); ADD_PROPERTY(PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_ENUM, "2D,2D No-Sampling,3D,3D No-Effects"), "set_usage", "get_usage"); @@ -3389,6 +3406,7 @@ Viewport::Viewport() { use_debanding = false; sharpen_intensity = 0.0; hdr = true; + use_32_bpc_depth = false; usage = USAGE_3D; debug_draw = DEBUG_DRAW_DISABLED; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 360f75860452..4df764ae63ec 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -283,6 +283,7 @@ class Viewport : public Node { bool use_debanding; float sharpen_intensity; bool hdr; + bool use_32_bpc_depth; Ref default_texture; Set viewport_textures; @@ -509,6 +510,9 @@ class Viewport : public Node { void set_hdr(bool p_hdr); bool get_hdr() const; + void set_use_32_bpc_depth(bool p_enable); + bool is_using_32_bpc_depth() const; + Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const; Vector2 get_camera_rect_size() const; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index fc9b0021300c..bf02eedf2bde 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -562,6 +562,7 @@ class RasterizerStorage { RENDER_TARGET_HDR, RENDER_TARGET_KEEP_3D_LINEAR, RENDER_TARGET_DIRECT_TO_SCREEN, + RENDER_TARGET_USE_32_BPC_DEPTH, RENDER_TARGET_FLAG_MAX }; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index a35e64ffaf72..dbfdce0cc002 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -490,6 +490,7 @@ class VisualServerRaster : public VisualServer { BIND2(viewport_set_use_debanding, RID, bool) BIND2(viewport_set_sharpen_intensity, RID, float) BIND2(viewport_set_hdr, RID, bool) + BIND2(viewport_set_use_32_bpc_depth, RID, bool) BIND2(viewport_set_usage, RID, ViewportUsage) BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo) diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 28a31b479c46..e299ee264445 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -648,6 +648,13 @@ void VisualServerViewport::viewport_set_hdr(RID p_viewport, bool p_enabled) { VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_HDR, p_enabled); } +void VisualServerViewport::viewport_set_use_32_bpc_depth(RID p_viewport, bool p_enabled) { + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_USE_32_BPC_DEPTH, p_enabled); +} + void VisualServerViewport::viewport_set_usage(RID p_viewport, VS::ViewportUsage p_usage) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index 201d1c70e634..adcef9f97d01 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -190,6 +190,7 @@ class VisualServerViewport { void viewport_set_use_debanding(RID p_viewport, bool p_debanding); void viewport_set_sharpen_intensity(RID p_viewport, float p_intensity); void viewport_set_hdr(RID p_viewport, bool p_enabled); + void viewport_set_use_32_bpc_depth(RID p_viewport, bool p_enabled); void viewport_set_usage(RID p_viewport, VS::ViewportUsage p_usage); virtual int viewport_get_render_info(RID p_viewport, VS::ViewportRenderInfo p_info); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index a4cd6cd444dd..63ef62a4fa81 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -418,6 +418,7 @@ class VisualServerWrapMT : public VisualServer { FUNC2(viewport_set_use_debanding, RID, bool) FUNC2(viewport_set_sharpen_intensity, RID, float) FUNC2(viewport_set_hdr, RID, bool) + FUNC2(viewport_set_use_32_bpc_depth, RID, bool) FUNC2(viewport_set_usage, RID, ViewportUsage) //this passes directly to avoid stalling, but it's pretty dangerous, so don't call after freeing a viewport diff --git a/servers/visual_server.h b/servers/visual_server.h index 6d2c3f9826eb..0798535720e2 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -701,6 +701,7 @@ class VisualServer : public Object { }; virtual void viewport_set_hdr(RID p_viewport, bool p_enabled) = 0; + virtual void viewport_set_use_32_bpc_depth(RID p_viewport, bool p_enabled) = 0; virtual void viewport_set_usage(RID p_viewport, ViewportUsage p_usage) = 0; enum ViewportRenderInfo {