smaa.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /**************************************************************************/
  2. /* smaa.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "smaa.h"
  31. #include "core/config/project_settings.h"
  32. #include "core/io/image_loader.h"
  33. #include "servers/rendering/renderer_rd/effects/smaa_area_tex.gen.h"
  34. #include "servers/rendering/renderer_rd/effects/smaa_search_tex.gen.h"
  35. #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
  36. #include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
  37. #include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
  38. #include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
  39. using namespace RendererRD;
  40. SMAA::SMAA() {
  41. {
  42. // Initialize edge detection.
  43. Vector<String> smaa_modes;
  44. smaa_modes.push_back("\n");
  45. smaa.edge_shader.initialize(smaa_modes);
  46. smaa.edge_shader_version = smaa.edge_shader.version_create();
  47. RD::PipelineDepthStencilState stencil_state = RD::PipelineDepthStencilState();
  48. stencil_state.enable_stencil = true;
  49. stencil_state.back_op.reference = 0xff;
  50. stencil_state.back_op.write_mask = 0xff;
  51. stencil_state.back_op.compare_mask = 0xff;
  52. stencil_state.back_op.pass = RD::STENCIL_OP_REPLACE;
  53. stencil_state.front_op.reference = 0xff;
  54. stencil_state.front_op.write_mask = 0xff;
  55. stencil_state.front_op.compare_mask = 0xff;
  56. stencil_state.front_op.pass = RD::STENCIL_OP_REPLACE;
  57. for (int i = SMAA_EDGE_DETECTION_COLOR; i <= SMAA_EDGE_DETECTION_COLOR; i++) {
  58. 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);
  59. }
  60. edge_detection_threshold = GLOBAL_GET("rendering/anti_aliasing/quality/smaa_edge_detection_threshold");
  61. }
  62. {
  63. // Initialize weight calculation.
  64. Vector<String> smaa_modes;
  65. smaa_modes.push_back("\n");
  66. smaa.weight_shader.initialize(smaa_modes);
  67. smaa.weight_shader_version = smaa.weight_shader.version_create();
  68. RD::PipelineDepthStencilState stencil_state;
  69. stencil_state.enable_stencil = true;
  70. stencil_state.back_op.reference = 0xff;
  71. stencil_state.back_op.compare_mask = 0xff;
  72. stencil_state.back_op.compare = RD::COMPARE_OP_EQUAL;
  73. stencil_state.front_op.reference = 0xff;
  74. stencil_state.front_op.compare_mask = 0xff;
  75. stencil_state.front_op.compare = RD::COMPARE_OP_EQUAL;
  76. for (int i = SMAA_WEIGHT_FULL; i <= SMAA_WEIGHT_FULL; i++) {
  77. 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);
  78. }
  79. }
  80. {
  81. // Initialize color blending.
  82. Vector<String> smaa_modes;
  83. smaa_modes.push_back("\n");
  84. smaa.blend_shader.initialize(smaa_modes);
  85. smaa.blend_shader_version = smaa.blend_shader.version_create();
  86. for (int i = SMAA_BLENDING; i <= SMAA_BLENDING; i++) {
  87. 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);
  88. }
  89. }
  90. {
  91. // Initialize SearchTex.
  92. RD::TextureFormat tf;
  93. tf.format = RD::DATA_FORMAT_R8_UNORM;
  94. tf.width = SEARCHTEX_WIDTH;
  95. tf.height = SEARCHTEX_HEIGHT;
  96. tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
  97. smaa.search_tex = RD::get_singleton()->texture_create(tf, RD::TextureView(), Vector<Vector<unsigned char>>{ Image(search_tex_png).get_data() });
  98. }
  99. {
  100. // Initialize AreaTex.
  101. RD::TextureFormat tf;
  102. tf.format = RD::DATA_FORMAT_R8G8_UNORM;
  103. tf.width = AREATEX_WIDTH;
  104. tf.height = AREATEX_HEIGHT;
  105. tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
  106. smaa.area_tex = RD::get_singleton()->texture_create(tf, RD::TextureView(), Vector<Vector<unsigned char>>{ Image(area_tex_png).get_data() });
  107. }
  108. {
  109. // Find smallest stencil texture format.
  110. if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D16_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
  111. smaa.stencil_format = RD::DATA_FORMAT_D16_UNORM_S8_UINT;
  112. } 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)) {
  113. smaa.stencil_format = RD::DATA_FORMAT_D24_UNORM_S8_UINT;
  114. } else {
  115. smaa.stencil_format = RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
  116. }
  117. }
  118. }
  119. SMAA::~SMAA() {
  120. RD::get_singleton()->free(smaa.search_tex);
  121. RD::get_singleton()->free(smaa.area_tex);
  122. smaa.edge_shader.version_free(smaa.edge_shader_version);
  123. smaa.weight_shader.version_free(smaa.weight_shader_version);
  124. smaa.blend_shader.version_free(smaa.blend_shader_version);
  125. }
  126. void SMAA::allocate_render_targets(Ref<RenderSceneBuffersRD> p_render_buffers) {
  127. Size2i full_size = p_render_buffers->get_internal_size();
  128. // As we're not clearing these, and render buffers will return the cached texture if it already exists,
  129. // we don't first check has_texture here.
  130. 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);
  131. 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);
  132. 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);
  133. }
  134. void SMAA::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_color, RID p_dst_framebuffer) {
  135. UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
  136. ERR_FAIL_NULL(uniform_set_cache);
  137. MaterialStorage *material_storage = MaterialStorage::get_singleton();
  138. ERR_FAIL_NULL(material_storage);
  139. memset(&smaa.edge_push_constant, 0, sizeof(SMAAEdgePushConstant));
  140. memset(&smaa.weight_push_constant, 0, sizeof(SMAAWeightPushConstant));
  141. memset(&smaa.blend_push_constant, 0, sizeof(SMAABlendPushConstant));
  142. Size2i size = p_render_buffers->get_internal_size();
  143. Size2 inv_size = Size2(1.0f / (float)size.x, 1.0f / (float)size.y);
  144. smaa.edge_push_constant.inv_size[0] = inv_size.x;
  145. smaa.edge_push_constant.inv_size[1] = inv_size.y;
  146. smaa.edge_push_constant.threshold = edge_detection_threshold;
  147. smaa.weight_push_constant.inv_size[0] = inv_size.x;
  148. smaa.weight_push_constant.inv_size[1] = inv_size.y;
  149. smaa.weight_push_constant.size[0] = size.x;
  150. smaa.weight_push_constant.size[1] = size.y;
  151. smaa.blend_push_constant.inv_size[0] = inv_size.x;
  152. smaa.blend_push_constant.inv_size[1] = inv_size.y;
  153. RID linear_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
  154. allocate_render_targets(p_render_buffers);
  155. RID edges_tex = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_EDGES);
  156. RID blend_tex = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_BLEND);
  157. RID stencil_buffer = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_STENCIL);
  158. RID edges_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(edges_tex, stencil_buffer);
  159. RID blend_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(blend_tex, stencil_buffer);
  160. RD::Uniform u_source_color;
  161. u_source_color.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
  162. u_source_color.binding = 0;
  163. u_source_color.append_id(linear_sampler);
  164. u_source_color.append_id(p_source_color);
  165. RD::Uniform u_edges_texture;
  166. u_edges_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
  167. u_edges_texture.binding = 0;
  168. u_edges_texture.append_id(linear_sampler);
  169. u_edges_texture.append_id(edges_tex);
  170. RD::Uniform u_area_texture;
  171. u_area_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
  172. u_area_texture.binding = 0;
  173. u_area_texture.append_id(linear_sampler);
  174. u_area_texture.append_id(smaa.area_tex);
  175. RD::Uniform u_search_texture;
  176. u_search_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
  177. u_search_texture.binding = 1;
  178. u_search_texture.append_id(linear_sampler);
  179. u_search_texture.append_id(smaa.search_tex);
  180. RD::Uniform u_blend_texture;
  181. u_blend_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
  182. u_blend_texture.binding = 0;
  183. u_blend_texture.append_id(linear_sampler);
  184. u_blend_texture.append_id(blend_tex);
  185. {
  186. int mode = SMAA_EDGE_DETECTION_COLOR;
  187. RID shader = smaa.edge_shader.version_get_shader(smaa.edge_shader_version, mode);
  188. ERR_FAIL_COND(shader.is_null());
  189. RD::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);
  190. 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()));
  191. RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
  192. RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.edge_push_constant, sizeof(SMAAEdgePushConstant));
  193. RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
  194. RD::get_singleton()->draw_list_end();
  195. }
  196. {
  197. int mode = SMAA_WEIGHT_FULL;
  198. RID shader = smaa.weight_shader.version_get_shader(smaa.weight_shader_version, mode - SMAA_WEIGHT_FULL);
  199. ERR_FAIL_COND(shader.is_null());
  200. RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(blend_framebuffer, RD::DRAW_CLEAR_COLOR_0, Vector<Color>({ Color(0, 0, 0, 0) }));
  201. 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()));
  202. RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_edges_texture), 0);
  203. RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_area_texture, u_search_texture), 1);
  204. RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.weight_push_constant, sizeof(SMAAWeightPushConstant));
  205. RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
  206. RD::get_singleton()->draw_list_end();
  207. }
  208. {
  209. int mode = SMAA_BLENDING;
  210. RID shader = smaa.blend_shader.version_get_shader(smaa.blend_shader_version, mode - SMAA_BLENDING);
  211. ERR_FAIL_COND(shader.is_null());
  212. RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::DRAW_IGNORE_COLOR_0);
  213. 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()));
  214. RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
  215. RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_blend_texture), 1);
  216. RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.blend_push_constant, sizeof(SMAABlendPushConstant));
  217. RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
  218. RD::get_singleton()->draw_list_end();
  219. }
  220. }