diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 65f84a48e8b..6183ba8c26e 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -174,6 +174,18 @@ Comment: AccessKit
Copyright: 2023, The AccessKit Authors.
License: Expat
+Files: servers/rendering/renderer_rd/shaders/smaa_blending.glsl
+ servers/rendering/renderer_rd/shaders/smaa_weight_calculation.glsl
+ servers/rendering/renderer_rd/shaders/smaa_edge_detection.glsl
+ thirdparty/smaa/*
+Comment: Subpixel Morphological Antialiasing
+Copyright: 2013 Jorge Jimenez (jorge@iryoku.com)
+ 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
+ 2013 Belen Masia (bmasia@unizar.es)
+ 2013 Fernando Navarro (fernandn@microsoft.com)
+ 2013 Diego Gutierrez (diegog@unizar.es)
+License: Expat
+
Files: thirdparty/amd-fsr/*
Comment: AMD FidelityFX Super Resolution
Copyright: 2021, Advanced Micro Devices, Inc.
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index cef1253b6dd..0d69d908f99 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -2703,6 +2703,10 @@
[b]Note:[/b] Screen-space antialiasing is only supported in the Forward+ and Mobile rendering methods, not Compatibility.
[b]Note:[/b] This property is only read when the project starts. To set the screen-space antialiasing mode at runtime, set [member Viewport.screen_space_aa] on the root [Viewport] instead, or use [method RenderingServer.viewport_set_screen_space_aa].
+
+ Sets the sensitivity to edges when using SMAA for antialiasing. Lower values will catch more edges, at a potentially higher performance cost.
+ [b]Note:[/b] This property is only read when the project starts. There is currently no way to change this setting at run-time.
+
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].
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.
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index d87d2a48e6e..e1def286cd0 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -5141,7 +5141,10 @@
Use fast approximate antialiasing. FXAA is a popular screen-space antialiasing method, which is fast but will make the image look blurry, especially at lower resolutions. It can still work relatively well at large resolutions such as 1440p and 4K.
-
+
+ Use subpixel morphological antialiasing. SMAA may produce clearer results than FXAA, but at a slightly higher performance cost.
+
+
Represents the size of the [enum ViewportScreenSpaceAA] enum.
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 8f82d9f587b..c6e07123a51 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -598,7 +598,10 @@
Use fast approximate antialiasing. FXAA is a popular screen-space antialiasing method, which is fast but will make the image look blurry, especially at lower resolutions. It can still work relatively well at large resolutions such as 1440p and 4K.
-
+
+ Use subpixel morphological antialiasing. SMAA may produce clearer results than FXAA, but at a slightly higher performance cost.
+
+
Represents the size of the [enum ScreenSpaceAA] enum.
diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp
index 1cf180bc173..9befa050920 100644
--- a/editor/editor_property_name_processor.cpp
+++ b/editor/editor_property_name_processor.cpp
@@ -274,6 +274,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["sdk"] = "SDK";
capitalize_string_remaps["sec"] = "(sec)"; // Unit.
capitalize_string_remaps["signtool"] = "signtool";
+ capitalize_string_remaps["smaa"] = "SMAA";
capitalize_string_remaps["sms"] = "SMS";
capitalize_string_remaps["srgb"] = "sRGB";
capitalize_string_remaps["ssao"] = "SSAO";
diff --git a/pyproject.toml b/pyproject.toml
index 7a220d4c810..7c745d1eb9d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -89,4 +89,5 @@ ignore-words-list = [
"textin",
"thirdparty",
"vai",
+ "Masia",
]
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index ad62b72e54f..7789f5f7887 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -2060,7 +2060,7 @@ SceneTree::SceneTree() {
const bool use_hdr_2d = GLOBAL_GET("rendering/viewport/hdr_2d");
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);
+ const int ssaa_mode = GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast),SMAA (Average)"), 0);
root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
const bool use_taa = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/use_taa", false);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index c32afcee55a..f57cc3cfffe 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -5127,7 +5127,7 @@ void Viewport::_bind_methods() {
ADD_GROUP("Rendering", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa_2d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa_2d", "get_msaa_2d");
ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa_3d", "get_msaa_3d");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast),SMAA (Average)"), "set_screen_space_aa", "get_screen_space_aa");
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");
@@ -5216,6 +5216,7 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_DISABLED);
BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_FXAA);
+ BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_SMAA);
BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_MAX);
BIND_ENUM_CONSTANT(RENDER_INFO_OBJECTS_IN_FRAME);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 9744ff09e2d..03cc39ee92c 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -136,6 +136,7 @@ public:
enum ScreenSpaceAA {
SCREEN_SPACE_AA_DISABLED,
SCREEN_SPACE_AA_FXAA,
+ SCREEN_SPACE_AA_SMAA,
SCREEN_SPACE_AA_MAX
};
diff --git a/servers/rendering/renderer_rd/effects/SCsub b/servers/rendering/renderer_rd/effects/SCsub
index c60099512ec..7f85cfdfe3f 100644
--- a/servers/rendering/renderer_rd/effects/SCsub
+++ b/servers/rendering/renderer_rd/effects/SCsub
@@ -1,6 +1,8 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
+import methods
+
Import("env")
env_effects = env.Clone()
@@ -15,6 +17,44 @@ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_effects.Prepend(CPPEXTPATH=[thirdparty_dir])
+
+def areatex_builder(target, source, env):
+ buffer = methods.get_buffer(str(source[0]))
+
+ with methods.generated_wrapper(str(target[0])) as file:
+ file.write(f"""\
+#define AREATEX_WIDTH 160
+#define AREATEX_HEIGHT 560
+#define AREATEX_PITCH (AREATEX_WIDTH * 2)
+#define AREATEX_SIZE (AREATEX_HEIGHT * AREATEX_PITCH)
+
+inline constexpr const unsigned char area_tex_png[] = {{
+ {methods.format_buffer(buffer, 1)}
+}};
+""")
+
+
+env.CommandNoCache("smaa_area_tex.gen.h", "#thirdparty/smaa/AreaTex.png", env.Run(areatex_builder))
+
+
+def searchtex_builder(target, source, env):
+ buffer = methods.get_buffer(str(source[0]))
+
+ with methods.generated_wrapper(str(target[0])) as file:
+ file.write(f"""\
+#define SEARCHTEX_WIDTH 64
+#define SEARCHTEX_HEIGHT 16
+#define SEARCHTEX_PITCH SEARCHTEX_WIDTH
+#define SEARCHTEX_SIZE (SEARCHTEX_HEIGHT * SEARCHTEX_PITCH)
+
+inline constexpr const unsigned char search_tex_png[] = {{
+ {methods.format_buffer(buffer, 1)}
+}};
+""")
+
+
+env.CommandNoCache("smaa_search_tex.gen.h", "#thirdparty/smaa/SearchTex.png", env.Run(searchtex_builder))
+
# This flag doesn't actually control anything GCC specific in FSR2. It determines
# if symbols should be exported, which is not required for Godot.
env_effects.Append(CPPDEFINES=["FFX_GCC"])
diff --git a/servers/rendering/renderer_rd/effects/smaa.cpp b/servers/rendering/renderer_rd/effects/smaa.cpp
new file mode 100644
index 00000000000..93e50243a70
--- /dev/null
+++ b/servers/rendering/renderer_rd/effects/smaa.cpp
@@ -0,0 +1,268 @@
+/**************************************************************************/
+/* smaa.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "smaa.h"
+
+#include "core/config/project_settings.h"
+#include "core/io/image_loader.h"
+#include "servers/rendering/renderer_rd/effects/smaa_area_tex.gen.h"
+#include "servers/rendering/renderer_rd/effects/smaa_search_tex.gen.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
+#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
+
+using namespace RendererRD;
+
+SMAA::SMAA() {
+ {
+ // Initialize edge detection.
+ Vector smaa_modes;
+ smaa_modes.push_back("\n");
+ smaa.edge_shader.initialize(smaa_modes);
+
+ smaa.edge_shader_version = smaa.edge_shader.version_create();
+
+ RD::PipelineDepthStencilState stencil_state = RD::PipelineDepthStencilState();
+ stencil_state.enable_stencil = true;
+ stencil_state.back_op.reference = 0xff;
+ stencil_state.back_op.write_mask = 0xff;
+ stencil_state.back_op.compare_mask = 0xff;
+ stencil_state.back_op.pass = RD::STENCIL_OP_REPLACE;
+ stencil_state.front_op.reference = 0xff;
+ stencil_state.front_op.write_mask = 0xff;
+ stencil_state.front_op.compare_mask = 0xff;
+ stencil_state.front_op.pass = RD::STENCIL_OP_REPLACE;
+
+ for (int i = SMAA_EDGE_DETECTION_COLOR; i <= SMAA_EDGE_DETECTION_COLOR; i++) {
+ smaa.pipelines[i].setup(smaa.edge_shader.version_get_shader(smaa.edge_shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+
+ edge_detection_threshold = GLOBAL_GET("rendering/anti_aliasing/quality/smaa_edge_detection_threshold");
+ }
+
+ {
+ // Initialize weight calculation.
+ Vector smaa_modes;
+ smaa_modes.push_back("\n");
+ smaa.weight_shader.initialize(smaa_modes);
+
+ smaa.weight_shader_version = smaa.weight_shader.version_create();
+
+ RD::PipelineDepthStencilState stencil_state;
+ stencil_state.enable_stencil = true;
+ stencil_state.back_op.reference = 0xff;
+ stencil_state.back_op.compare_mask = 0xff;
+ stencil_state.back_op.compare = RD::COMPARE_OP_EQUAL;
+ stencil_state.front_op.reference = 0xff;
+ stencil_state.front_op.compare_mask = 0xff;
+ stencil_state.front_op.compare = RD::COMPARE_OP_EQUAL;
+
+ for (int i = SMAA_WEIGHT_FULL; i <= SMAA_WEIGHT_FULL; i++) {
+ smaa.pipelines[i].setup(smaa.weight_shader.version_get_shader(smaa.weight_shader_version, i - SMAA_WEIGHT_FULL), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ }
+
+ {
+ // Initialize color blending.
+ Vector smaa_modes;
+ smaa_modes.push_back("\n");
+ smaa.blend_shader.initialize(smaa_modes);
+
+ smaa.blend_shader_version = smaa.blend_shader.version_create();
+
+ for (int i = SMAA_BLENDING; i <= SMAA_BLENDING; i++) {
+ smaa.pipelines[i].setup(smaa.blend_shader.version_get_shader(smaa.blend_shader_version, i - SMAA_BLENDING), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ }
+
+ {
+ // Initialize SearchTex.
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8_UNORM;
+ tf.width = SEARCHTEX_WIDTH;
+ tf.height = SEARCHTEX_HEIGHT;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ smaa.search_tex = RD::get_singleton()->texture_create(tf, RD::TextureView(), Vector>{ Image(search_tex_png).get_data() });
+ }
+
+ {
+ // Initialize AreaTex.
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8G8_UNORM;
+ tf.width = AREATEX_WIDTH;
+ tf.height = AREATEX_HEIGHT;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ smaa.area_tex = RD::get_singleton()->texture_create(tf, RD::TextureView(), Vector>{ Image(area_tex_png).get_data() });
+ }
+
+ {
+ // Find smallest stencil texture format.
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D16_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ smaa.stencil_format = RD::DATA_FORMAT_D16_UNORM_S8_UINT;
+ } else if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ smaa.stencil_format = RD::DATA_FORMAT_D24_UNORM_S8_UINT;
+ } else {
+ smaa.stencil_format = RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+ }
+ }
+}
+
+SMAA::~SMAA() {
+ RD::get_singleton()->free(smaa.search_tex);
+ RD::get_singleton()->free(smaa.area_tex);
+
+ smaa.edge_shader.version_free(smaa.edge_shader_version);
+ smaa.weight_shader.version_free(smaa.weight_shader_version);
+ smaa.blend_shader.version_free(smaa.blend_shader_version);
+}
+
+void SMAA::allocate_render_targets(Ref p_render_buffers) {
+ Size2i full_size = p_render_buffers->get_internal_size();
+
+ // As we're not clearing these, and render buffers will return the cached texture if it already exists,
+ // we don't first check has_texture here.
+
+ p_render_buffers->create_texture(RB_SCOPE_SMAA, RB_EDGES, RD::DATA_FORMAT_R8G8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, full_size, 1, 1, true, true);
+ p_render_buffers->create_texture(RB_SCOPE_SMAA, RB_BLEND, RD::DATA_FORMAT_R8G8B8A8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, full_size, 1, 1, true, true);
+ p_render_buffers->create_texture(RB_SCOPE_SMAA, RB_STENCIL, smaa.stencil_format, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, full_size, 1, 1, true, true);
+}
+
+void SMAA::process(Ref p_render_buffers, RID p_source_color, RID p_dst_framebuffer) {
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ memset(&smaa.edge_push_constant, 0, sizeof(SMAAEdgePushConstant));
+ memset(&smaa.weight_push_constant, 0, sizeof(SMAAWeightPushConstant));
+ memset(&smaa.blend_push_constant, 0, sizeof(SMAABlendPushConstant));
+
+ Size2i size = p_render_buffers->get_internal_size();
+ Size2 inv_size = Size2(1.0f / (float)size.x, 1.0f / (float)size.y);
+
+ smaa.edge_push_constant.inv_size[0] = inv_size.x;
+ smaa.edge_push_constant.inv_size[1] = inv_size.y;
+ smaa.edge_push_constant.threshold = edge_detection_threshold;
+
+ smaa.weight_push_constant.inv_size[0] = inv_size.x;
+ smaa.weight_push_constant.inv_size[1] = inv_size.y;
+ smaa.weight_push_constant.size[0] = size.x;
+ smaa.weight_push_constant.size[1] = size.y;
+
+ smaa.blend_push_constant.inv_size[0] = inv_size.x;
+ smaa.blend_push_constant.inv_size[1] = inv_size.y;
+
+ RID linear_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ allocate_render_targets(p_render_buffers);
+ RID edges_tex = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_EDGES);
+ RID blend_tex = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_BLEND);
+ RID stencil_buffer = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_STENCIL);
+
+ RID edges_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(edges_tex, stencil_buffer);
+ RID blend_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(blend_tex, stencil_buffer);
+
+ RD::Uniform u_source_color;
+ u_source_color.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u_source_color.binding = 0;
+ u_source_color.append_id(linear_sampler);
+ u_source_color.append_id(p_source_color);
+
+ RD::Uniform u_edges_texture;
+ u_edges_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u_edges_texture.binding = 0;
+ u_edges_texture.append_id(linear_sampler);
+ u_edges_texture.append_id(edges_tex);
+
+ RD::Uniform u_area_texture;
+ u_area_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u_area_texture.binding = 0;
+ u_area_texture.append_id(linear_sampler);
+ u_area_texture.append_id(smaa.area_tex);
+
+ RD::Uniform u_search_texture;
+ u_search_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u_search_texture.binding = 1;
+ u_search_texture.append_id(linear_sampler);
+ u_search_texture.append_id(smaa.search_tex);
+
+ RD::Uniform u_blend_texture;
+ u_blend_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u_blend_texture.binding = 0;
+ u_blend_texture.append_id(linear_sampler);
+ u_blend_texture.append_id(blend_tex);
+
+ {
+ int mode = SMAA_EDGE_DETECTION_COLOR;
+ RID shader = smaa.edge_shader.version_get_shader(smaa.edge_shader_version, mode);
+ ERR_FAIL_COND(shader.is_null());
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(edges_framebuffer, RD::DRAW_CLEAR_COLOR_0 | RD::DRAW_CLEAR_STENCIL, Vector({ Color(0, 0, 0, 0) }), 1.0f, 0);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, smaa.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(edges_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass()));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.edge_push_constant, sizeof(SMAAEdgePushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ {
+ int mode = SMAA_WEIGHT_FULL;
+ RID shader = smaa.weight_shader.version_get_shader(smaa.weight_shader_version, mode - SMAA_WEIGHT_FULL);
+ ERR_FAIL_COND(shader.is_null());
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(blend_framebuffer, RD::DRAW_CLEAR_COLOR_0, Vector({ Color(0, 0, 0, 0) }));
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, smaa.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(blend_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass()));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_edges_texture), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_area_texture, u_search_texture), 1);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.weight_push_constant, sizeof(SMAAWeightPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ {
+ int mode = SMAA_BLENDING;
+ RID shader = smaa.blend_shader.version_get_shader(smaa.blend_shader_version, mode - SMAA_BLENDING);
+ ERR_FAIL_COND(shader.is_null());
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::DRAW_IGNORE_COLOR_0);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, smaa.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass()));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_blend_texture), 1);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.blend_push_constant, sizeof(SMAABlendPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
+ RD::get_singleton()->draw_list_end();
+ }
+}
diff --git a/servers/rendering/renderer_rd/effects/smaa.h b/servers/rendering/renderer_rd/effects/smaa.h
new file mode 100644
index 00000000000..589b666904c
--- /dev/null
+++ b/servers/rendering/renderer_rd/effects/smaa.h
@@ -0,0 +1,108 @@
+/**************************************************************************/
+/* smaa.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#pragma once
+
+#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
+#include "servers/rendering/renderer_rd/shaders/effects/smaa_blending.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/smaa_edge_detection.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/smaa_weight_calculation.glsl.gen.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
+#include "servers/rendering/renderer_scene_render.h"
+
+#include "servers/rendering_server.h"
+
+#define RB_SCOPE_SMAA SNAME("rb_smaa")
+
+#define RB_EDGES SNAME("edges")
+#define RB_BLEND SNAME("blend")
+#define RB_STENCIL SNAME("stencil")
+
+namespace RendererRD {
+
+class SMAA {
+private:
+ enum SMAAMode {
+ SMAA_EDGE_DETECTION_COLOR,
+ SMAA_WEIGHT_FULL,
+ SMAA_BLENDING,
+ SMAA_MAX,
+ };
+
+ struct SMAAEdgePushConstant {
+ float inv_size[2];
+ float threshold;
+ float reserved;
+ };
+
+ struct SMAAWeightPushConstant {
+ float inv_size[2];
+ uint32_t size[2];
+
+ float subsample_indices[4];
+ };
+
+ struct SMAABlendPushConstant {
+ float inv_size[2];
+ float reserved[2];
+ };
+
+ struct SMAAEffect {
+ SMAAEdgePushConstant edge_push_constant;
+ SmaaEdgeDetectionShaderRD edge_shader;
+ RID edge_shader_version;
+
+ SMAAWeightPushConstant weight_push_constant;
+ SmaaWeightCalculationShaderRD weight_shader;
+ RID weight_shader_version;
+
+ SMAABlendPushConstant blend_push_constant;
+ SmaaBlendingShaderRD blend_shader;
+ RID blend_shader_version;
+
+ RID search_tex;
+ RID area_tex;
+
+ RD::DataFormat stencil_format;
+
+ PipelineCacheRD pipelines[SMAA_MAX];
+ } smaa;
+
+ float edge_detection_threshold;
+
+public:
+ SMAA();
+ ~SMAA();
+
+ void allocate_render_targets(Ref p_render_buffers);
+ void process(Ref p_render_buffers, RID p_source_color, RID p_dst_framebuffer);
+};
+
+} // namespace RendererRD
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 d37a59ab140..37b4c1184a6 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -883,8 +883,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
using_subpass_post_process = false;
}
- if (rb->get_screen_space_aa() == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
- // Can't do blit subpass because we're using FXAA.
+ if (rb->get_screen_space_aa() != RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED) {
+ // Can't do blit subpass because we're using screen space AA.
using_subpass_post_process = false;
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index b8d2d66f018..2a037d241e2 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -470,6 +470,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
}
}
+ bool use_smaa = smaa && rb->get_screen_space_aa() == RS::VIEWPORT_SCREEN_SPACE_AA_SMAA;
+
RID render_target = rb->get_render_target();
RID color_texture = use_upscaled_texture ? rb->get_upscaled_texture() : rb->get_internal_texture();
Size2i color_size = use_upscaled_texture ? target_size : rb->get_internal_size();
@@ -682,8 +684,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(render_target);
RID dest_fb;
- if (spatial_upscaler != nullptr) {
- // If we use a spatial upscaler to upscale we need to write our result into an intermediate buffer.
+ if (spatial_upscaler != nullptr || use_smaa) {
+ // If we use a spatial upscaler to upscale or SMAA to antialias we need to write our result into an intermediate buffer.
// Note that this is cached so we only create the texture the first time.
RID dest_texture = rb->create_texture(SNAME("Tonemapper"), SNAME("destination"), _render_buffers_get_color_format(), RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, Size2i(), 0, 1, true, true);
dest_fb = FramebufferCacheRD::get_singleton()->get_cache(dest_texture);
@@ -705,13 +707,61 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
RD::get_singleton()->draw_command_end_label();
}
+ if (use_smaa) {
+ RENDER_TIMESTAMP("SMAA");
+ RD::get_singleton()->draw_command_begin_label("SMAA");
+
+ RID dest_fb;
+ if (spatial_upscaler) {
+ rb->create_texture(SNAME("SMAA"), SNAME("destination"), _render_buffers_get_color_format(), RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, Size2i(), 0, 1, true, true);
+ }
+ if (rb->get_view_count() > 1) {
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ RID source_texture = rb->get_texture_slice(SNAME("Tonemapper"), SNAME("destination"), v, 0);
+
+ RID dest_texture;
+ if (spatial_upscaler) {
+ dest_texture = rb->get_texture_slice(SNAME("SMAA"), SNAME("destination"), v, 0);
+ } else {
+ dest_texture = texture_storage->render_target_get_rd_texture_slice(render_target, v);
+ }
+ dest_fb = FramebufferCacheRD::get_singleton()->get_cache(dest_texture);
+
+ smaa->process(rb, source_texture, dest_fb);
+ }
+ } else {
+ RID source_texture = rb->get_texture(SNAME("Tonemapper"), SNAME("destination"));
+
+ if (spatial_upscaler) {
+ RID dest_texture = rb->create_texture(SNAME("SMAA"), SNAME("destination"), _render_buffers_get_color_format(), RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT, RD::TEXTURE_SAMPLES_1, Size2i(), 0, 1, true, true);
+ dest_fb = FramebufferCacheRD::get_singleton()->get_cache(dest_texture);
+ } else {
+ if (dest_is_msaa_2d) {
+ dest_fb = FramebufferCacheRD::get_singleton()->get_cache(texture_storage->render_target_get_rd_texture_msaa(render_target));
+ texture_storage->render_target_set_msaa_needs_resolve(render_target, true); // Make sure this gets resolved.
+ } else {
+ dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target);
+ }
+ }
+
+ smaa->process(rb, source_texture, dest_fb);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+ }
+
if (rb.is_valid() && spatial_upscaler) {
spatial_upscaler->ensure_context(rb);
RD::get_singleton()->draw_command_begin_label(spatial_upscaler->get_label());
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
- RID source_texture = rb->get_texture_slice(SNAME("Tonemapper"), SNAME("destination"), v, 0);
+ RID source_texture;
+ if (use_smaa) {
+ source_texture = rb->get_texture_slice(SNAME("SMAA"), SNAME("destination"), v, 0);
+ } else {
+ source_texture = rb->get_texture_slice(SNAME("Tonemapper"), SNAME("destination"), v, 0);
+ }
RID dest_texture = texture_storage->render_target_get_rd_texture_slice(render_target, v);
spatial_upscaler->process(rb, source_texture, dest_texture);
@@ -1553,6 +1603,7 @@ void RendererSceneRenderRD::init() {
copy_effects = memnew(RendererRD::CopyEffects(!can_use_storage));
debug_effects = memnew(RendererRD::DebugEffects);
luminance = memnew(RendererRD::Luminance(!can_use_storage));
+ smaa = memnew(RendererRD::SMAA);
tone_mapper = memnew(RendererRD::ToneMapper);
if (can_use_vrs) {
vrs = memnew(RendererRD::VRS);
@@ -1582,6 +1633,9 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
if (luminance) {
memdelete(luminance);
}
+ if (smaa) {
+ memdelete(smaa);
+ }
if (tone_mapper) {
memdelete(tone_mapper);
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 95e500679b5..0043901946d 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -39,6 +39,7 @@
#ifdef METAL_ENABLED
#include "servers/rendering/renderer_rd/effects/metal_fx.h"
#endif
+#include "servers/rendering/renderer_rd/effects/smaa.h"
#include "servers/rendering/renderer_rd/effects/tone_mapper.h"
#include "servers/rendering/renderer_rd/effects/vrs.h"
#include "servers/rendering/renderer_rd/environment/gi.h"
@@ -60,6 +61,7 @@ protected:
RendererRD::CopyEffects *copy_effects = nullptr;
RendererRD::DebugEffects *debug_effects = nullptr;
RendererRD::Luminance *luminance = nullptr;
+ RendererRD::SMAA *smaa = nullptr;
RendererRD::ToneMapper *tone_mapper = nullptr;
RendererRD::FSR *fsr = nullptr;
RendererRD::VRS *vrs = nullptr;
diff --git a/servers/rendering/renderer_rd/shaders/effects/smaa_blending.glsl b/servers/rendering/renderer_rd/shaders/effects/smaa_blending.glsl
new file mode 100644
index 00000000000..f8ef9ea71ed
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/smaa_blending.glsl
@@ -0,0 +1,123 @@
+/**
+ * Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com)
+ * Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
+ * Copyright (C) 2013 Belen Masia (bmasia@unizar.es)
+ * Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com)
+ * Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to
+ * do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software. As clarification, there
+ * is no requirement that the copyright notice and permission be included in
+ * binary distributions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#[vertex]
+#version 450
+
+layout(location = 0) out vec2 tex_coord;
+layout(location = 1) out vec4 offset;
+
+layout(push_constant, std430) uniform Params {
+ vec2 inv_size;
+ vec2 reserved;
+}
+params;
+
+void main() {
+ vec2 vertex_base;
+ if (gl_VertexIndex == 0) {
+ vertex_base = vec2(-1.0, -1.0);
+ } else if (gl_VertexIndex == 1) {
+ vertex_base = vec2(-1.0, 3.0);
+ } else {
+ vertex_base = vec2(3.0, -1.0);
+ }
+ gl_Position = vec4(vertex_base, 0.0, 1.0);
+ tex_coord = clamp(vertex_base, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
+ offset = fma(params.inv_size.xyxy, vec4(1.0, 0.0, 0.0, 1.0), tex_coord.xyxy);
+}
+
+#[fragment]
+#version 450
+
+layout(location = 0) in vec2 tex_coord;
+layout(location = 1) in vec4 offset;
+layout(set = 0, binding = 0) uniform sampler2D color_tex;
+layout(set = 1, binding = 0) uniform sampler2D blend_tex;
+
+layout(location = 0) out vec4 out_color;
+
+layout(push_constant, std430) uniform Params {
+ vec2 inv_size;
+ vec2 reserved;
+}
+params;
+
+#define textureLinear(tex, uv) srgb_to_linear(textureLod(tex, uv, 0.0).rgb)
+
+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)));
+}
+
+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)));
+}
+
+void SMAAMovc(bvec2 cond, inout vec2 variable, vec2 value) {
+ if (cond.x) {
+ variable.x = value.x;
+ }
+ if (cond.y) {
+ variable.y = value.y;
+ }
+}
+
+void SMAAMovc(bvec4 cond, inout vec4 variable, vec4 value) {
+ SMAAMovc(cond.xy, variable.xy, value.xy);
+ SMAAMovc(cond.zw, variable.zw, value.zw);
+}
+
+void main() {
+ vec4 a;
+ a.x = texture(blend_tex, offset.xy).a;
+ a.y = texture(blend_tex, offset.zw).g;
+ a.wz = texture(blend_tex, tex_coord).xz;
+
+ if (dot(a, vec4(1.0, 1.0, 1.0, 1.0)) < 1e-5) {
+ out_color = textureLod(color_tex, tex_coord, 0.0);
+ } else {
+ bool h = max(a.x, a.z) > max(a.y, a.w);
+
+ vec4 blending_offset = vec4(0.0, a.y, 0.0, a.w);
+ vec2 blending_weight = a.yw;
+
+ SMAAMovc(bvec4(h, h, h, h), blending_offset, vec4(a.x, 0.0, a.z, 0.0));
+ SMAAMovc(bvec2(h, h), blending_weight, a.xz);
+ blending_weight /= dot(blending_weight, vec2(1.0, 1.0));
+
+ vec4 blending_coord = fma(blending_offset, vec4(params.inv_size.xy, -params.inv_size.xy), tex_coord.xyxy);
+
+ out_color.rgb = blending_weight.x * textureLinear(color_tex, blending_coord.xy);
+ out_color.rgb += blending_weight.y * textureLinear(color_tex, blending_coord.zw);
+ out_color.rgb = linear_to_srgb(out_color.rgb);
+ out_color.a = texture(color_tex, tex_coord).a;
+ }
+}
diff --git a/servers/rendering/renderer_rd/shaders/effects/smaa_edge_detection.glsl b/servers/rendering/renderer_rd/shaders/effects/smaa_edge_detection.glsl
new file mode 100644
index 00000000000..50fa81911a1
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/smaa_edge_detection.glsl
@@ -0,0 +1,120 @@
+/**
+ * Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com)
+ * Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
+ * Copyright (C) 2013 Belen Masia (bmasia@unizar.es)
+ * Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com)
+ * Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to
+ * do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software. As clarification, there
+ * is no requirement that the copyright notice and permission be included in
+ * binary distributions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#[vertex]
+#version 450
+
+layout(location = 0) out vec2 tex_coord;
+layout(location = 1) out vec4 offset[3];
+
+layout(push_constant, std430) uniform Params {
+ vec2 inv_size;
+ float threshold;
+ float reserved;
+}
+params;
+
+void main() {
+ vec2 vertex_base;
+ if (gl_VertexIndex == 0) {
+ vertex_base = vec2(-1.0, -1.0);
+ } else if (gl_VertexIndex == 1) {
+ vertex_base = vec2(-1.0, 3.0);
+ } else {
+ vertex_base = vec2(3.0, -1.0);
+ }
+ gl_Position = vec4(vertex_base, 0.0, 1.0);
+ tex_coord = clamp(vertex_base, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
+
+ offset[0] = fma(params.inv_size.xyxy, vec4(-1.0, 0.0, 0.0, -1.0), tex_coord.xyxy);
+ offset[1] = fma(params.inv_size.xyxy, vec4(1.0, 0.0, 0.0, 1.0), tex_coord.xyxy);
+ offset[2] = fma(params.inv_size.xyxy, vec4(-2.0, 0.0, 0.0, -2.0), tex_coord.xyxy);
+}
+
+#[fragment]
+#version 450
+
+layout(location = 0) in vec2 tex_coord;
+layout(location = 1) in vec4 offset[3];
+
+layout(set = 0, binding = 0) uniform sampler2D color_tex;
+
+layout(location = 0) out vec2 edges;
+
+layout(push_constant, std430) uniform Params {
+ vec2 inv_size;
+ float threshold;
+ float reserved;
+}
+params;
+
+#define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 2.0
+
+void main() {
+ vec2 threshold = vec2(params.threshold);
+
+ vec4 delta;
+ vec3 C = texture(color_tex, tex_coord).rgb;
+
+ vec3 Cleft = texture(color_tex, offset[0].xy).rgb;
+ vec3 t = abs(C - Cleft);
+ delta.x = max(max(t.r, t.g), t.b);
+
+ vec3 Ctop = texture(color_tex, offset[0].zw).rgb;
+ t = abs(C - Ctop);
+ delta.y = max(max(t.r, t.g), t.b);
+
+ edges = step(threshold, delta.xy);
+
+ if (dot(edges, vec2(1.0, 1.0)) == 0.0) {
+ discard;
+ }
+
+ vec3 Cright = texture(color_tex, offset[1].xy).rgb;
+ t = abs(C - Cright);
+ delta.z = max(max(t.r, t.g), t.b);
+
+ vec3 Cbottom = texture(color_tex, offset[1].zw).rgb;
+ t = abs(C - Cbottom);
+ delta.w = max(max(t.r, t.g), t.b);
+
+ vec2 max_delta = max(delta.xy, delta.zw);
+
+ vec3 Cleftleft = texture(color_tex, offset[2].xy).rgb;
+ t = abs(Cleft - Cleftleft);
+ delta.z = max(max(t.r, t.g), t.b);
+
+ vec3 Ctoptop = texture(color_tex, offset[2].zw).rgb;
+ t = abs(Ctop - Ctoptop);
+ delta.w = max(max(t.r, t.g), t.b);
+
+ max_delta = max(max_delta.xy, delta.zw);
+ float final_delta = max(max_delta.x, max_delta.y);
+
+ edges.xy *= step(final_delta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy);
+}
diff --git a/servers/rendering/renderer_rd/shaders/effects/smaa_weight_calculation.glsl b/servers/rendering/renderer_rd/shaders/effects/smaa_weight_calculation.glsl
new file mode 100644
index 00000000000..b92ea29402c
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/effects/smaa_weight_calculation.glsl
@@ -0,0 +1,376 @@
+/**
+ * Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com)
+ * Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
+ * Copyright (C) 2013 Belen Masia (bmasia@unizar.es)
+ * Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com)
+ * Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to
+ * do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software. As clarification, there
+ * is no requirement that the copyright notice and permission be included in
+ * binary distributions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#[vertex]
+#version 450
+
+layout(location = 0) out vec2 tex_coord;
+layout(location = 1) out vec2 pix_coord;
+layout(location = 2) out vec4 offset[3];
+
+layout(push_constant, std430) uniform Params {
+ vec2 inv_size;
+ ivec2 size;
+
+ vec4 subsample_indices;
+}
+params;
+
+#define SMAA_MAX_SEARCH_STEPS 32
+
+void main() {
+ vec2 vertex_base;
+ if (gl_VertexIndex == 0) {
+ vertex_base = vec2(-1.0, -1.0);
+ } else if (gl_VertexIndex == 1) {
+ vertex_base = vec2(-1.0, 3.0);
+ } else {
+ vertex_base = vec2(3.0, -1.0);
+ }
+ gl_Position = vec4(vertex_base, 0.0, 1.0);
+ tex_coord = clamp(vertex_base, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
+ pix_coord = tex_coord * params.size.xy;
+
+ offset[0] = fma(params.inv_size.xyxy, vec4(-0.25, -0.125, 1.25, -0.125), tex_coord.xyxy);
+ offset[1] = fma(params.inv_size.xyxy, vec4(-0.125, -0.25, -0.125, 1.25), tex_coord.xyxy);
+ offset[2] = fma(params.inv_size.xxyy,
+ vec4(-2.0, 2.0, -2.0, 2.0) * SMAA_MAX_SEARCH_STEPS,
+ vec4(offset[0].xz, offset[1].yw));
+}
+
+#[fragment]
+#version 450
+
+layout(location = 0) in vec2 tex_coord;
+layout(location = 1) in vec2 pix_coord;
+layout(location = 2) in vec4 offset[3];
+layout(set = 0, binding = 0) uniform sampler2D edges_tex;
+layout(set = 1, binding = 0) uniform sampler2D area_tex;
+layout(set = 1, binding = 1) uniform sampler2D search_tex;
+layout(location = 0) out vec4 weights;
+
+layout(push_constant, std430) uniform Params {
+ vec2 inv_size;
+ ivec2 size;
+
+ vec4 subsample_indices;
+}
+params;
+
+#define SMAA_MAX_SEARCH_STEPS 32
+#define SMAA_MAX_SEARCH_STEPS_DIAG 16
+#define SMAA_CORNER_ROUNDING 25
+
+#ifndef SMAA_AREATEX_SELECT
+#define SMAA_AREATEX_SELECT(sample) sample.rg
+#endif
+
+#ifndef SMAA_SEARCHTEX_SELECT
+#define SMAA_SEARCHTEX_SELECT(sample) sample.r
+#endif
+
+#define SMAA_AREATEX_MAX_DISTANCE 16
+#define SMAA_AREATEX_MAX_DISTANCE_DIAG 20
+#define SMAA_AREATEX_PIXEL_SIZE (1.0 / vec2(160.0, 560.0))
+#define SMAA_AREATEX_SUBTEX_SIZE (1.0 / 7.0)
+#define SMAA_SEARCHTEX_SIZE vec2(66.0, 33.0)
+#define SMAA_SEARCHTEX_PACKED_SIZE vec2(64.0, 16.0)
+#define SMAA_CORNER_ROUNDING_NORM (float(SMAA_CORNER_ROUNDING) / 100.0)
+
+void SMAAMovc(bvec2 cond, inout vec2 variable, vec2 value) {
+ if (cond.x) {
+ variable.x = value.x;
+ }
+ if (cond.y) {
+ variable.y = value.y;
+ }
+}
+
+vec2 SMAADecodeDiagBilinearAccess(vec2 e) {
+ e.r = e.r * abs(5.0 * e.r - 5.0 * 0.75);
+ return round(e);
+}
+
+vec4 SMAADecodeDiagBilinearAccess(vec4 e) {
+ e.rb = e.rb * abs(5.0 * e.rb - 5.0 * 0.75);
+ return round(e);
+}
+
+vec2 SMAASearchDiag1(vec2 tex_coord, vec2 dir, out vec2 e) {
+ vec4 coord = vec4(tex_coord, -1.0, 1.0);
+ vec3 t = vec3(params.inv_size.xy, 1.0);
+ while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) &&
+ coord.w > 0.9) {
+ coord.xyz = fma(t, vec3(dir, 1.0), coord.xyz);
+ e = textureLod(edges_tex, coord.xy, 0.0).rg;
+ coord.w = dot(e, vec2(0.5, 0.5));
+ }
+ return coord.zw;
+}
+
+vec2 SMAASearchDiag2(vec2 tex_coord, vec2 dir, out vec2 e) {
+ vec4 coord = vec4(tex_coord, -1.0, 1.0);
+ coord.x += 0.25 * params.inv_size.x;
+ vec3 t = vec3(params.inv_size.xy, 1.0);
+ while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) &&
+ coord.w > 0.9) {
+ coord.xyz = fma(t, vec3(dir, 1.0), coord.xyz);
+
+ e = textureLod(edges_tex, coord.xy, 0.0).rg;
+ e = SMAADecodeDiagBilinearAccess(e);
+
+ coord.w = dot(e, vec2(0.5, 0.5));
+ }
+ return coord.zw;
+}
+
+vec2 SMAAAreaDiag(vec2 dist, vec2 e, float offset) {
+ vec2 coord = fma(vec2(SMAA_AREATEX_MAX_DISTANCE_DIAG, SMAA_AREATEX_MAX_DISTANCE_DIAG), e, dist);
+
+ coord = fma(SMAA_AREATEX_PIXEL_SIZE, coord, 0.5 * SMAA_AREATEX_PIXEL_SIZE);
+
+ coord.x += 0.5;
+
+ coord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;
+
+ return SMAA_AREATEX_SELECT(textureLod(area_tex, coord, 0.0));
+}
+
+vec2 SMAACalculateDiagWeights(vec2 tex_coord, vec2 e, vec4 subsample_indices) {
+ vec2 weights = vec2(0.0, 0.0);
+
+ vec4 d;
+ vec2 end;
+ if (e.r > 0.0) {
+ d.xz = SMAASearchDiag1(tex_coord, vec2(-1.0, 1.0), end);
+ d.x += float(end.y > 0.9);
+ } else {
+ d.xz = vec2(0.0, 0.0);
+ }
+ d.yw = SMAASearchDiag1(tex_coord, vec2(1.0, -1.0), end);
+
+ if (d.x + d.y > 2.0) {
+ vec4 coords = fma(vec4(-d.x + 0.25, d.x, d.y, -d.y - 0.25), params.inv_size.xyxy, tex_coord.xyxy);
+ vec4 c;
+ c.xy = textureLodOffset(edges_tex, coords.xy, 0.0, ivec2(-1, 0)).rg;
+ c.zw = textureLodOffset(edges_tex, coords.zw, 0.0, ivec2(1, 0)).rg;
+ c.yxwz = SMAADecodeDiagBilinearAccess(c.xyzw);
+
+ vec2 cc = fma(vec2(2.0, 2.0), c.xz, c.yw);
+
+ SMAAMovc(bvec2(step(0.9, d.zw)), cc, vec2(0.0, 0.0));
+
+ weights += SMAAAreaDiag(d.xy, cc, subsample_indices.z);
+ }
+
+ d.xz = SMAASearchDiag2(tex_coord, vec2(-1.0, -1.0), end);
+ if (textureLodOffset(edges_tex, tex_coord, 0.0, ivec2(1, 0)).r > 0.0) {
+ d.yw = SMAASearchDiag2(tex_coord, vec2(1.0, 1.0), end);
+ d.y += float(end.y > 0.9);
+ } else {
+ d.yw = vec2(0.0, 0.0);
+ }
+
+ if (d.x + d.y > 2.0) {
+ vec4 coords = fma(vec4(-d.x, -d.x, d.y, d.y), params.inv_size.xyxy, tex_coord.xyxy);
+ vec4 c;
+ c.x = textureLodOffset(edges_tex, coords.xy, 0.0, ivec2(-1, 0)).g;
+ c.y = textureLodOffset(edges_tex, coords.xy, 0.0, ivec2(0, -1)).r;
+ c.zw = textureLodOffset(edges_tex, coords.zw, 0.0, ivec2(1, 0)).gr;
+ vec2 cc = fma(vec2(2.0, 2.0), c.xz, c.yw);
+
+ SMAAMovc(bvec2(step(0.9, d.zw)), cc, vec2(0.0, 0.0));
+
+ weights += SMAAAreaDiag(d.xy, cc, subsample_indices.w).gr;
+ }
+
+ return weights;
+}
+
+float SMAASearchLength(vec2 e, float offset) {
+ vec2 scale = SMAA_SEARCHTEX_SIZE * vec2(0.5, -1.0);
+ vec2 bias = SMAA_SEARCHTEX_SIZE * vec2(offset, 1.0);
+
+ scale += vec2(-1.0, 1.0);
+ bias += vec2(0.5, -0.5);
+
+ scale *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE;
+ bias *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE;
+
+ return SMAA_SEARCHTEX_SELECT(textureLod(search_tex, fma(scale, e, bias), 0.0));
+}
+
+float SMAASearchXLeft(vec2 tex_coord, float end) {
+ vec2 e = vec2(0.0, 1.0);
+ while (tex_coord.x > end &&
+ e.g > 0.8281 &&
+ e.r == 0.0) {
+ e = textureLod(edges_tex, tex_coord, 0.0).rg;
+ tex_coord = fma(-vec2(2.0, 0.0), params.inv_size.xy, tex_coord);
+ }
+
+ float offset = fma(-(255.0 / 127.0), SMAASearchLength(e, 0.0), 3.25);
+ return fma(params.inv_size.x, offset, tex_coord.x);
+}
+
+float SMAASearchXRight(vec2 tex_coord, float end) {
+ vec2 e = vec2(0.0, 1.0);
+ while (tex_coord.x < end &&
+ e.g > 0.8281 &&
+ e.r == 0.0) {
+ e = textureLod(edges_tex, tex_coord, 0.0).rg;
+ tex_coord = fma(vec2(2.0, 0.0), params.inv_size.xy, tex_coord);
+ }
+
+ float offset = fma(-(255.0 / 127.0), SMAASearchLength(e, 0.5), 3.25);
+ return fma(-params.inv_size.x, offset, tex_coord.x);
+}
+
+float SMAASearchYUp(vec2 tex_coord, float end) {
+ vec2 e = vec2(1.0, 0.0);
+ while (tex_coord.y > end &&
+ e.r > 0.8281 &&
+ e.g == 0.0) {
+ e = textureLod(edges_tex, tex_coord, 0.0).rg;
+ tex_coord = fma(-vec2(0.0, 2.0), params.inv_size.xy, tex_coord);
+ }
+
+ float offset = fma(-(255.0 / 127.0), SMAASearchLength(e.gr, 0.0), 3.25);
+ return fma(params.inv_size.y, offset, tex_coord.y);
+}
+
+float SMAASearchYDown(vec2 tex_coord, float end) {
+ vec2 e = vec2(1.0, 0.0);
+ while (tex_coord.y < end &&
+ e.r > 0.8281 &&
+ e.g == 0.0) {
+ e = textureLod(edges_tex, tex_coord, 0.0).rg;
+ tex_coord = fma(vec2(0.0, 2.0), params.inv_size.xy, tex_coord);
+ }
+
+ float offset = fma(-(255.0 / 127.0), SMAASearchLength(e.gr, 0.5), 3.25);
+ return fma(-params.inv_size.y, offset, tex_coord.y);
+}
+
+vec2 SMAAArea(vec2 dist, float e1, float e2, float offset) {
+ vec2 tex_coord = fma(vec2(SMAA_AREATEX_MAX_DISTANCE, SMAA_AREATEX_MAX_DISTANCE), round(4.0 * vec2(e1, e2)), dist);
+
+ tex_coord = fma(SMAA_AREATEX_PIXEL_SIZE, tex_coord, 0.5 * SMAA_AREATEX_PIXEL_SIZE);
+
+ tex_coord.y = fma(SMAA_AREATEX_SUBTEX_SIZE, offset, tex_coord.y);
+
+ return SMAA_AREATEX_SELECT(textureLod(area_tex, tex_coord, 0.0));
+}
+
+void SMAADetectHorizontalCornerPattern(inout vec2 weights, vec4 coord, vec2 d) {
+ vec2 left_right = step(d.xy, d.yx);
+ vec2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * left_right;
+
+ rounding /= left_right.x + left_right.y;
+
+ vec2 factor = vec2(1.0, 1.0);
+ factor.x -= rounding.x * textureLodOffset(edges_tex, coord.xy, 0.0, ivec2(0, 1)).r;
+ factor.x -= rounding.y * textureLodOffset(edges_tex, coord.zw, 0.0, ivec2(1, 1)).r;
+ factor.y -= rounding.x * textureLodOffset(edges_tex, coord.xy, 0.0, ivec2(0, -2)).r;
+ factor.y -= rounding.y * textureLodOffset(edges_tex, coord.zw, 0.0, ivec2(1, -2)).r;
+
+ weights *= clamp(factor, 0.0, 1.0);
+}
+
+void SMAADetectVerticalCornerPattern(inout vec2 weights, vec4 coord, vec2 d) {
+ vec2 left_right = step(d.xy, d.yx);
+ vec2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * left_right;
+
+ rounding /= left_right.x + left_right.y;
+
+ vec2 factor = vec2(1.0, 1.0);
+ factor.x -= rounding.x * textureLodOffset(edges_tex, coord.xy, 0.0, ivec2(1, 0)).g;
+ factor.x -= rounding.y * textureLodOffset(edges_tex, coord.zw, 0.0, ivec2(1, 1)).g;
+ factor.y -= rounding.x * textureLodOffset(edges_tex, coord.xy, 0.0, ivec2(-2, 0)).g;
+ factor.y -= rounding.y * textureLodOffset(edges_tex, coord.zw, 0.0, ivec2(-2, 1)).g;
+
+ weights *= clamp(factor, 0.0, 1.0);
+}
+
+void main() {
+ weights = vec4(0.0, 0.0, 0.0, 0.0);
+ vec2 e = textureLod(edges_tex, tex_coord, 0.0).rg;
+
+ if (e.g > 0.0) { // Edge at north.
+ weights.rg = SMAACalculateDiagWeights(tex_coord, e, params.subsample_indices);
+ if (weights.r == -weights.g) {
+ vec2 d;
+ vec3 coords;
+ coords.x = SMAASearchXLeft(offset[0].xy, offset[2].x);
+ coords.y = offset[1].y;
+ d.x = coords.x;
+
+ float e1 = textureLod(edges_tex, coords.xy, 0.0).r;
+
+ coords.z = SMAASearchXRight(offset[0].zw, offset[2].y);
+ d.y = coords.z;
+
+ d = abs(round(fma(params.size.xx, d, -pix_coord.xx)));
+
+ vec2 sqrt_d = sqrt(d);
+
+ float e2 = textureLodOffset(edges_tex, coords.zy, 0.0, ivec2(1, 0)).r;
+
+ weights.rg = SMAAArea(sqrt_d, e1, e2, params.subsample_indices.y);
+
+ coords.y = tex_coord.y;
+ SMAADetectHorizontalCornerPattern(weights.rg, coords.xyzy, d);
+ } else {
+ e.r = 0.0;
+ }
+ }
+
+ if (e.r > 0.0) { // Edge at west.
+ vec2 d;
+ vec3 coords;
+ coords.y = SMAASearchYUp(offset[1].xy, offset[2].z);
+ coords.x = offset[0].x;
+ d.x = coords.y;
+
+ float e1 = textureLod(edges_tex, coords.xy, 0.0).g;
+
+ coords.z = SMAASearchYDown(offset[1].zw, offset[2].w);
+ d.y = coords.z;
+
+ d = abs(round(fma(params.size.yy, d, -pix_coord.yy)));
+
+ vec2 sqrt_d = sqrt(d);
+
+ float e2 = textureLodOffset(edges_tex, coords.xz, 0.0, ivec2(0, 1)).g;
+
+ weights.ba = SMAAArea(sqrt_d, e1, e2, params.subsample_indices.x);
+
+ coords.x = tex_coord.x;
+ SMAADetectVerticalCornerPattern(weights.ba, coords.xyxz, d);
+ }
+}
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index d84dced9e1d..118f9cce846 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -1363,6 +1363,7 @@ bool RendererViewport::viewport_is_using_hdr_2d(RID p_viewport) const {
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_NULL(viewport);
+ ERR_FAIL_COND_EDMSG(p_mode != RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED && OS::get_singleton()->get_current_rendering_method() == "gl_compatibility", "Screen space AA is currently unavailable on the Compatibility renderer.");
if (viewport->screen_space_aa == p_mode) {
return;
diff --git a/servers/rendering/storage/render_scene_buffers.cpp b/servers/rendering/storage/render_scene_buffers.cpp
index 4bf0365b72d..67135a4c4b5 100644
--- a/servers/rendering/storage/render_scene_buffers.cpp
+++ b/servers/rendering/storage/render_scene_buffers.cpp
@@ -57,7 +57,7 @@ void RenderSceneBuffersConfiguration::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &RenderSceneBuffersConfiguration::get_screen_space_aa);
ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &RenderSceneBuffersConfiguration::set_screen_space_aa);
- 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::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA,SMAA"), "set_screen_space_aa", "get_screen_space_aa");
ClassDB::bind_method(D_METHOD("get_fsr_sharpness"), &RenderSceneBuffersConfiguration::get_fsr_sharpness);
ClassDB::bind_method(D_METHOD("set_fsr_sharpness", "fsr_sharpness"), &RenderSceneBuffersConfiguration::set_fsr_sharpness);
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 37a9d0947a3..ac17ea3337e 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2914,6 +2914,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(VIEWPORT_SCREEN_SPACE_AA_DISABLED);
BIND_ENUM_CONSTANT(VIEWPORT_SCREEN_SPACE_AA_FXAA);
+ BIND_ENUM_CONSTANT(VIEWPORT_SCREEN_SPACE_AA_SMAA);
BIND_ENUM_CONSTANT(VIEWPORT_SCREEN_SPACE_AA_MAX);
BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW);
@@ -3676,6 +3677,8 @@ void RenderingServer::init() {
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01"), 0.25);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01"), 0.18);
+ GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/quality/smaa_edge_detection_threshold", PROPERTY_HINT_RANGE, "0.01,0.2,0.01"), 0.05);
+
{
String mode_hints;
String mode_hints_metal;
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index c83309275ae..4047330b215 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -1073,6 +1073,7 @@ public:
enum ViewportScreenSpaceAA {
VIEWPORT_SCREEN_SPACE_AA_DISABLED,
VIEWPORT_SCREEN_SPACE_AA_FXAA,
+ VIEWPORT_SCREEN_SPACE_AA_SMAA,
VIEWPORT_SCREEN_SPACE_AA_MAX,
};
diff --git a/thirdparty/smaa/AreaTex.png b/thirdparty/smaa/AreaTex.png
new file mode 100644
index 00000000000..48396b15cec
Binary files /dev/null and b/thirdparty/smaa/AreaTex.png differ
diff --git a/thirdparty/smaa/LICENSE.txt b/thirdparty/smaa/LICENSE.txt
new file mode 100644
index 00000000000..e6c0a6db87e
--- /dev/null
+++ b/thirdparty/smaa/LICENSE.txt
@@ -0,0 +1,24 @@
+Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com)
+Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
+Copyright (C) 2013 Belen Masia (bmasia@unizar.es)
+Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com)
+Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software. As clarification, there is no
+requirement that the copyright notice and permission be included in binary
+distributions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/thirdparty/smaa/SearchTex.png b/thirdparty/smaa/SearchTex.png
new file mode 100644
index 00000000000..4cff7bc4f52
Binary files /dev/null and b/thirdparty/smaa/SearchTex.png differ