Skip to content

Commit

Permalink
Implement force_high_precision and keep_linear flags for Viewport
Browse files Browse the repository at this point in the history
Toggles allowing to change the buffer format to higher precision and output raw data (no
tonemapping) using a viewport.

Implement in both Vulkan and GLES3.

Co-authored-by: Clay John <claynjohn@gmail.com>
  • Loading branch information
JonqsGames and clayjohn committed Aug 30, 2022
1 parent 0b5d728 commit 350b188
Show file tree
Hide file tree
Showing 29 changed files with 202 additions and 35 deletions.
17 changes: 17 additions & 0 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3185,6 +3185,15 @@
If [code]true[/code], rendering of a viewport's environment is disabled.
</description>
</method>
<method name="viewport_set_force_high_precision">
<return type="void" />
<param index="0" name="viewport" type="RID" />
<param index="1" name="enable" type="bool" />
<description>
If [code]true[/code] and using the Vulkan-Clustered or Vulkan-mobile renderer, high precision will be used in the 2D rendering pipeline (3D is always high precision) and [method viewport_get_texture] will return an image with the [constant Image.FORMAT_RGBAH] format.
Use with [method viewport_set_keep_linear] to obtain an accurate texture containing the rendering results from a frame.
</description>
</method>
<method name="viewport_set_fsr_sharpness">
<return type="void" />
<param index="0" name="viewport" type="RID" />
Expand All @@ -3201,6 +3210,14 @@
Sets the viewport's global transformation matrix.
</description>
</method>
<method name="viewport_set_keep_linear">
<return type="void" />
<param index="0" name="viewport" type="RID" />
<param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], skip linear to sRGB conversion during tonemapping. If used without [method viewport_set_force_high_precision] this can result in significant banding in the rendered output.
</description>
</method>
<method name="viewport_set_measure_render_time">
<return type="void" />
<param index="0" name="viewport" type="RID" />
Expand Down
7 changes: 7 additions & 0 deletions doc/classes/Viewport.xml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@
<member name="disable_3d" type="bool" setter="set_disable_3d" getter="is_3d_disabled" default="false">
Disable 3D rendering (but keep 2D rendering).
</member>
<member name="force_high_precision" type="bool" setter="set_force_high_precision" getter="is_forced_high_precision" default="false">
If [code]true[/code] and using the Vulkan-Clustered or Vulkan-mobile renderer, high precision will be used in the 2D rendering pipeline (3D is always high precision) and [method get_texture] will return an image with the [constant Image.FORMAT_RGBAH] format. Use with [member keep_linear] to obtain an accurate texture containing the rendering results from a frame.
</member>
<member name="fsr_sharpness" type="float" setter="set_fsr_sharpness" getter="get_fsr_sharpness" default="0.2">
Determines how sharp the upscaled image will be when using the FSR upscaling mode. Sharpness halves with every whole number. Values go from 0.0 (sharpest) to 2.0. Values above 2.0 won't make a visible difference.
To control this property on the root viewport, set the [member ProjectSettings.rendering/scaling_3d/fsr_sharpness] project setting.
Expand All @@ -213,6 +216,10 @@
</member>
<member name="handle_input_locally" type="bool" setter="set_handle_input_locally" getter="is_handling_input_locally" default="true">
</member>
<member name="keep_linear" type="bool" setter="set_keep_linear" getter="is_keeping_linear" default="false">
If [code]true[/code], skip linear to sRGB conversion during tonemapping.
[b]Note:[/b] If used without [member force_high_precision] this can result in significant banding in the rendered output.
</member>
<member name="mesh_lod_threshold" type="float" setter="set_mesh_lod_threshold" getter="get_mesh_lod_threshold" default="1.0">
The automatic LOD bias to use for meshes rendered within the [Viewport] (this is analogous to [member ReflectionProbe.mesh_lod_threshold]). Higher values will use less detailed versions of meshes that have LOD variations generated. If set to [code]0.0[/code], automatic LOD is disabled. Increase [member mesh_lod_threshold] to improve performance at the cost of geometry detail.
To control this property on the root viewport, set the [member ProjectSettings.rendering/mesh_lod/lod_change/threshold_pixels] project setting.
Expand Down
5 changes: 4 additions & 1 deletion drivers/gles3/rasterizer_scene_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,7 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da

//time global variables
scene_state.ubo.time = time;
scene_state.ubo.keep_linear = p_render_data->keep_linear;

if (is_environment(p_render_data->environment)) {
RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
Expand Down Expand Up @@ -1721,6 +1722,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
}
render_data.render_info = r_render_info;
render_data.keep_linear = rb->keep_linear;
}

PagedArray<RID> empty;
Expand Down Expand Up @@ -2275,7 +2277,7 @@ RID RasterizerSceneGLES3::render_buffers_create() {
return render_buffers_owner.make_rid(rb);
}

void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count, bool p_keep_linear) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();

RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
Expand All @@ -2291,6 +2293,7 @@ void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_
//rb->screen_space_aa = p_screen_space_aa;
//rb->use_debanding = p_use_debanding;
//rb->view_count = p_view_count;
rb->keep_linear = p_keep_linear;

_free_render_buffer_data(rb);

Expand Down
7 changes: 5 additions & 2 deletions drivers/gles3/rasterizer_scene_gles3.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ struct RenderDataGLES3 {
uint32_t spot_light_count = 0;
uint32_t omni_light_count = 0;

bool keep_linear = false;

RendererScene::RenderInfo *render_info = nullptr;
};

Expand Down Expand Up @@ -354,10 +356,10 @@ class RasterizerSceneGLES3 : public RendererSceneRender {

float radiance_inverse_xform[12];

bool keep_linear = false;
uint32_t directional_light_count;
float z_far;
float z_near;
float pad1;

uint32_t fog_enabled;
float fog_density;
Expand Down Expand Up @@ -502,6 +504,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender {
//uint32_t view_count = 1;

bool is_transparent = false;
bool keep_linear = false;

RID render_target;
GLuint internal_texture = 0; // Used for rendering when post effects are enabled
Expand Down Expand Up @@ -762,7 +765,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender {
}

RID render_buffers_create() override;
void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count, bool p_keep_linear) override;
void gi_set_use_half_resolution(bool p_enable) override;

void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override;
Expand Down
18 changes: 11 additions & 7 deletions drivers/gles3/shaders/scene.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ layout(std140) uniform SceneData { // ubo:2

mat3 radiance_inverse_xform;

bool keep_linear;
uint directional_light_count;
float z_far;
float z_near;
float pad;

bool fog_enabled;
float fog_density;
Expand Down Expand Up @@ -448,10 +448,10 @@ layout(std140) uniform SceneData { // ubo:2

mat3 radiance_inverse_xform;

bool keep_linear;
uint directional_light_count;
float z_far;
float z_near;
float pad;

bool fog_enabled;
float fog_density;
Expand Down Expand Up @@ -1032,8 +1032,10 @@ void main() {
#ifndef MODE_RENDER_DEPTH

// Convert colors to linear
albedo = srgb_to_linear(albedo);
emission = srgb_to_linear(emission);
if (!scene_data.keep_linear) {
albedo = srgb_to_linear(albedo);
emission = srgb_to_linear(emission);
}
// TODO Backlight and transmittance when used
#ifndef MODE_UNSHADED
vec3 f0 = F0(metallic, specular, albedo);
Expand Down Expand Up @@ -1248,10 +1250,12 @@ void main() {
}
#endif

// Tonemap before writing as we are writing to an sRGB framebuffer
frag_color.rgb *= exposure;
frag_color.rgb = apply_tonemapping(frag_color.rgb, white);
frag_color.rgb = linear_to_srgb(frag_color.rgb);
if (!scene_data.keep_linear) {
// Tonemap before writing as we are writing to an sRGB framebuffer
frag_color.rgb = apply_tonemapping(frag_color.rgb, white);
frag_color.rgb = linear_to_srgb(frag_color.rgb);
}

#ifdef USE_BCS
frag_color.rgb = apply_bcs(frag_color.rgb, bcs);
Expand Down
2 changes: 2 additions & 0 deletions drivers/gles3/storage/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@ Config::Config() {
etc2_supported = false;
s3tc_supported = true;
rgtc_supported = true; //RGTC - core since OpenGL version 3.0
framebuffer_float_supported = true;
#else
float_texture_supported = extensions.has("GL_ARB_texture_float") || extensions.has("GL_OES_texture_float");
etc2_supported = true;
framebuffer_float_supported = extensions.has("GL_EXT_color_buffer_float") && extensions.has("GL_EXT_color_buffer_half_float");
#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
// Some Android devices report support for S3TC but we don't expect that and don't export the textures.
// This could be fixed but so few devices support it that it doesn't seem useful (and makes bigger APKs).
Expand Down
1 change: 1 addition & 0 deletions drivers/gles3/storage/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class Config {
bool rgtc_supported = false;
bool bptc_supported = false;
bool etc2_supported = false;
bool framebuffer_float_supported = false;

bool force_vertex_shading = false;

Expand Down
25 changes: 20 additions & 5 deletions drivers/gles3/storage/texture_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,7 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const {
GLuint TextureStorage::system_fbo = 0;

void TextureStorage::_update_render_target(RenderTarget *rt) {
Config *config = Config::get_singleton();
// do not allocate a render target with no size
if (rt->size.x <= 0 || rt->size.y <= 0) {
return;
Expand All @@ -1196,11 +1197,17 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
rt->fbo = system_fbo;
return;
}

rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2;
rt->color_format = GL_RGBA;
rt->color_type = rt->is_transparent ? GL_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
rt->image_format = Image::FORMAT_RGBA8;
if (rt->force_high_precision && config->framebuffer_float_supported) {
rt->color_internal_format = rt->is_transparent ? GL_RGBA16F : GL_RGB16F;
rt->color_format = GL_RGBA;
rt->color_type = GL_HALF_FLOAT;
rt->image_format = Image::FORMAT_RGBAF;
} else {
rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2;
rt->color_format = GL_RGBA;
rt->color_type = rt->is_transparent ? GL_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
rt->image_format = Image::FORMAT_RGBA8;
}

glDisable(GL_SCISSOR_TEST);
glColorMask(1, 1, 1, 1);
Expand Down Expand Up @@ -1390,6 +1397,14 @@ void TextureStorage::render_target_free(RID p_rid) {
}
render_target_owner.free(p_rid);
}
void TextureStorage::render_target_set_force_high_precision(RID p_render_target, bool p_force_high_precision) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
if (rt->force_high_precision != p_force_high_precision) {
rt->force_high_precision = p_force_high_precision;
_update_render_target(rt);
}
}

void TextureStorage::render_target_set_position(RID p_render_target, int p_x, int p_y) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
Expand Down
4 changes: 4 additions & 0 deletions drivers/gles3/storage/texture_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ struct RenderTarget {

bool is_transparent = false;
bool direct_to_screen = false;
bool force_high_precision = false;

bool used_in_frame = false;
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
Expand Down Expand Up @@ -518,6 +519,9 @@ class TextureStorage : public RendererTextureStorage {

virtual RID render_target_create() override;
virtual void render_target_free(RID p_rid) override;

virtual void render_target_set_force_high_precision(RID p_render_target, bool p_force_high_precision) override;

virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override;
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override;
Size2i render_target_get_size(RID p_render_target);
Expand Down
40 changes: 38 additions & 2 deletions scene/main/viewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2947,6 +2947,34 @@ bool Viewport::is_using_occlusion_culling() const {
return use_occlusion_culling;
}

void Viewport::set_keep_linear(bool p_keep_linear) {
if (keep_linear == p_keep_linear) {
return;
}
keep_linear = p_keep_linear;
RS::get_singleton()->viewport_set_keep_linear(viewport, p_keep_linear);

notify_property_list_changed();
}

bool Viewport::is_keeping_linear() const {
return keep_linear;
}

void Viewport::set_force_high_precision(bool p_force_high_precision) {
if (force_high_precision == p_force_high_precision) {
return;
}
force_high_precision = p_force_high_precision;
RS::get_singleton()->viewport_set_force_high_precision(viewport, force_high_precision);

notify_property_list_changed();
}

bool Viewport::is_forced_high_precision() const {
return force_high_precision;
}

void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
debug_draw = p_debug_draw;
RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw));
Expand Down Expand Up @@ -3590,7 +3618,6 @@ void Viewport::_propagate_exit_world_3d(Node *p_node) {
_propagate_exit_world_3d(p_node->get_child(i));
}
}

void Viewport::set_use_xr(bool p_use_xr) {
use_xr = p_use_xr;

Expand Down Expand Up @@ -3690,6 +3717,12 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_occlusion_culling", "enable"), &Viewport::set_use_occlusion_culling);
ClassDB::bind_method(D_METHOD("is_using_occlusion_culling"), &Viewport::is_using_occlusion_culling);

ClassDB::bind_method(D_METHOD("set_keep_linear", "enable"), &Viewport::set_keep_linear);
ClassDB::bind_method(D_METHOD("is_keeping_linear"), &Viewport::is_keeping_linear);

ClassDB::bind_method(D_METHOD("set_force_high_precision", "enable"), &Viewport::set_force_high_precision);
ClassDB::bind_method(D_METHOD("is_forced_high_precision"), &Viewport::is_forced_high_precision);

ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw);
ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw);

Expand Down Expand Up @@ -3821,6 +3854,8 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_taa"), "set_use_taa", "is_using_taa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_linear"), "set_keep_linear", "is_keeping_linear");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_high_precision"), "set_force_high_precision", "is_forced_high_precision");
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,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
#ifndef _3D_DISABLED
Expand Down Expand Up @@ -4145,6 +4180,7 @@ void SubViewport::_bind_methods() {
BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
}

SubViewport::SubViewport() {}
SubViewport::SubViewport() {
}

SubViewport::~SubViewport() {}
10 changes: 9 additions & 1 deletion scene/main/viewport.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@ class Viewport : public Node {
float mesh_lod_threshold = 1.0;
bool use_occlusion_culling = false;

bool keep_linear = false;
bool force_high_precision = false;

Ref<ViewportTexture> default_texture;
HashSet<ViewportTexture *> viewport_textures;

Expand Down Expand Up @@ -552,6 +555,12 @@ class Viewport : public Node {
void set_use_occlusion_culling(bool p_us_occlusion_culling);
bool is_using_occlusion_culling() const;

void set_keep_linear(bool p_keep_linear);
bool is_keeping_linear() const;

void set_force_high_precision(bool p_force_high_precision);
bool is_forced_high_precision() const;

Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;

Expand Down Expand Up @@ -704,7 +713,6 @@ class Viewport : public Node {
bool is_using_own_world_3d() const;
void _propagate_enter_world_3d(Node *p_node);
void _propagate_exit_world_3d(Node *p_node);

void set_use_xr(bool p_use_xr);
bool is_using_xr();
#endif // _3D_DISABLED
Expand Down
2 changes: 1 addition & 1 deletion servers/rendering/dummy/rasterizer_scene_dummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class RasterizerSceneDummy : public RendererSceneRender {
void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override {}

RID render_buffers_create() override { return RID(); }
void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override {}
void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count, bool p_keep_linear) override {}
void gi_set_use_half_resolution(bool p_enable) override {}

void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override {}
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/dummy/storage/texture_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class TextureStorage : public RendererTextureStorage {

virtual RID render_target_create() override { return RID(); }
virtual void render_target_free(RID p_rid) override {}
virtual void render_target_set_force_high_precision(RID p_render_target, bool p_force_high_precision) override {}
virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override {}
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override {}
virtual RID render_target_get_texture(RID p_render_target) override { return RID(); }
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/renderer_rd/effects/tone_mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton

tonemap.push_constant.use_fxaa = p_settings.use_fxaa;
tonemap.push_constant.use_debanding = p_settings.use_debanding;
tonemap.push_constant.keep_linear = p_settings.keep_linear;
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;

Expand Down Expand Up @@ -208,6 +209,7 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col
tonemap.push_constant.use_color_correction = p_settings.use_color_correction;

tonemap.push_constant.use_debanding = p_settings.use_debanding;
tonemap.push_constant.keep_linear = p_settings.keep_linear;
tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier;

RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
Expand Down
Loading

0 comments on commit 350b188

Please sign in to comment.