Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/servers/rendering/renderer_rd/effects/smaa.cpp
10279 views
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
31
#include "smaa.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/io/image_loader.h"
35
#include "servers/rendering/renderer_rd/effects/smaa_area_tex.gen.h"
36
#include "servers/rendering/renderer_rd/effects/smaa_search_tex.gen.h"
37
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
38
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
39
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
40
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
41
42
using namespace RendererRD;
43
44
SMAA::SMAA() {
45
{
46
// Initialize edge detection.
47
Vector<String> smaa_modes;
48
smaa_modes.push_back("\n");
49
smaa.edge_shader.initialize(smaa_modes);
50
51
smaa.edge_shader_version = smaa.edge_shader.version_create();
52
53
RD::PipelineDepthStencilState stencil_state = RD::PipelineDepthStencilState();
54
stencil_state.enable_stencil = true;
55
stencil_state.back_op.reference = 0xff;
56
stencil_state.back_op.write_mask = 0xff;
57
stencil_state.back_op.compare_mask = 0xff;
58
stencil_state.back_op.pass = RD::STENCIL_OP_REPLACE;
59
stencil_state.front_op.reference = 0xff;
60
stencil_state.front_op.write_mask = 0xff;
61
stencil_state.front_op.compare_mask = 0xff;
62
stencil_state.front_op.pass = RD::STENCIL_OP_REPLACE;
63
64
for (int i = SMAA_EDGE_DETECTION_COLOR; i <= SMAA_EDGE_DETECTION_COLOR; i++) {
65
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);
66
}
67
68
edge_detection_threshold = GLOBAL_GET("rendering/anti_aliasing/quality/smaa_edge_detection_threshold");
69
}
70
71
{
72
// Initialize weight calculation.
73
Vector<String> smaa_modes;
74
smaa_modes.push_back("\n");
75
smaa.weight_shader.initialize(smaa_modes);
76
77
smaa.weight_shader_version = smaa.weight_shader.version_create();
78
79
RD::PipelineDepthStencilState stencil_state;
80
stencil_state.enable_stencil = true;
81
stencil_state.back_op.reference = 0xff;
82
stencil_state.back_op.compare_mask = 0xff;
83
stencil_state.back_op.compare = RD::COMPARE_OP_EQUAL;
84
stencil_state.front_op.reference = 0xff;
85
stencil_state.front_op.compare_mask = 0xff;
86
stencil_state.front_op.compare = RD::COMPARE_OP_EQUAL;
87
88
for (int i = SMAA_WEIGHT_FULL; i <= SMAA_WEIGHT_FULL; i++) {
89
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);
90
}
91
}
92
93
{
94
// Initialize color blending.
95
Vector<String> smaa_modes;
96
smaa_modes.push_back("\n");
97
smaa.blend_shader.initialize(smaa_modes);
98
99
smaa.blend_shader_version = smaa.blend_shader.version_create();
100
101
for (int i = SMAA_BLENDING; i <= SMAA_BLENDING; i++) {
102
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);
103
}
104
}
105
106
{
107
// Initialize SearchTex.
108
RD::TextureFormat tf;
109
tf.format = RD::DATA_FORMAT_R8_UNORM;
110
tf.width = SEARCHTEX_WIDTH;
111
tf.height = SEARCHTEX_HEIGHT;
112
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
113
114
smaa.search_tex = RD::get_singleton()->texture_create(tf, RD::TextureView(), Vector<Vector<unsigned char>>{ Image(search_tex_png).get_data() });
115
}
116
117
{
118
// Initialize AreaTex.
119
RD::TextureFormat tf;
120
tf.format = RD::DATA_FORMAT_R8G8_UNORM;
121
tf.width = AREATEX_WIDTH;
122
tf.height = AREATEX_HEIGHT;
123
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
124
125
smaa.area_tex = RD::get_singleton()->texture_create(tf, RD::TextureView(), Vector<Vector<unsigned char>>{ Image(area_tex_png).get_data() });
126
}
127
128
{
129
// Find smallest stencil texture format.
130
if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D16_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
131
smaa.stencil_format = RD::DATA_FORMAT_D16_UNORM_S8_UINT;
132
} 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)) {
133
smaa.stencil_format = RD::DATA_FORMAT_D24_UNORM_S8_UINT;
134
} else {
135
smaa.stencil_format = RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
136
}
137
}
138
}
139
140
SMAA::~SMAA() {
141
RD::get_singleton()->free(smaa.search_tex);
142
RD::get_singleton()->free(smaa.area_tex);
143
144
smaa.edge_shader.version_free(smaa.edge_shader_version);
145
smaa.weight_shader.version_free(smaa.weight_shader_version);
146
smaa.blend_shader.version_free(smaa.blend_shader_version);
147
}
148
149
void SMAA::allocate_render_targets(Ref<RenderSceneBuffersRD> p_render_buffers) {
150
Size2i full_size = p_render_buffers->get_internal_size();
151
152
// As we're not clearing these, and render buffers will return the cached texture if it already exists,
153
// we don't first check has_texture here.
154
155
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);
156
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);
157
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);
158
}
159
160
void SMAA::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_color, RID p_dst_framebuffer) {
161
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
162
ERR_FAIL_NULL(uniform_set_cache);
163
MaterialStorage *material_storage = MaterialStorage::get_singleton();
164
ERR_FAIL_NULL(material_storage);
165
166
memset(&smaa.edge_push_constant, 0, sizeof(SMAAEdgePushConstant));
167
memset(&smaa.weight_push_constant, 0, sizeof(SMAAWeightPushConstant));
168
memset(&smaa.blend_push_constant, 0, sizeof(SMAABlendPushConstant));
169
170
Size2i size = p_render_buffers->get_internal_size();
171
Size2 inv_size = Size2(1.0f / (float)size.x, 1.0f / (float)size.y);
172
173
smaa.edge_push_constant.inv_size[0] = inv_size.x;
174
smaa.edge_push_constant.inv_size[1] = inv_size.y;
175
smaa.edge_push_constant.threshold = edge_detection_threshold;
176
177
smaa.weight_push_constant.inv_size[0] = inv_size.x;
178
smaa.weight_push_constant.inv_size[1] = inv_size.y;
179
smaa.weight_push_constant.size[0] = size.x;
180
smaa.weight_push_constant.size[1] = size.y;
181
182
smaa.blend_push_constant.inv_size[0] = inv_size.x;
183
smaa.blend_push_constant.inv_size[1] = inv_size.y;
184
if (debanding_mode == DEBANDING_MODE_8_BIT) {
185
smaa.blend_push_constant.flags |= SMAA_BLEND_FLAG_USE_8_BIT_DEBANDING;
186
} else if (debanding_mode == DEBANDING_MODE_10_BIT) {
187
smaa.blend_push_constant.flags |= SMAA_BLEND_FLAG_USE_10_BIT_DEBANDING;
188
}
189
190
RID linear_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
191
192
allocate_render_targets(p_render_buffers);
193
RID edges_tex = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_EDGES);
194
RID blend_tex = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_BLEND);
195
RID stencil_buffer = p_render_buffers->get_texture(RB_SCOPE_SMAA, RB_STENCIL);
196
197
RID edges_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(edges_tex, stencil_buffer);
198
RID blend_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(blend_tex, stencil_buffer);
199
200
RD::Uniform u_source_color;
201
u_source_color.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
202
u_source_color.binding = 0;
203
u_source_color.append_id(linear_sampler);
204
u_source_color.append_id(p_source_color);
205
206
RD::Uniform u_edges_texture;
207
u_edges_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
208
u_edges_texture.binding = 0;
209
u_edges_texture.append_id(linear_sampler);
210
u_edges_texture.append_id(edges_tex);
211
212
RD::Uniform u_area_texture;
213
u_area_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
214
u_area_texture.binding = 0;
215
u_area_texture.append_id(linear_sampler);
216
u_area_texture.append_id(smaa.area_tex);
217
218
RD::Uniform u_search_texture;
219
u_search_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
220
u_search_texture.binding = 1;
221
u_search_texture.append_id(linear_sampler);
222
u_search_texture.append_id(smaa.search_tex);
223
224
RD::Uniform u_blend_texture;
225
u_blend_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
226
u_blend_texture.binding = 0;
227
u_blend_texture.append_id(linear_sampler);
228
u_blend_texture.append_id(blend_tex);
229
230
{
231
int mode = SMAA_EDGE_DETECTION_COLOR;
232
RID shader = smaa.edge_shader.version_get_shader(smaa.edge_shader_version, mode);
233
ERR_FAIL_COND(shader.is_null());
234
235
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);
236
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()));
237
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
238
239
RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.edge_push_constant, sizeof(SMAAEdgePushConstant));
240
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
241
RD::get_singleton()->draw_list_end();
242
}
243
244
{
245
int mode = SMAA_WEIGHT_FULL;
246
RID shader = smaa.weight_shader.version_get_shader(smaa.weight_shader_version, mode - SMAA_WEIGHT_FULL);
247
ERR_FAIL_COND(shader.is_null());
248
249
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(blend_framebuffer, RD::DRAW_CLEAR_COLOR_0, Vector<Color>({ Color(0, 0, 0, 0) }));
250
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()));
251
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_edges_texture), 0);
252
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_area_texture, u_search_texture), 1);
253
254
RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.weight_push_constant, sizeof(SMAAWeightPushConstant));
255
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
256
RD::get_singleton()->draw_list_end();
257
}
258
259
{
260
int mode = SMAA_BLENDING;
261
RID shader = smaa.blend_shader.version_get_shader(smaa.blend_shader_version, mode - SMAA_BLENDING);
262
ERR_FAIL_COND(shader.is_null());
263
264
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::DRAW_IGNORE_COLOR_0);
265
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()));
266
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0);
267
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_blend_texture), 1);
268
269
RD::get_singleton()->draw_list_set_push_constant(draw_list, &smaa.blend_push_constant, sizeof(SMAABlendPushConstant));
270
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
271
RD::get_singleton()->draw_list_end();
272
}
273
}
274
275