Add a debanding property to Viewport

It can be enabled in the Project Settings
(`rendering/quality/screen_filters/use_debanding`). It's disabled
by default as it has a small performance impact and can make
PNG screenshots much larger (due to how dithering works).
It will also slightly brighten the scene's dark areas.

As a result, it should be enabled only when banding is noticeable enough.

This closes #17006.
This commit is contained in:
Hugo Locurcio 2020-04-20 23:34:47 +02:00
parent aded76cb84
commit 8891579068
No known key found for this signature in database
GPG key ID: 39E8F8BE30B0A49C
16 changed files with 82 additions and 14 deletions

View file

@ -2447,12 +2447,14 @@ void Node3DEditorViewport::_notification(int p_what) {
subviewport_container->set_stretch_shrink(shrink ? 2 : 1);
}
//update msaa if changed
// Update MSAA, screen-space AA and debanding if changed
int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/screen_filters/msaa");
const int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/screen_filters/msaa");
viewport->set_msaa(Viewport::MSAA(msaa_mode));
int ssaa_mode = GLOBAL_GET("rendering/quality/screen_filters/screen_space_aa");
const int ssaa_mode = GLOBAL_GET("rendering/quality/screen_filters/screen_space_aa");
viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
const bool use_debanding = GLOBAL_GET("rendering/quality/screen_filters/use_debanding");
viewport->set_use_debanding(use_debanding);
bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
if (show_info != info_label->is_visible()) {

View file

@ -1383,14 +1383,17 @@ SceneTree::SceneTree() {
root->set_as_audio_listener_2d(true);
current_scene = nullptr;
int msaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/msaa", 0);
const int msaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/msaa", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/msaa", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Fast),4x (Average),8x (Slow),16x (Slower)"));
root->set_msaa(Viewport::MSAA(msaa_mode));
int ssaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/screen_space_aa", 0);
const int ssaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/screen_space_aa", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_aa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"));
root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
const bool use_debanding = GLOBAL_DEF("rendering/quality/screen_filters/use_debanding", false);
root->set_use_debanding(use_debanding);
{ //load default fallback environment
//get possible extensions
List<String> exts;

View file

@ -3133,6 +3133,17 @@ Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const {
return screen_space_aa;
}
void Viewport::set_use_debanding(bool p_use_debanding) {
if (use_debanding == p_use_debanding)
return;
use_debanding = p_use_debanding;
RS::get_singleton()->viewport_set_use_debanding(viewport, p_use_debanding);
}
bool Viewport::is_using_debanding() const {
return use_debanding;
}
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));
@ -3319,6 +3330,9 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &Viewport::set_screen_space_aa);
ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &Viewport::get_screen_space_aa);
ClassDB::bind_method(D_METHOD("set_use_debanding", "enable"), &Viewport::set_use_debanding);
ClassDB::bind_method(D_METHOD("is_using_debanding"), &Viewport::is_using_debanding);
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);
@ -3392,6 +3406,7 @@ void Viewport::_bind_methods() {
ADD_GROUP("Rendering", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa");
ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
ADD_GROUP("Canvas Items", "canvas_item_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");

View file

@ -279,6 +279,7 @@ private:
MSAA msaa;
ScreenSpaceAA screen_space_aa;
bool use_debanding;
Ref<ViewportTexture> default_texture;
Set<ViewportTexture *> viewport_textures;
@ -521,6 +522,9 @@ public:
void set_screen_space_aa(ScreenSpaceAA p_screen_space_aa);
ScreenSpaceAA get_screen_space_aa() const;
void set_use_debanding(bool p_use_debanding);
bool is_using_debanding() const;
Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;

View file

@ -304,7 +304,7 @@ public:
virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0;
virtual RID render_buffers_create() = 0;
virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa) = 0;
virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0;
virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0;
virtual bool screen_space_roughness_limiter_is_active() const = 0;

View file

@ -708,6 +708,7 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer,
tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
tonemap.push_constant.use_fxaa = p_settings.use_fxaa;
tonemap.push_constant.use_debanding = p_settings.use_debanding;
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;

View file

@ -184,7 +184,7 @@ class RasterizerEffectsRD {
float pixel_size[2];
uint32_t use_fxaa;
uint32_t pad;
uint32_t use_debanding;
};
/* tonemap actually writes to a framebuffer, which is
@ -628,6 +628,7 @@ public:
RID color_correction_texture;
bool use_fxaa = false;
bool use_debanding = false;
Vector2i texture_size;
};

View file

@ -5250,6 +5250,7 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu
tonemap.use_fxaa = true;
}
tonemap.use_debanding = rb->use_debanding;
tonemap.texture_size = Vector2i(rb->width, rb->height);
if (env) {
@ -5618,13 +5619,14 @@ float RasterizerSceneRD::render_buffers_get_volumetric_fog_detail_spread(RID p_r
return rb->volumetric_fog->spread;
}
void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa) {
void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
rb->width = p_width;
rb->height = p_height;
rb->render_target = p_render_target;
rb->msaa = p_msaa;
rb->screen_space_aa = p_screen_space_aa;
rb->use_debanding = p_use_debanding;
_free_render_buffer_data(rb);
{

View file

@ -788,6 +788,7 @@ private:
int width = 0, height = 0;
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
bool use_debanding = false;
RID render_target;
@ -1815,7 +1816,7 @@ public:
}
*/
RID render_buffers_create();
void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa);
void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding);
RID render_buffers_get_ao_texture(RID p_render_buffers);
RID render_buffers_get_back_buffer_texture(RID p_render_buffers);

View file

@ -46,7 +46,7 @@ layout(push_constant, binding = 1, std430) uniform Params {
vec2 pixel_size;
bool use_fxaa;
uint pad;
bool use_debanding;
}
params;
@ -299,6 +299,19 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
}
}
#define QUARTER_COLOR 1.0 / 1024.0
// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).
vec3 screen_space_dither(vec2 frag_coord) {
// Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR.
vec3 dither = vec3(dot(vec2(171.0, 231.0), frag_coord));
dither.rgb = fract(dither.rgb / vec3(103.0, 71.0, 97.0));
return dither.rgb / 255.0;
}
void main() {
vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb;
@ -322,6 +335,10 @@ void main() {
if (params.use_fxaa) {
color = do_fxaa(color, exposure, uv_interp);
}
if (params.use_debanding) {
// Debanding should be done before tonemapping.
color += screen_space_dither(gl_FragCoord.xy);
}
color = apply_tonemapping(color, params.white);
color = linear_to_srgb(color); // regular linear -> SRGB conversion

View file

@ -509,6 +509,7 @@ public:
BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
BIND2(viewport_set_msaa, RID, ViewportMSAA)
BIND2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
BIND2(viewport_set_use_debanding, RID, bool)
BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo)
BIND2(viewport_set_debug_draw, RID, ViewportDebugDraw)

View file

@ -115,7 +115,7 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
if ((scenario_draw_canvas_bg || can_draw_3d) && !p_viewport->render_buffers.is_valid()) {
//wants to draw 3D but there is no render buffer, create
p_viewport->render_buffers = RSG::scene_render->render_buffers_create();
RSG::scene_render->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa, p_viewport->screen_space_aa);
RSG::scene_render->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding);
}
RSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor);
@ -491,7 +491,7 @@ void RenderingServerViewport::viewport_set_size(RID p_viewport, int p_width, int
RSG::scene_render->free(viewport->render_buffers);
viewport->render_buffers = RID();
} else {
RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa);
RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding);
}
}
}
@ -704,7 +704,7 @@ void RenderingServerViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA
}
viewport->msaa = p_msaa;
if (viewport->render_buffers.is_valid()) {
RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa);
RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa, viewport->use_debanding);
}
}
@ -717,7 +717,20 @@ void RenderingServerViewport::viewport_set_screen_space_aa(RID p_viewport, RS::V
}
viewport->screen_space_aa = p_mode;
if (viewport->render_buffers.is_valid()) {
RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode);
RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode, viewport->use_debanding);
}
}
void RenderingServerViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) {
Viewport *viewport = viewport_owner.getornull(p_viewport);
ERR_FAIL_COND(!viewport);
if (viewport->use_debanding == p_use_debanding) {
return;
}
viewport->use_debanding = p_use_debanding;
if (viewport->render_buffers.is_valid()) {
RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, p_use_debanding);
}
}

View file

@ -59,6 +59,7 @@ public:
RS::ViewportMSAA msaa;
RS::ViewportScreenSpaceAA screen_space_aa;
bool use_debanding;
DisplayServer::WindowID viewport_to_screen;
Rect2 viewport_to_screen_rect;
@ -130,6 +131,7 @@ public:
debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
msaa = RS::VIEWPORT_MSAA_DISABLED;
screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
use_debanding = false;
for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_MAX; i++) {
render_info[i] = 0;
@ -206,6 +208,7 @@ public:
void viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa);
void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode);
void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding);
virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info);
virtual void viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw);

View file

@ -418,6 +418,7 @@ public:
FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
FUNC2(viewport_set_msaa, RID, ViewportMSAA)
FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
FUNC2(viewport_set_use_debanding, RID, bool)
//this passes directly to avoid stalling, but it's pretty dangerous, so don't call after freeing a viewport
virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfo p_info) {

View file

@ -1730,6 +1730,8 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size"), &RenderingServer::viewport_set_shadow_atlas_size);
ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &RenderingServer::viewport_set_shadow_atlas_quadrant_subdivision);
ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &RenderingServer::viewport_set_msaa);
ClassDB::bind_method(D_METHOD("viewport_set_use_debanding" "viewport", "enable"), &RenderingServer::viewport_set_use_debanding);
ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "info"), &RenderingServer::viewport_get_render_info);
ClassDB::bind_method(D_METHOD("viewport_set_debug_draw", "viewport", "draw"), &RenderingServer::viewport_set_debug_draw);

View file

@ -676,6 +676,8 @@ public:
virtual void viewport_set_screen_space_aa(RID p_viewport, ViewportScreenSpaceAA p_mode) = 0;
virtual void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) = 0;
enum ViewportRenderInfo {
VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME,
VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME,