Skip to content

Commit a33b548

Browse files
committed
Merge pull request #78168 from clayjohn/GLES3-gaussian-rt
Use Gaussian approximation for backbuffer mipmaps in GL Compatibility renderer
2 parents 008f32c + 9721a27 commit a33b548

File tree

4 files changed

+122
-8
lines changed

4 files changed

+122
-8
lines changed

drivers/gles3/effects/copy_effects.cpp

+76
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#ifdef GLES3_ENABLED
3232

3333
#include "copy_effects.h"
34+
#include "../storage/texture_storage.h"
3435

3536
using namespace GLES3;
3637

@@ -133,6 +134,7 @@ void CopyEffects::copy_screen() {
133134
draw_screen_triangle();
134135
}
135136

137+
// Intended for efficiently mipmapping textures.
136138
void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
137139
GLuint framebuffers[2];
138140
glGenFramebuffers(2, framebuffers);
@@ -158,6 +160,80 @@ void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, con
158160
glDeleteFramebuffers(2, framebuffers);
159161
}
160162

163+
// Intended for approximating a gaussian blur. Used for 2D backbuffer mipmaps. Slightly less efficient than bilinear_blur().
164+
void CopyEffects::gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size) {
165+
GLuint framebuffer;
166+
glGenFramebuffers(1, &framebuffer);
167+
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
168+
169+
glActiveTexture(GL_TEXTURE0);
170+
glBindTexture(GL_TEXTURE_2D, p_source_texture);
171+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
172+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
173+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
174+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
175+
176+
Size2i base_size = p_size;
177+
178+
Rect2i source_region = p_region;
179+
Rect2i dest_region = p_region;
180+
181+
Size2 float_size = Size2(p_size);
182+
Rect2 normalized_source_region = Rect2(p_region);
183+
normalized_source_region.position = normalized_source_region.position / float_size;
184+
normalized_source_region.size = normalized_source_region.size / float_size;
185+
Rect2 normalized_dest_region = Rect2(p_region);
186+
for (int i = 1; i < p_mipmap_count; i++) {
187+
dest_region.position.x >>= 1;
188+
dest_region.position.y >>= 1;
189+
dest_region.size.x = MAX(1, dest_region.size.x >> 1);
190+
dest_region.size.y = MAX(1, dest_region.size.y >> 1);
191+
base_size.x >>= 1;
192+
base_size.y >>= 1;
193+
194+
glBindTexture(GL_TEXTURE_2D, p_source_texture);
195+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, i - 1);
196+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i - 1);
197+
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, i);
198+
#ifdef DEV_ENABLED
199+
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
200+
if (status != GL_FRAMEBUFFER_COMPLETE) {
201+
WARN_PRINT("Could not bind Gaussian blur framebuffer, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
202+
}
203+
#endif
204+
205+
glViewport(0, 0, base_size.x, base_size.y);
206+
207+
bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);
208+
if (!success) {
209+
return;
210+
}
211+
212+
float_size = Size2(base_size);
213+
normalized_dest_region.position = Size2(dest_region.position) / float_size;
214+
normalized_dest_region.size = Size2(dest_region.size) / float_size;
215+
216+
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, normalized_dest_region.position.x, normalized_dest_region.position.y, normalized_dest_region.size.x, normalized_dest_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);
217+
copy.shader.version_set_uniform(CopyShaderGLES3::SOURCE_SECTION, normalized_source_region.position.x, normalized_source_region.position.y, normalized_source_region.size.x, normalized_source_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);
218+
copy.shader.version_set_uniform(CopyShaderGLES3::PIXEL_SIZE, 1.0 / float_size.x, 1.0 / float_size.y, copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);
219+
220+
draw_screen_quad();
221+
222+
source_region = dest_region;
223+
normalized_source_region = normalized_dest_region;
224+
}
225+
glBindFramebuffer(GL_FRAMEBUFFER, 0);
226+
glDeleteFramebuffers(1, &framebuffer);
227+
228+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
229+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
230+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
231+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, p_mipmap_count - 1);
232+
glBindTexture(GL_TEXTURE_2D, 0);
233+
234+
glViewport(0, 0, p_size.x, p_size.y);
235+
}
236+
161237
void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) {
162238
bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
163239
if (!success) {

drivers/gles3/effects/copy_effects.h

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class CopyEffects {
6464
void copy_to_rect(const Rect2 &p_rect);
6565
void copy_screen();
6666
void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
67+
void gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size);
6768
void set_color(const Color &p_color, const Rect2i &p_region);
6869
void draw_screen_triangle();
6970
void draw_screen_quad();

drivers/gles3/shaders/copy.glsl

+37-2
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,24 @@ layout(location = 0) in vec2 vertex_attrib;
1616
out vec2 uv_interp;
1717
/* clang-format on */
1818

19-
#ifdef USE_COPY_SECTION
19+
#if defined(USE_COPY_SECTION) || defined(MODE_GAUSSIAN_BLUR)
20+
// Defined in 0-1 coords.
2021
uniform highp vec4 copy_section;
2122
#endif
23+
#ifdef MODE_GAUSSIAN_BLUR
24+
uniform highp vec4 source_section;
25+
#endif
2226

2327
void main() {
2428
uv_interp = vertex_attrib * 0.5 + 0.5;
2529
gl_Position = vec4(vertex_attrib, 1.0, 1.0);
2630

27-
#ifdef USE_COPY_SECTION
31+
#if defined(USE_COPY_SECTION) || defined(MODE_GAUSSIAN_BLUR)
2832
gl_Position.xy = (copy_section.xy + uv_interp.xy * copy_section.zw) * 2.0 - 1.0;
2933
#endif
34+
#ifdef MODE_GAUSSIAN_BLUR
35+
uv_interp = source_section.xy + uv_interp * source_section.zw;
36+
#endif
3037
}
3138

3239
/* clang-format off */
@@ -39,6 +46,7 @@ uniform vec4 color_in;
3946
#endif
4047

4148
#ifdef MODE_GAUSSIAN_BLUR
49+
// Defined in 0-1 coords.
4250
uniform highp vec2 pixel_size;
4351
#endif
4452

@@ -55,4 +63,31 @@ void main() {
5563
#ifdef MODE_SIMPLE_COLOR
5664
frag_color = color_in;
5765
#endif
66+
67+
// Efficient box filter from Jimenez: http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
68+
// Approximates a Gaussian in a single pass.
69+
#ifdef MODE_GAUSSIAN_BLUR
70+
vec4 A = textureLod(source, uv_interp + pixel_size * vec2(-1.0, -1.0), 0.0);
71+
vec4 B = textureLod(source, uv_interp + pixel_size * vec2(0.0, -1.0), 0.0);
72+
vec4 C = textureLod(source, uv_interp + pixel_size * vec2(1.0, -1.0), 0.0);
73+
vec4 D = textureLod(source, uv_interp + pixel_size * vec2(-0.5, -0.5), 0.0);
74+
vec4 E = textureLod(source, uv_interp + pixel_size * vec2(0.5, -0.5), 0.0);
75+
vec4 F = textureLod(source, uv_interp + pixel_size * vec2(-1.0, 0.0), 0.0);
76+
vec4 G = textureLod(source, uv_interp, 0.0);
77+
vec4 H = textureLod(source, uv_interp + pixel_size * vec2(1.0, 0.0), 0.0);
78+
vec4 I = textureLod(source, uv_interp + pixel_size * vec2(-0.5, 0.5), 0.0);
79+
vec4 J = textureLod(source, uv_interp + pixel_size * vec2(0.5, 0.5), 0.0);
80+
vec4 K = textureLod(source, uv_interp + pixel_size * vec2(-1.0, 1.0), 0.0);
81+
vec4 L = textureLod(source, uv_interp + pixel_size * vec2(0.0, 1.0), 0.0);
82+
vec4 M = textureLod(source, uv_interp + pixel_size * vec2(1.0, 1.0), 0.0);
83+
84+
float weight = 0.5 / 4.0;
85+
float lesser_weight = 0.125 / 4.0;
86+
87+
frag_color = (D + E + I + J) * weight;
88+
frag_color += (A + B + G + F) * lesser_weight;
89+
frag_color += (B + C + H + G) * lesser_weight;
90+
frag_color += (F + G + L + K) * lesser_weight;
91+
frag_color += (G + H + M + L) * lesser_weight;
92+
#endif
5893
}

drivers/gles3/storage/texture_storage.cpp

+8-6
Original file line numberDiff line numberDiff line change
@@ -1837,10 +1837,10 @@ void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
18371837
}
18381838
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, texture_size_bytes, "Render target backbuffer color texture");
18391839

1840-
// Initialize all levels to opaque Magenta.
1840+
// Initialize all levels to clear black.
18411841
for (int j = 0; j < count; j++) {
18421842
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, j);
1843-
glClearColor(1.0, 0.0, 1.0, 1.0);
1843+
glClearColor(0.0, 0.0, 0.0, 0.0);
18441844
glClear(GL_COLOR_BUFFER_BIT);
18451845
}
18461846

@@ -2568,18 +2568,18 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons
25682568
}
25692569

25702570
glDisable(GL_BLEND);
2571-
//single texture copy for backbuffer
2571+
// Single texture copy for backbuffer.
25722572
glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
25732573
glActiveTexture(GL_TEXTURE0);
25742574
glBindTexture(GL_TEXTURE_2D, rt->color);
25752575
GLES3::CopyEffects::get_singleton()->copy_screen();
25762576

25772577
if (p_gen_mipmaps) {
2578-
GLES3::CopyEffects::get_singleton()->bilinear_blur(rt->backbuffer, rt->mipmap_count, region);
2578+
GLES3::CopyEffects::get_singleton()->gaussian_blur(rt->backbuffer, rt->mipmap_count, region, rt->size);
25792579
glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
25802580
}
25812581

2582-
glEnable(GL_BLEND); // 2D almost always uses blend.
2582+
glEnable(GL_BLEND); // 2D starts with blend enabled.
25832583
}
25842584

25852585
void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) {
@@ -2624,8 +2624,10 @@ void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target,
26242624
return; //nothing to do
26252625
}
26262626
}
2627+
glDisable(GL_BLEND);
2628+
GLES3::CopyEffects::get_singleton()->gaussian_blur(rt->backbuffer, rt->mipmap_count, region, rt->size);
2629+
glEnable(GL_BLEND); // 2D starts with blend enabled.
26272630

2628-
GLES3::CopyEffects::get_singleton()->bilinear_blur(rt->backbuffer, rt->mipmap_count, region);
26292631
glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
26302632
}
26312633

0 commit comments

Comments
 (0)