Path: blob/master/servers/rendering/renderer_rd/effects/smaa.cpp
10279 views
/**************************************************************************/1/* smaa.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "smaa.h"3132#include "core/config/project_settings.h"33#include "core/io/image_loader.h"34#include "servers/rendering/renderer_rd/effects/smaa_area_tex.gen.h"35#include "servers/rendering/renderer_rd/effects/smaa_search_tex.gen.h"36#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"37#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"38#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"39#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"4041using namespace RendererRD;4243SMAA::SMAA() {44{45// Initialize edge detection.46Vector<String> smaa_modes;47smaa_modes.push_back("\n");48smaa.edge_shader.initialize(smaa_modes);4950smaa.edge_shader_version = smaa.edge_shader.version_create();5152RD::PipelineDepthStencilState stencil_state = RD::PipelineDepthStencilState();53stencil_state.enable_stencil = true;54stencil_state.back_op.reference = 0xff;55stencil_state.back_op.write_mask = 0xff;56stencil_state.back_op.compare_mask = 0xff;57stencil_state.back_op.pass = RD::STENCIL_OP_REPLACE;58stencil_state.front_op.reference = 0xff;59stencil_state.front_op.write_mask = 0xff;60stencil_state.front_op.compare_mask = 0xff;61stencil_state.front_op.pass = RD::STENCIL_OP_REPLACE;6263for (int i = SMAA_EDGE_DETECTION_COLOR; i <= SMAA_EDGE_DETECTION_COLOR; i++) {64smaa.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);65}6667edge_detection_threshold = GLOBAL_GET("rendering/anti_aliasing/quality/smaa_edge_detection_threshold");68}6970{71// Initialize weight calculation.72Vector<String> smaa_modes;73smaa_modes.push_back("\n");74smaa.weight_shader.initialize(smaa_modes);7576smaa.weight_shader_version = smaa.weight_shader.version_create();7778RD::PipelineDepthStencilState stencil_state;79stencil_state.enable_stencil = true;80stencil_state.back_op.reference = 0xff;81stencil_state.back_op.compare_mask = 0xff;82stencil_state.back_op.compare = RD::COMPARE_OP_EQUAL;83stencil_state.front_op.reference = 0xff;84stencil_state.front_op.compare_mask = 0xff;85stencil_state.front_op.compare = RD::COMPARE_OP_EQUAL;8687for (int i = SMAA_WEIGHT_FULL; i <= SMAA_WEIGHT_FULL; i++) {88smaa.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);89}90}9192{93// Initialize color blending.94Vector<String> smaa_modes;95smaa_modes.push_back("\n");96smaa.blend_shader.initialize(smaa_modes);9798smaa.blend_shader_version = smaa.blend_shader.version_create();99100for (int i = SMAA_BLENDING; i <= SMAA_BLENDING; i++) {101smaa.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);102}103}104105{106// Initialize SearchTex.107RD::TextureFormat tf;108tf.format = RD::DATA_FORMAT_R8_UNORM;109tf.width = SEARCHTEX_WIDTH;110tf.height = SEARCHTEX_HEIGHT;111tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;112113smaa.search_tex = RD::get_singleton()->texture_create(tf, RD::TextureView(), Vector<Vector<unsigned char>>{ Image(search_tex_png).get_data() });114}115116{117// Initialize AreaTex.118RD::TextureFormat tf;119tf.format = RD::DATA_FORMAT_R8G8_UNORM;120tf.width = AREATEX_WIDTH;121tf.height = AREATEX_HEIGHT;122tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;123124smaa.area_tex = RD::get_singleton()->texture_create(tf, RD::TextureView(), Vector<Vector<unsigned char>>{ Image(area_tex_png).get_data() });125}126127{128// Find smallest stencil texture format.129if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D16_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {130smaa.stencil_format = RD::DATA_FORMAT_D16_UNORM_S8_UINT;131} 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)) {132smaa.stencil_format = RD::DATA_FORMAT_D24_UNORM_S8_UINT;133} else {134smaa.stencil_format = RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;135}136}137}138139SMAA::~SMAA() {140RD::get_singleton()->free(smaa.search_tex);141RD::get_singleton()->free(smaa.area_tex);142143smaa.edge_shader.version_free(smaa.edge_shader_version);144smaa.weight_shader.version_free(smaa.weight_shader_version);145smaa.blend_shader.version_free(smaa.blend_shader_version);146}147148void SMAA::allocate_render_targets(Ref<RenderSceneBuffersRD> p_render_buffers) {149Size2i full_size = p_render_buffers->get_internal_size();150151// As we're not clearing these, and render buffers will return the cached texture if it already exists,152// we don't first check has_texture here.153154p_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);155p_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);156p_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);157}158159void SMAA::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_color, RID p_dst_framebuffer) {160UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();161ERR_FAIL_NULL(uniform_set_cache);162MaterialStorage *material_storage = MaterialStorage::get_singleton();163ERR_FAIL_NULL(material_storage);164165memset(&smaa.edge_push_constant, 0, sizeof(SMAAEdgePushConstant));166memset(&smaa.weight_push_constant, 0, sizeof(SMAAWeightPushConstant));167memset(&smaa.blend_push_constant, 0, sizeof(SMAABlendPushConstant));168169Size2i size = p_render_buffers->get_internal_size();170Size2 inv_size = Size2(1.0f / (float)size.x, 1.0f / (float)size.y);171172smaa.edge_push_constant.inv_size[0] = inv_size.x;173smaa.edge_push_constant.inv_size[1] = inv_size.y;174smaa.edge_push_constant.threshold = edge_detection_threshold;175176smaa.weight_push_constant.inv_size[0] = inv_size.x;177smaa.weight_push_constant.inv_size[1] = inv_size.y;178smaa.weight_push_constant.size[0] = size.x;179smaa.weight_push_constant.size[1] = size.y;180181smaa.blend_push_constant.inv_size[0] = inv_size.x;182smaa.blend_push_constant.inv_size[1] = inv_size.y;183if (debanding_mode == DEBANDING_MODE_8_BIT) {184smaa.blend_push_constant.flags |= SMAA_BLEND_FLAG_USE_8_BIT_DEBANDING;185} else if (debanding_mode == DEBANDING_MODE_10_BIT) {186smaa.blend_push_constant.flags |= SMAA_BLEND_FLAG_USE_10_BIT_DEBANDING;187}188189RID linear_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);190191allocate_render_targets(p_render_buffers);192RID edges_tex = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_EDGES);193RID blend_tex = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_BLEND);194RID stencil_buffer = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_STENCIL);195196RID edges_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(edges_tex, stencil_buffer);197RID blend_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(blend_tex, stencil_buffer);198199RD::Uniform u_source_color;200u_source_color.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;201u_source_color.binding = 0;202u_source_color.append_id(linear_sampler);203u_source_color.append_id(p_source_color);204205RD::Uniform u_edges_texture;206u_edges_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;207u_edges_texture.binding = 0;208u_edges_texture.append_id(linear_sampler);209u_edges_texture.append_id(edges_tex);210211RD::Uniform u_area_texture;212u_area_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;213u_area_texture.binding = 0;214u_area_texture.append_id(linear_sampler);215u_area_texture.append_id(smaa.area_tex);216217RD::Uniform u_search_texture;218u_search_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;219u_search_texture.binding = 1;220u_search_texture.append_id(linear_sampler);221u_search_texture.append_id(smaa.search_tex);222223RD::Uniform u_blend_texture;224u_blend_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;225u_blend_texture.binding = 0;226u_blend_texture.append_id(linear_sampler);227u_blend_texture.append_id(blend_tex);228229{230int mode = SMAA_EDGE_DETECTION_COLOR;231RID shader = smaa.edge_shader.version_get_shader(smaa.edge_shader_version, mode);232ERR_FAIL_COND(shader.is_null());233234RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(edges_framebuffer, RD::DRAW_CLEAR_COLOR_0 | RD::DRAW_CLEAR_STENCIL, Vector<Color>({ Color(0, 0, 0, 0) }), 1.0f, 0);235RD::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()));236RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);237238RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.edge_push_constant, sizeof(SMAAEdgePushConstant));239RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);240RD::get_singleton()->draw_list_end();241}242243{244int mode = SMAA_WEIGHT_FULL;245RID shader = smaa.weight_shader.version_get_shader(smaa.weight_shader_version, mode - SMAA_WEIGHT_FULL);246ERR_FAIL_COND(shader.is_null());247248RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(blend_framebuffer, RD::DRAW_CLEAR_COLOR_0, Vector<Color>({ Color(0, 0, 0, 0) }));249RD::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()));250RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_edges_texture), 0);251RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_area_texture, u_search_texture), 1);252253RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.weight_push_constant, sizeof(SMAAWeightPushConstant));254RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);255RD::get_singleton()->draw_list_end();256}257258{259int mode = SMAA_BLENDING;260RID shader = smaa.blend_shader.version_get_shader(smaa.blend_shader_version, mode - SMAA_BLENDING);261ERR_FAIL_COND(shader.is_null());262263RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::DRAW_IGNORE_COLOR_0);264RD::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()));265RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);266RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_blend_texture), 1);267268RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.blend_push_constant, sizeof(SMAABlendPushConstant));269RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);270RD::get_singleton()->draw_list_end();271}272}273274275