summaryrefslogtreecommitdiffstats
path: root/drivers/gles3
diff options
context:
space:
mode:
authorBastiaan Olij <mux213@gmail.com>2024-01-19 16:14:36 +1100
committerBastiaan Olij <mux213@gmail.com>2024-02-19 13:29:43 +1100
commitaa260e5f3d4ce0c5551e84ef0b098ddf9e78fd0d (patch)
tree36f783a9e1c84aafe723833d2831f2ef3c8c430b /drivers/gles3
parentab4c5a594ab11cf6446fa819de639bb71de9ccbf (diff)
downloadredot-engine-aa260e5f3d4ce0c5551e84ef0b098ddf9e78fd0d.tar.gz
Implement glow/bloom on compatibility renderer
Diffstat (limited to 'drivers/gles3')
-rw-r--r--drivers/gles3/effects/copy_effects.cpp6
-rw-r--r--drivers/gles3/effects/copy_effects.h4
-rw-r--r--drivers/gles3/effects/glow.cpp172
-rw-r--r--drivers/gles3/effects/glow.h89
-rw-r--r--drivers/gles3/effects/post_effects.cpp152
-rw-r--r--drivers/gles3/effects/post_effects.h69
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp4
-rw-r--r--drivers/gles3/rasterizer_gles3.h4
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp309
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h90
-rw-r--r--drivers/gles3/shaders/SCsub11
-rw-r--r--drivers/gles3/shaders/effects/SCsub17
-rw-r--r--drivers/gles3/shaders/effects/copy.glsl (renamed from drivers/gles3/shaders/copy.glsl)13
-rw-r--r--drivers/gles3/shaders/effects/glow.glsl113
-rw-r--r--drivers/gles3/shaders/effects/post.glsl96
-rw-r--r--drivers/gles3/shaders/scene.glsl24
-rw-r--r--drivers/gles3/shaders/sky.glsl10
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.cpp177
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h70
-rw-r--r--drivers/gles3/storage/texture_storage.cpp75
-rw-r--r--drivers/gles3/storage/texture_storage.h11
21 files changed, 1303 insertions, 213 deletions
diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp
index 29e7de873b..43bc6d5476 100644
--- a/drivers/gles3/effects/copy_effects.cpp
+++ b/drivers/gles3/effects/copy_effects.cpp
@@ -155,12 +155,14 @@ void CopyEffects::copy_to_and_from_rect(const Rect2 &p_rect) {
draw_screen_quad();
}
-void CopyEffects::copy_screen() {
- bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);
+void CopyEffects::copy_screen(float p_multiply) {
+ bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SCREEN);
if (!success) {
return;
}
+ copy.shader.version_set_uniform(CopyShaderGLES3::MULTIPLY, p_multiply, copy.shader_version, CopyShaderGLES3::MODE_SCREEN);
+
draw_screen_triangle();
}
diff --git a/drivers/gles3/effects/copy_effects.h b/drivers/gles3/effects/copy_effects.h
index e65ebbce03..1f7b3ee689 100644
--- a/drivers/gles3/effects/copy_effects.h
+++ b/drivers/gles3/effects/copy_effects.h
@@ -33,7 +33,7 @@
#ifdef GLES3_ENABLED
-#include "drivers/gles3/shaders/copy.glsl.gen.h"
+#include "drivers/gles3/shaders/effects/copy.glsl.gen.h"
namespace GLES3 {
@@ -64,7 +64,7 @@ public:
void copy_to_rect(const Rect2 &p_rect);
void copy_to_rect_3d(const Rect2 &p_rect, float p_layer, int p_type, float p_lod = 0.0f);
void copy_to_and_from_rect(const Rect2 &p_rect);
- void copy_screen();
+ void copy_screen(float p_multiply = 1.0);
void copy_cube_to_rect(const Rect2 &p_rect);
void copy_cube_to_panorama(float p_mip_level);
void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
diff --git a/drivers/gles3/effects/glow.cpp b/drivers/gles3/effects/glow.cpp
new file mode 100644
index 0000000000..9fc2eef65b
--- /dev/null
+++ b/drivers/gles3/effects/glow.cpp
@@ -0,0 +1,172 @@
+/**************************************************************************/
+/* glow.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. */
+/**************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "glow.h"
+
+using namespace GLES3;
+
+Glow *Glow::singleton = nullptr;
+
+Glow *Glow::get_singleton() {
+ return singleton;
+}
+
+Glow::Glow() {
+ singleton = this;
+
+ glow.shader.initialize();
+ glow.shader_version = glow.shader.version_create();
+
+ { // Screen Triangle.
+ glGenBuffers(1, &screen_triangle);
+ glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
+
+ const float qv[6] = {
+ -1.0f,
+ -1.0f,
+ 3.0f,
+ -1.0f,
+ -1.0f,
+ 3.0f,
+ };
+
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+
+ glGenVertexArrays(1, &screen_triangle_array);
+ glBindVertexArray(screen_triangle_array);
+ glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ }
+}
+
+Glow::~Glow() {
+ glDeleteBuffers(1, &screen_triangle);
+ glDeleteVertexArrays(1, &screen_triangle_array);
+
+ glow.shader.version_free(glow.shader_version);
+
+ singleton = nullptr;
+}
+
+void Glow::_draw_screen_triangle() {
+ glBindVertexArray(screen_triangle_array);
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ glBindVertexArray(0);
+}
+
+void Glow::process_glow(GLuint p_source_color, Size2i p_size, const Glow::GLOWLEVEL *p_glow_buffers, uint32_t p_view, bool p_use_multiview) {
+ ERR_FAIL_COND(p_source_color == 0);
+ ERR_FAIL_COND(p_glow_buffers[3].color == 0);
+
+ // Reset some OpenGL state...
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+
+ // Start with our filter pass
+ {
+ glBindFramebuffer(GL_FRAMEBUFFER, p_glow_buffers[0].fbo);
+ glViewport(0, 0, p_glow_buffers[0].size.x, p_glow_buffers[0].size.y);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(p_use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D, p_source_color);
+
+ uint64_t specialization = p_use_multiview ? GlowShaderGLES3::USE_MULTIVIEW : 0;
+ bool success = glow.shader.version_bind_shader(glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
+ if (!success) {
+ return;
+ }
+
+ glow.shader.version_set_uniform(GlowShaderGLES3::PIXEL_SIZE, 1.0 / p_glow_buffers[0].size.x, 1.0 / p_glow_buffers[0].size.y, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
+ glow.shader.version_set_uniform(GlowShaderGLES3::VIEW, float(p_view), glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
+ glow.shader.version_set_uniform(GlowShaderGLES3::LUMINANCE_MULTIPLIER, luminance_multiplier, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
+ glow.shader.version_set_uniform(GlowShaderGLES3::GLOW_BLOOM, glow_bloom, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
+ glow.shader.version_set_uniform(GlowShaderGLES3::GLOW_HDR_THRESHOLD, glow_hdr_bleed_threshold, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
+ glow.shader.version_set_uniform(GlowShaderGLES3::GLOW_HDR_SCALE, glow_hdr_bleed_scale, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
+ glow.shader.version_set_uniform(GlowShaderGLES3::GLOW_LUMINANCE_CAP, glow_hdr_luminance_cap, glow.shader_version, GlowShaderGLES3::MODE_FILTER, specialization);
+
+ _draw_screen_triangle();
+ }
+
+ // Continue with downsampling
+ {
+ bool success = glow.shader.version_bind_shader(glow.shader_version, GlowShaderGLES3::MODE_DOWNSAMPLE, 0);
+ if (!success) {
+ return;
+ }
+
+ for (int i = 1; i < 4; i++) {
+ glBindFramebuffer(GL_FRAMEBUFFER, p_glow_buffers[i].fbo);
+ glViewport(0, 0, p_glow_buffers[i].size.x, p_glow_buffers[i].size.y);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, p_glow_buffers[i - 1].color);
+
+ glow.shader.version_set_uniform(GlowShaderGLES3::PIXEL_SIZE, 1.0 / p_glow_buffers[i].size.x, 1.0 / p_glow_buffers[i].size.y, glow.shader_version, GlowShaderGLES3::MODE_DOWNSAMPLE);
+
+ _draw_screen_triangle();
+ }
+ }
+
+ // Now upsample
+ {
+ bool success = glow.shader.version_bind_shader(glow.shader_version, GlowShaderGLES3::MODE_UPSAMPLE, 0);
+ if (!success) {
+ return;
+ }
+
+ for (int i = 2; i >= 0; i--) {
+ glBindFramebuffer(GL_FRAMEBUFFER, p_glow_buffers[i].fbo);
+ glViewport(0, 0, p_glow_buffers[i].size.x, p_glow_buffers[i].size.y);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, p_glow_buffers[i + 1].color);
+
+ glow.shader.version_set_uniform(GlowShaderGLES3::PIXEL_SIZE, 1.0 / p_glow_buffers[i].size.x, 1.0 / p_glow_buffers[i].size.y, glow.shader_version, GlowShaderGLES3::MODE_UPSAMPLE);
+
+ _draw_screen_triangle();
+ }
+ }
+
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+ glUseProgram(0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/effects/glow.h b/drivers/gles3/effects/glow.h
new file mode 100644
index 0000000000..a1be6e1f4c
--- /dev/null
+++ b/drivers/gles3/effects/glow.h
@@ -0,0 +1,89 @@
+/**************************************************************************/
+/* glow.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. */
+/**************************************************************************/
+
+#ifndef GLOW_GLES3_H
+#define GLOW_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "drivers/gles3/shaders/effects/glow.glsl.gen.h"
+
+namespace GLES3 {
+
+class Glow {
+private:
+ static Glow *singleton;
+
+ struct GLOW {
+ GlowShaderGLES3 shader;
+ RID shader_version;
+ } glow;
+
+ float luminance_multiplier = 1.0;
+
+ float glow_intensity = 1.0;
+ float glow_bloom = 0.0;
+ float glow_hdr_bleed_threshold = 1.0;
+ float glow_hdr_bleed_scale = 2.0;
+ float glow_hdr_luminance_cap = 12.0;
+
+ // Use for full-screen effects. Slightly more efficient than screen_quad as this eliminates pixel overdraw along the diagonal.
+ GLuint screen_triangle = 0;
+ GLuint screen_triangle_array = 0;
+
+ void _draw_screen_triangle();
+
+public:
+ struct GLOWLEVEL {
+ Size2i size;
+ GLuint color = 0;
+ GLuint fbo = 0;
+ };
+
+ static Glow *get_singleton();
+
+ Glow();
+ ~Glow();
+
+ void set_intensity(float p_value) { glow_intensity = p_value; }
+ void set_luminance_multiplier(float p_luminance_multiplier) { luminance_multiplier = p_luminance_multiplier; }
+ void set_glow_bloom(float p_bloom) { glow_bloom = p_bloom; }
+ void set_glow_hdr_bleed_threshold(float p_threshold) { glow_hdr_bleed_threshold = p_threshold; }
+ void set_glow_hdr_bleed_scale(float p_scale) { glow_hdr_bleed_scale = p_scale; }
+ void set_glow_hdr_luminance_cap(float p_cap) { glow_hdr_luminance_cap = p_cap; }
+
+ void process_glow(GLuint p_source_color, Size2i p_size, const GLOWLEVEL *p_glow_buffers, uint32_t p_view = 0, bool p_use_multiview = false);
+};
+
+} //namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // GLOW_GLES3_H
diff --git a/drivers/gles3/effects/post_effects.cpp b/drivers/gles3/effects/post_effects.cpp
new file mode 100644
index 0000000000..75af068ab5
--- /dev/null
+++ b/drivers/gles3/effects/post_effects.cpp
@@ -0,0 +1,152 @@
+/**************************************************************************/
+/* post_effects.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. */
+/**************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "post_effects.h"
+
+using namespace GLES3;
+
+PostEffects *PostEffects::singleton = nullptr;
+
+PostEffects *PostEffects::get_singleton() {
+ return singleton;
+}
+
+PostEffects::PostEffects() {
+ singleton = this;
+
+ post.shader.initialize();
+ post.shader_version = post.shader.version_create();
+ post.shader.version_bind_shader(post.shader_version, PostShaderGLES3::MODE_DEFAULT);
+
+ { // Screen Triangle.
+ glGenBuffers(1, &screen_triangle);
+ glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
+
+ const float qv[6] = {
+ -1.0f,
+ -1.0f,
+ 3.0f,
+ -1.0f,
+ -1.0f,
+ 3.0f,
+ };
+
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+
+ glGenVertexArrays(1, &screen_triangle_array);
+ glBindVertexArray(screen_triangle_array);
+ glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ }
+}
+
+PostEffects::~PostEffects() {
+ singleton = nullptr;
+ glDeleteBuffers(1, &screen_triangle);
+ glDeleteVertexArrays(1, &screen_triangle_array);
+ post.shader.version_free(post.shader_version);
+}
+
+void PostEffects::_draw_screen_triangle() {
+ glBindVertexArray(screen_triangle_array);
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ glBindVertexArray(0);
+}
+
+void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view, bool p_use_multiview) {
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_BLEND);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, p_dest_framebuffer);
+ glViewport(0, 0, p_dest_size.x, p_dest_size.y);
+
+ PostShaderGLES3::ShaderVariant mode = PostShaderGLES3::MODE_DEFAULT;
+ uint64_t flags = 0;
+ if (p_use_multiview) {
+ flags |= PostShaderGLES3::USE_MULTIVIEW;
+ }
+ if (p_glow_buffers != nullptr) {
+ flags |= PostShaderGLES3::USE_GLOW;
+ }
+ if (p_luminance_multiplier != 1.0) {
+ flags |= PostShaderGLES3::USE_LUMINANCE_MULTIPLIER;
+ }
+
+ bool success = post.shader.version_bind_shader(post.shader_version, mode, flags);
+ if (!success) {
+ return;
+ }
+
+ GLenum texture_target = p_use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(texture_target, p_source_color);
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ if (p_glow_buffers != nullptr) {
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, p_glow_buffers[0].color);
+
+ post.shader.version_set_uniform(PostShaderGLES3::PIXEL_SIZE, 1.0 / p_source_size.x, 1.0 / p_source_size.y, post.shader_version, mode, flags);
+ post.shader.version_set_uniform(PostShaderGLES3::GLOW_INTENSITY, p_glow_intensity, post.shader_version, mode, flags);
+ }
+
+ post.shader.version_set_uniform(PostShaderGLES3::VIEW, float(p_view), post.shader_version, mode, flags);
+ post.shader.version_set_uniform(PostShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, post.shader_version, mode, flags);
+
+ _draw_screen_triangle();
+
+ // Reset state
+ if (p_glow_buffers != nullptr) {
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ // Return back to nearest
+ glActiveTexture(GL_TEXTURE0);
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glBindTexture(texture_target, 0);
+
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+ glUseProgram(0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/effects/post_effects.h b/drivers/gles3/effects/post_effects.h
new file mode 100644
index 0000000000..b90c77d6c7
--- /dev/null
+++ b/drivers/gles3/effects/post_effects.h
@@ -0,0 +1,69 @@
+/**************************************************************************/
+/* post_effects.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. */
+/**************************************************************************/
+
+#ifndef POST_EFFECTS_GLES3_H
+#define POST_EFFECTS_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "drivers/gles3/shaders/effects/post.glsl.gen.h"
+#include "glow.h"
+
+namespace GLES3 {
+
+class PostEffects {
+private:
+ struct Post {
+ PostShaderGLES3 shader;
+ RID shader_version;
+ } post;
+
+ static PostEffects *singleton;
+
+ // Use for full-screen effects. Slightly more efficient than screen_quad as this eliminates pixel overdraw along the diagonal.
+ GLuint screen_triangle = 0;
+ GLuint screen_triangle_array = 0;
+
+ void _draw_screen_triangle();
+
+public:
+ static PostEffects *get_singleton();
+
+ PostEffects();
+ ~PostEffects();
+
+ void post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view = 0, bool p_use_multiview = false);
+};
+
+} //namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // POST_EFFECTS_GLES3_H
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index f5296f969f..14ef0f40cf 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -201,6 +201,8 @@ void RasterizerGLES3::finalize() {
memdelete(canvas);
memdelete(gi);
memdelete(fog);
+ memdelete(post_effects);
+ memdelete(glow);
memdelete(copy_effects);
memdelete(light_storage);
memdelete(particles_storage);
@@ -347,6 +349,8 @@ RasterizerGLES3::RasterizerGLES3() {
particles_storage = memnew(GLES3::ParticlesStorage);
light_storage = memnew(GLES3::LightStorage);
copy_effects = memnew(GLES3::CopyEffects);
+ glow = memnew(GLES3::Glow);
+ post_effects = memnew(GLES3::PostEffects);
gi = memnew(GLES3::GI);
fog = memnew(GLES3::Fog);
canvas = memnew(RasterizerCanvasGLES3());
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index cf3cedfea1..fc1315035b 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -34,6 +34,8 @@
#ifdef GLES3_ENABLED
#include "effects/copy_effects.h"
+#include "effects/glow.h"
+#include "effects/post_effects.h"
#include "environment/fog.h"
#include "environment/gi.h"
#include "rasterizer_canvas_gles3.h"
@@ -67,6 +69,8 @@ protected:
GLES3::GI *gi = nullptr;
GLES3::Fog *fog = nullptr;
GLES3::CopyEffects *copy_effects = nullptr;
+ GLES3::Glow *glow = nullptr;
+ GLES3::PostEffects *post_effects = nullptr;
RasterizerCanvasGLES3 *canvas = nullptr;
RasterizerSceneGLES3 *scene = nullptr;
static RasterizerGLES3 *singleton;
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index efd554eac9..4e31e1bcdd 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -764,7 +764,7 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
}
}
-void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier, bool p_use_multiview, bool p_flip_y) {
+void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_sky_energy_multiplier, float p_luminance_multiplier, bool p_use_multiview, bool p_flip_y, bool p_apply_color_adjustments_in_post) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
@@ -778,6 +778,10 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
if (p_flip_y) {
spec_constants |= SkyShaderGLES3::USE_INVERTED_Y;
}
+ if (!p_apply_color_adjustments_in_post) {
+ spec_constants |= SkyShaderGLES3::APPLY_TONEMAPPING;
+ // TODO add BCS and color corrections once supported.
+ }
RS::EnvironmentBG background = environment_get_background(p_env);
@@ -832,6 +836,7 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.columns[2][0], camera.columns[0][0], camera.columns[2][1], camera.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::SKY_ENERGY_MULTIPLIER, p_sky_energy_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
if (p_use_multiview) {
@@ -843,7 +848,7 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
glDrawArrays(GL_TRIANGLES, 0, 3);
}
-void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier) {
+void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_sky_energy_multiplier) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
@@ -939,20 +944,17 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, cm.columns[2][0], cm.columns[0][0], cm.columns[2][1], cm.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
- material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::SKY_ENERGY_MULTIPLIER, p_sky_energy_multiplier, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, 1.0, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
glBindVertexArray(sky_globals.screen_triangle_array);
glViewport(0, 0, sky->radiance_size, sky->radiance_size);
glBindFramebuffer(GL_FRAMEBUFFER, sky->radiance_framebuffer);
- glDisable(GL_BLEND);
- glDepthMask(GL_FALSE);
- glDisable(GL_DEPTH_TEST);
- scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_DISABLED;
- glDisable(GL_SCISSOR_TEST);
- glDisable(GL_CULL_FACE);
- scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
+ scene_state.reset_gl_state();
+ scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED);
+ scene_state.enable_gl_blend(false);
for (int i = 0; i < 6; i++) {
Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
@@ -969,17 +971,13 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
_filter_sky_radiance(sky, 0); //Just copy over the first mipmap
}
sky->processing_layer = 1;
- sky->baked_exposure = p_luminance_multiplier;
+ sky->baked_exposure = p_sky_energy_multiplier;
sky->reflection_dirty = false;
} else {
if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
- glDisable(GL_BLEND);
- glDepthMask(GL_FALSE);
- glDisable(GL_DEPTH_TEST);
- scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_DISABLED;
- glDisable(GL_SCISSOR_TEST);
- glDisable(GL_CULL_FACE);
- scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
+ scene_state.reset_gl_state();
+ scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED);
+ scene_state.enable_gl_blend(false);
_filter_sky_radiance(sky, sky->processing_layer);
sky->processing_layer++;
@@ -1584,6 +1582,8 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
+ scene_state.ubo.luminance_multiplier = p_render_data->luminance_multiplier;
+
scene_state.ubo.shadow_bias = p_shadow_bias;
scene_state.ubo.pancake_shadows = p_pancake_shadows;
@@ -2271,14 +2271,10 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
+ scene_state.reset_gl_state();
+ scene_state.enable_gl_depth_test(true);
+ scene_state.enable_gl_depth_draw(true);
glDepthFunc(GL_LESS);
- glDisable(GL_SCISSOR_TEST);
- glCullFace(GL_BACK);
- glEnable(GL_CULL_FACE);
- scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
glColorMask(0, 0, 0, 0);
glDrawBuffers(0, nullptr);
@@ -2303,8 +2299,8 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
_render_list_template<PASS_MODE_SHADOW>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_SECONDARY].elements.size());
glColorMask(1, 1, 1, 1);
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
+ scene_state.enable_gl_depth_test(false);
+ scene_state.enable_gl_depth_draw(true);
glDisable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -2315,15 +2311,32 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
GLES3::Config *config = GLES3::Config::get_singleton();
RENDER_TIMESTAMP("Setup 3D Scene");
+ bool apply_color_adjustments_in_post = false;
+
Ref<RenderSceneBuffersGLES3> rb;
if (p_render_buffers.is_valid()) {
rb = p_render_buffers;
ERR_FAIL_COND(rb.is_null());
+
+ if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) {
+ // If we're scaling, we apply tonemapping etc. in post, so disable it during rendering
+ apply_color_adjustments_in_post = true;
+ }
}
GLES3::RenderTarget *rt = texture_storage->get_render_target(rb->render_target);
ERR_FAIL_NULL(rt);
+ bool glow_enabled = false;
+ if (p_environment.is_valid() && rb.is_valid()) {
+ glow_enabled = environment_get_glow_enabled(p_environment);
+ rb->set_glow_enabled(glow_enabled); // ensure our intermediate buffer is available if glow is enabled
+ if (glow_enabled) {
+ // If glow is enabled, we apply tonemapping etc. in post, so disable it during rendering
+ apply_color_adjustments_in_post = true;
+ }
+ }
+
// Assign render data
// Use the format from rendererRD
RenderDataGLES3 render_data;
@@ -2359,6 +2372,13 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
// this should be the same for all cameras..
render_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier();
+ if (rt->color_type == GL_UNSIGNED_INT_2_10_10_10_REV && glow_enabled) {
+ // As our output is in sRGB and we're using 10bit color space, we can fake a little HDR to do glow...
+ render_data.luminance_multiplier = 0.25;
+ } else {
+ render_data.luminance_multiplier = 1.0;
+ }
+
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
render_data.screen_mesh_lod_threshold = 0.0;
} else {
@@ -2519,9 +2539,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, rb->internal_size.x, rb->internal_size.y);
- glCullFace(GL_BACK);
- glEnable(GL_CULL_FACE);
- scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
+ scene_state.reset_gl_state();
// Do depth prepass if it's explicitly enabled
bool use_depth_prepass = config->use_depth_prepass;
@@ -2533,11 +2551,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
RENDER_TIMESTAMP("Depth Prepass");
//pre z pass
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
+ scene_state.enable_gl_depth_test(true);
+ scene_state.enable_gl_depth_draw(true);
+ scene_state.enable_gl_blend(false);
glDepthFunc(GL_LEQUAL);
- glDisable(GL_SCISSOR_TEST);
+ scene_state.enable_gl_scissor_test(false);
glColorMask(0, 0, 0, 0);
RasterizerGLES3::clear_depth(1.0);
@@ -2560,21 +2578,19 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
}
glBlendEquation(GL_FUNC_ADD);
-
if (render_data.transparent_bg) {
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ scene_state.enable_gl_blend(true);
} else {
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
- glDisable(GL_BLEND);
+ scene_state.enable_gl_blend(false);
}
scene_state.current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
- glEnable(GL_DEPTH_TEST);
+ scene_state.enable_gl_scissor_test(false);
+ scene_state.enable_gl_depth_test(true);
+ scene_state.enable_gl_depth_draw(true);
glDepthFunc(GL_LEQUAL);
- glDepthMask(GL_TRUE);
- scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
- scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS;
{
GLuint db = GL_COLOR_ATTACHMENT0;
@@ -2589,7 +2605,19 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
if (!keep_color) {
clear_color.a = render_data.transparent_bg ? 0.0f : 1.0f;
glClearBufferfv(GL_COLOR, 0, clear_color.components);
+ } else if (fbo != rt->fbo) {
+ // Need to copy our current contents to our intermediate/MSAA buffer
+ GLES3::CopyEffects *copy_effects = GLES3::CopyEffects::get_singleton();
+
+ scene_state.enable_gl_depth_test(false);
+ scene_state.enable_gl_depth_draw(false);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(rt->view_count > 1 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D, rt->color);
+
+ copy_effects->copy_screen(render_data.luminance_multiplier);
}
+
RENDER_TIMESTAMP("Render Opaque Pass");
uint64_t spec_constant_base_flags = 0;
@@ -2606,26 +2634,28 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
if (render_data.environment.is_valid() && environment_get_fog_mode(render_data.environment) == RS::EnvironmentFogMode::ENV_FOG_MODE_DEPTH) {
spec_constant_base_flags |= SceneShaderGLES3::USE_DEPTH_FOG;
}
+
+ if (!apply_color_adjustments_in_post) {
+ spec_constant_base_flags |= SceneShaderGLES3::APPLY_TONEMAPPING;
+
+ // TODO add BCS and Color corrections here once supported.
+ }
}
// Render Opaque Objects.
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, spec_constant_base_flags, use_wireframe);
_render_list_template<PASS_MODE_COLOR>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
- glDepthMask(GL_FALSE);
- scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_DISABLED;
+ scene_state.enable_gl_depth_draw(false);
if (draw_sky) {
RENDER_TIMESTAMP("Render Sky");
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_BLEND);
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
- scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
- scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
+ scene_state.enable_gl_depth_test(true);
+ scene_state.enable_gl_blend(false);
+ scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_BACK);
- _draw_sky(render_data.environment, render_data.cam_projection, render_data.cam_transform, sky_energy_multiplier, p_camera_data->view_count > 1, flip_y);
+ _draw_sky(render_data.environment, render_data.cam_projection, render_data.cam_transform, sky_energy_multiplier, render_data.luminance_multiplier, p_camera_data->view_count > 1, flip_y, apply_color_adjustments_in_post);
}
if (scene_state.used_screen_texture || scene_state.used_depth_texture) {
@@ -2674,7 +2704,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
}
RENDER_TIMESTAMP("Render 3D Transparent Pass");
- glEnable(GL_BLEND);
+ scene_state.enable_gl_blend(true);
//Render transparent pass
RenderListParameters render_list_params_alpha(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, spec_constant_base_flags, use_wireframe);
@@ -2689,7 +2719,10 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
if (rb.is_valid()) {
_render_buffers_debug_draw(rb, p_shadow_atlas, fbo);
}
- glDisable(GL_BLEND);
+
+ // Reset stuff that may trip up the next process.
+ scene_state.reset_gl_state();
+ glUseProgram(0);
_render_post_processing(&render_data);
@@ -2700,6 +2733,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_render_data) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Glow *glow = GLES3::Glow::get_singleton();
+ GLES3::PostEffects *post_effects = GLES3::PostEffects::get_singleton();
+
Ref<RenderSceneBuffersGLES3> rb = p_render_data->render_buffers;
ERR_FAIL_COND(rb.is_null());
@@ -2714,6 +2750,26 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
GLuint fbo_int = rb->get_internal_fbo();
GLuint fbo_rt = texture_storage->render_target_get_fbo(render_target); // TODO if MSAA 2D is enabled and we're not using rt_msaa, get 2D render target here.
+ // Check if we have glow enabled and if so, check if our buffers were allocated
+ bool glow_enabled = false;
+ float glow_intensity = 1.0;
+ float glow_bloom = 0.0;
+ float glow_hdr_bleed_threshold = 1.0;
+ float glow_hdr_bleed_scale = 2.0;
+ float glow_hdr_luminance_cap = 12.0;
+ if (p_render_data->environment.is_valid()) {
+ glow_enabled = environment_get_glow_enabled(p_render_data->environment);
+ glow_intensity = environment_get_glow_intensity(p_render_data->environment);
+ glow_bloom = environment_get_glow_bloom(p_render_data->environment);
+ glow_hdr_bleed_threshold = environment_get_glow_hdr_bleed_threshold(p_render_data->environment);
+ glow_hdr_bleed_scale = environment_get_glow_hdr_bleed_scale(p_render_data->environment);
+ glow_hdr_luminance_cap = environment_get_glow_hdr_luminance_cap(p_render_data->environment);
+ }
+
+ if (glow_enabled) {
+ rb->check_glow_buffers();
+ }
+
if (view_count == 1) {
// Resolve if needed.
if (fbo_msaa_3d != 0 && msaa3d_needs_resolve) {
@@ -2729,23 +2785,41 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, internal_size.x, internal_size.y, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
+ // Rendered to intermediate buffer, must copy to our render target
if (fbo_int != 0) {
- // TODO If we have glow or other post processing, we upscale only depth here, post processing will also do scaling.
+ // Apply glow/bloom if requested? then populate our glow buffers
+ GLuint color = fbo_int != 0 ? rb->get_internal_color() : texture_storage->render_target_get_color(render_target);
+ const GLES3::Glow::GLOWLEVEL *glow_buffers = nullptr;
+ if (glow_enabled) {
+ glow_buffers = rb->get_glow_buffers();
+
+ glow->set_luminance_multiplier(p_render_data->luminance_multiplier);
+
+ glow->set_intensity(glow_intensity);
+ glow->set_glow_bloom(glow_bloom);
+ glow->set_glow_hdr_bleed_threshold(glow_hdr_bleed_threshold);
+ glow->set_glow_hdr_bleed_scale(glow_hdr_bleed_scale);
+ glow->set_glow_hdr_luminance_cap(glow_hdr_luminance_cap);
+
+ glow->process_glow(color, internal_size, glow_buffers);
+ }
+
+ // Copy color buffer
+ post_effects->post_copy(fbo_rt, target_size, color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity);
+
+ // Copy depth buffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_int);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_rt);
- glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
glBindFramebuffer(GL_FRAMEBUFFER, fbo_rt);
} else if ((fbo_msaa_3d != 0 && msaa3d_needs_resolve) || (fbo_int != 0)) {
// TODO investigate if it's smarter to cache these FBOs
- GLuint fbos[2]; // read and write
- glGenFramebuffers(2, fbos);
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
+ GLuint fbos[3]; // read, write and post
+ glGenFramebuffers(3, fbos);
+ // Resolve if needed.
if (fbo_msaa_3d != 0 && msaa3d_needs_resolve) {
GLuint read_color = rb->get_msaa3d_color();
GLuint read_depth = rb->get_msaa3d_depth();
@@ -2760,6 +2834,9 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
write_depth = texture_storage->render_target_get_depth(render_target);
}
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
+
for (uint32_t v = 0; v < view_count; v++) {
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, read_color, 0, v);
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, read_depth, 0, v);
@@ -2769,25 +2846,53 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
}
}
+ // Rendered to intermediate buffer, must copy to our render target
if (fbo_int != 0) {
- GLuint read_color = rb->get_internal_color();
- GLuint read_depth = rb->get_internal_depth();
+ // Apply glow/bloom if requested? then populate our glow buffers
+ const GLES3::Glow::GLOWLEVEL *glow_buffers = nullptr;
+ GLuint source_color = fbo_int != 0 ? rb->get_internal_color() : texture_storage->render_target_get_color(render_target);
+
+ if (glow_enabled) {
+ glow_buffers = rb->get_glow_buffers();
+
+ glow->set_luminance_multiplier(p_render_data->luminance_multiplier);
+
+ glow->set_intensity(glow_intensity);
+ glow->set_glow_bloom(glow_bloom);
+ glow->set_glow_hdr_bleed_threshold(glow_hdr_bleed_threshold);
+ glow->set_glow_hdr_bleed_scale(glow_hdr_bleed_scale);
+ glow->set_glow_hdr_luminance_cap(glow_hdr_luminance_cap);
+ }
+
GLuint write_color = texture_storage->render_target_get_color(render_target);
+
+ for (uint32_t v = 0; v < view_count; v++) {
+ if (glow_enabled) {
+ glow->process_glow(source_color, internal_size, glow_buffers, v, true);
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[2]);
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
+ post_effects->post_copy(fbos[2], target_size, source_color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, v, true);
+ }
+
+ // Copy depth
+ GLuint read_depth = rb->get_internal_depth();
GLuint write_depth = texture_storage->render_target_get_depth(render_target);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
+
for (uint32_t v = 0; v < view_count; v++) {
- glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, read_color, 0, v);
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, read_depth, 0, v);
- glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, write_depth, 0, v);
- glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
}
glBindFramebuffer(GL_FRAMEBUFFER, fbo_rt);
- glDeleteFramebuffers(2, fbos);
+ glDeleteFramebuffers(3, fbos);
}
}
@@ -2884,33 +2989,15 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
if constexpr (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
- if (scene_state.current_depth_test != shader->depth_test) {
- if (shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED) {
- glDisable(GL_DEPTH_TEST);
- } else {
- glEnable(GL_DEPTH_TEST);
- }
- scene_state.current_depth_test = shader->depth_test;
- }
+ scene_state.enable_gl_depth_test(shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_ENABLED);
}
if constexpr (p_pass_mode != PASS_MODE_SHADOW) {
- if (scene_state.current_depth_draw != shader->depth_draw) {
- switch (shader->depth_draw) {
- case GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE: {
- glDepthMask((p_pass_mode == PASS_MODE_COLOR && !GLES3::Config::get_singleton()->use_depth_prepass) ||
- p_pass_mode == PASS_MODE_DEPTH);
- } break;
- case GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS: {
- glDepthMask(GL_TRUE);
- } break;
- case GLES3::SceneShaderData::DEPTH_DRAW_DISABLED: {
- glDepthMask(GL_FALSE);
- } break;
- }
+ if (shader->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE) {
+ scene_state.enable_gl_depth_draw((p_pass_mode == PASS_MODE_COLOR && !GLES3::Config::get_singleton()->use_depth_prepass) || p_pass_mode == PASS_MODE_DEPTH);
+ } else {
+ scene_state.enable_gl_depth_draw(shader->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS);
}
-
- scene_state.current_depth_draw = shader->depth_draw;
}
bool uses_additive_lighting = (inst->light_passes.size() + p_render_data->directional_shadow_count) > 0;
@@ -2937,7 +3024,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
if (uses_additive_lighting && pass == 1 && !p_render_data->transparent_bg) {
// Enable blending if in opaque pass and not already enabled.
- glEnable(GL_BLEND);
+ scene_state.enable_gl_blend(true);
}
if (pass < int32_t(inst->light_passes.size())) {
RID light_instance_rid = inst->light_passes[pass].light_instance_rid;
@@ -3017,18 +3104,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
}
- if (scene_state.cull_mode != cull_mode) {
- if (cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
- glDisable(GL_CULL_FACE);
- } else {
- if (scene_state.cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
- // Last time was disabled, so enable and set proper face.
- glEnable(GL_CULL_FACE);
- }
- glCullFace(cull_mode == GLES3::SceneShaderData::CULL_FRONT ? GL_FRONT : GL_BACK);
- }
- scene_state.cull_mode = cull_mode;
- }
+ scene_state.set_gl_cull_mode(cull_mode);
RS::PrimitiveType primitive = surf->primitive;
if (shader->uses_point_size) {
@@ -3417,7 +3493,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
if constexpr (p_pass_mode == PASS_MODE_COLOR) {
if (uses_additive_lighting && !p_render_data->transparent_bg) {
// Disable additive blending if enabled for additive lights.
- glDisable(GL_BLEND);
+ scene_state.enable_gl_blend(false);
}
}
}
@@ -3480,14 +3556,10 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider,
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
+ scene_state.reset_gl_state();
+ scene_state.enable_gl_depth_test(true);
+ scene_state.enable_gl_depth_draw(true);
glDepthFunc(GL_LESS);
- glDisable(GL_SCISSOR_TEST);
- glCullFace(GL_BACK);
- glEnable(GL_CULL_FACE);
- scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
glDrawBuffers(0, nullptr);
@@ -3530,14 +3602,10 @@ void RasterizerSceneGLES3::_render_uv2(const PagedArray<RenderGeometryInstance *
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
+ scene_state.reset_gl_state();
+ scene_state.enable_gl_depth_test(true);
+ scene_state.enable_gl_depth_draw(true);
glDepthFunc(GL_LESS);
- glDisable(GL_SCISSOR_TEST);
- glCullFace(GL_BACK);
- glEnable(GL_CULL_FACE);
- scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
TightLocalVector<GLenum> draw_buffers;
draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
@@ -3629,10 +3697,9 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES
glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas_fb);
glViewport(0, 0, shadow_atlas_size, shadow_atlas_size);
glActiveTexture(GL_TEXTURE0);
- glDepthMask(GL_TRUE);
+ scene_state.enable_gl_depth_draw(true);
glDepthFunc(GL_ALWAYS);
- glDisable(GL_CULL_FACE);
- scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
+ scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED);
// Loop through quadrants and copy shadows over.
for (int quadrant = 0; quadrant < 4; quadrant++) {
@@ -3706,8 +3773,8 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
+ scene_state.enable_gl_depth_test(false);
+ scene_state.enable_gl_depth_draw(false);
copy_effects->copy_to_rect(Rect2(Vector2(), Vector2(0.5, 0.5)));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index ed59aba266..53ecd19895 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -127,6 +127,8 @@ struct RenderDataGLES3 {
uint32_t spot_light_count = 0;
uint32_t omni_light_count = 0;
+ float luminance_multiplier = 1.0;
+
RenderingMethod::RenderInfo *render_info = nullptr;
/* Shadow data */
@@ -404,15 +406,14 @@ private:
float fog_height_density;
float fog_depth_curve;
- float pad;
+ float fog_sun_scatter;
float fog_depth_begin;
float fog_light_color[3];
float fog_depth_end;
- float fog_sun_scatter;
-
float shadow_bias;
+ float luminance_multiplier;
uint32_t camera_visible_layers;
bool pancake_shadows;
};
@@ -442,10 +443,85 @@ private:
bool used_depth_prepass = false;
GLES3::SceneShaderData::BlendMode current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
- GLES3::SceneShaderData::DepthDraw current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE;
- GLES3::SceneShaderData::DepthTest current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_DISABLED;
GLES3::SceneShaderData::Cull cull_mode = GLES3::SceneShaderData::CULL_BACK;
+ bool current_blend_enabled = false;
+ bool current_depth_draw_enabled = false;
+ bool current_depth_test_enabled = false;
+ bool current_scissor_test_enabled = false;
+
+ void reset_gl_state() {
+ glDisable(GL_BLEND);
+ current_blend_enabled = false;
+
+ glDisable(GL_SCISSOR_TEST);
+ current_scissor_test_enabled = false;
+
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ cull_mode = GLES3::SceneShaderData::CULL_BACK;
+
+ glDepthMask(GL_FALSE);
+ current_depth_draw_enabled = false;
+ glDisable(GL_DEPTH_TEST);
+ current_depth_test_enabled = false;
+ }
+
+ void set_gl_cull_mode(GLES3::SceneShaderData::Cull p_mode) {
+ if (cull_mode != p_mode) {
+ if (p_mode == GLES3::SceneShaderData::CULL_DISABLED) {
+ glDisable(GL_CULL_FACE);
+ } else {
+ if (cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
+ // Last time was disabled, so enable and set proper face.
+ glEnable(GL_CULL_FACE);
+ }
+ glCullFace(p_mode == GLES3::SceneShaderData::CULL_FRONT ? GL_FRONT : GL_BACK);
+ }
+ cull_mode = p_mode;
+ }
+ }
+
+ void enable_gl_blend(bool p_enabled) {
+ if (current_blend_enabled != p_enabled) {
+ if (p_enabled) {
+ glEnable(GL_BLEND);
+ } else {
+ glDisable(GL_BLEND);
+ }
+ current_blend_enabled = p_enabled;
+ }
+ }
+
+ void enable_gl_scissor_test(bool p_enabled) {
+ if (current_scissor_test_enabled != p_enabled) {
+ if (p_enabled) {
+ glEnable(GL_SCISSOR_TEST);
+ } else {
+ glDisable(GL_SCISSOR_TEST);
+ }
+ current_scissor_test_enabled = p_enabled;
+ }
+ }
+
+ void enable_gl_depth_draw(bool p_enabled) {
+ if (current_depth_draw_enabled != p_enabled) {
+ glDepthMask(p_enabled ? GL_TRUE : GL_FALSE);
+ current_depth_draw_enabled = p_enabled;
+ }
+ }
+
+ void enable_gl_depth_test(bool p_enabled) {
+ if (current_depth_test_enabled != p_enabled) {
+ if (p_enabled) {
+ glEnable(GL_DEPTH_TEST);
+ } else {
+ glDisable(GL_DEPTH_TEST);
+ }
+ current_depth_test_enabled = p_enabled;
+ }
+ }
+
bool texscreen_copied = false;
bool used_screen_texture = false;
bool used_normal_texture = false;
@@ -656,9 +732,9 @@ protected:
void _setup_sky(const RenderDataGLES3 *p_render_data, const PagedArray<RID> &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size);
void _invalidate_sky(Sky *p_sky);
void _update_dirty_skys();
- void _update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier);
+ void _update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_sky_energy_multiplier);
void _filter_sky_radiance(Sky *p_sky, int p_base_layer);
- void _draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier, bool p_use_multiview, bool p_flip_y);
+ void _draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_sky_energy_multiplier, float p_luminance_multiplier, bool p_use_multiview, bool p_flip_y, bool p_apply_color_adjustments_in_post);
void _free_sky_data(Sky *p_sky);
// Needed for a single argument calls (material and uv2).
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index 34713e7e29..0292b5d519 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -12,8 +12,10 @@ if "GLES3_GLSL" in env["BUILDERS"]:
# make sure we recompile shaders if include files change
env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#gles3_builders.py"])
+ # compile shaders
+
+ # as we have a few, not yet, converted files we name the ones we want to include:
env.GLES3_GLSL("canvas.glsl")
- env.GLES3_GLSL("copy.glsl")
env.GLES3_GLSL("scene.glsl")
env.GLES3_GLSL("sky.glsl")
env.GLES3_GLSL("cubemap_filter.glsl")
@@ -22,3 +24,10 @@ if "GLES3_GLSL" in env["BUILDERS"]:
env.GLES3_GLSL("particles.glsl")
env.GLES3_GLSL("particles_copy.glsl")
env.GLES3_GLSL("skeleton.glsl")
+
+ # once we finish conversion we can introduce this to cover all files:
+ # for glsl_file in glsl_files:
+ # env.GLES3_GLSL(glsl_file)
+
+
+SConscript("effects/SCsub")
diff --git a/drivers/gles3/shaders/effects/SCsub b/drivers/gles3/shaders/effects/SCsub
new file mode 100644
index 0000000000..38b185ed88
--- /dev/null
+++ b/drivers/gles3/shaders/effects/SCsub
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+Import("env")
+
+if "GLES3_GLSL" in env["BUILDERS"]:
+ # find all include files
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+
+ # find all shader code(all glsl files excluding our include files)
+ glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
+
+ # make sure we recompile shaders if include files change
+ env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#gles3_builders.py"])
+
+ # compile shaders
+ for glsl_file in glsl_files:
+ env.GLES3_GLSL(glsl_file)
diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/effects/copy.glsl
index db63b5d348..06f63ba629 100644
--- a/drivers/gles3/shaders/copy.glsl
+++ b/drivers/gles3/shaders/effects/copy.glsl
@@ -6,6 +6,7 @@ mode_copy_section = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY
mode_copy_section_source = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define MODE_COPY_FROM
mode_copy_section_3d = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define USE_TEXTURE_3D
mode_copy_section_2d_array = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define USE_TEXTURE_2D_ARRAY
+mode_screen = #define MODE_SIMPLE_COPY \n#define MODE_MULTIPLY
mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
mode_mipmap = #define MODE_MIPMAP
mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
@@ -55,6 +56,10 @@ uniform float lod;
uniform vec4 color_in;
#endif
+#ifdef MODE_MULTIPLY
+uniform float multiply;
+#endif
+
#ifdef MODE_GAUSSIAN_BLUR
// Defined in 0-1 coords.
uniform highp vec2 pixel_size;
@@ -105,10 +110,14 @@ void main() {
vec4 color = textureLod(source_2d_array, vec3(uv_interp, layer), lod);
#else
vec4 color = texture(source, uv_interp);
-#endif
+#endif // USE_TEXTURE_3D
+
+#ifdef MODE_MULTIPLY
+ color *= multiply;
+#endif // MODE_MULTIPLY
frag_color = color;
-#endif
+#endif // MODE_SIMPLE_COPY
#ifdef MODE_SIMPLE_COLOR
frag_color = color_in;
diff --git a/drivers/gles3/shaders/effects/glow.glsl b/drivers/gles3/shaders/effects/glow.glsl
new file mode 100644
index 0000000000..09f2f8afcb
--- /dev/null
+++ b/drivers/gles3/shaders/effects/glow.glsl
@@ -0,0 +1,113 @@
+/* clang-format off */
+#[modes]
+
+// Based on Dual filtering glow as explained in Marius Bjørge presentation at Siggraph 2015 "Bandwidth-Efficient Rendering"
+
+mode_filter = #define MODE_FILTER
+mode_downsample = #define MODE_DOWNSAMPLE
+mode_upsample = #define MODE_UPSAMPLE
+
+#[specializations]
+
+USE_MULTIVIEW = false
+
+#[vertex]
+layout(location = 0) in vec2 vertex_attrib;
+
+/* clang-format on */
+
+out vec2 uv_interp;
+
+void main() {
+ uv_interp = vertex_attrib * 0.5 + 0.5;
+ gl_Position = vec4(vertex_attrib, 1.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+/* clang-format on */
+
+#ifdef MODE_FILTER
+#ifdef USE_MULTIVIEW
+uniform sampler2DArray source_color; // texunit:0
+#else
+uniform sampler2D source_color; // texunit:0
+#endif // USE_MULTIVIEW
+uniform float view;
+uniform vec2 pixel_size;
+uniform float luminance_multiplier;
+uniform float glow_bloom;
+uniform float glow_hdr_threshold;
+uniform float glow_hdr_scale;
+uniform float glow_luminance_cap;
+#endif // MODE_FILTER
+
+#ifdef MODE_DOWNSAMPLE
+uniform sampler2D source_color; // texunit:0
+uniform vec2 pixel_size;
+#endif // MODE_DOWNSAMPLE
+
+#ifdef MODE_UPSAMPLE
+uniform sampler2D source_color; // texunit:0
+uniform vec2 pixel_size;
+#endif // MODE_UPSAMPLE
+
+in vec2 uv_interp;
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+#ifdef MODE_FILTER
+ // Note, we read from an image with double resolution, so we average those out
+#ifdef USE_MULTIVIEW
+ vec2 half_pixel = pixel_size * 0.5;
+ vec3 uv = vec3(uv_interp, view);
+ vec3 color = textureLod(source_color, uv, 0.0).rgb * 4.0;
+ color += textureLod(source_color, uv - vec3(half_pixel, 0.0), 0.0).rgb;
+ color += textureLod(source_color, uv + vec3(half_pixel, 0.0), 0.0).rgb;
+ color += textureLod(source_color, uv - vec3(half_pixel.x, -half_pixel.y, 0.0), 0.0).rgb;
+ color += textureLod(source_color, uv + vec3(half_pixel.x, -half_pixel.y, 0.0), 0.0).rgb;
+#else
+ vec2 half_pixel = pixel_size * 0.5;
+ vec2 uv = uv_interp;
+ vec3 color = textureLod(source_color, uv, 0.0).rgb * 4.0;
+ color += textureLod(source_color, uv - half_pixel, 0.0).rgb;
+ color += textureLod(source_color, uv + half_pixel, 0.0).rgb;
+ color += textureLod(source_color, uv - vec2(half_pixel.x, -half_pixel.y), 0.0).rgb;
+ color += textureLod(source_color, uv + vec2(half_pixel.x, -half_pixel.y), 0.0).rgb;
+#endif // USE_MULTIVIEW
+ color /= luminance_multiplier * 8.0;
+
+ float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
+ float feedback = max(smoothstep(glow_hdr_threshold, glow_hdr_threshold + glow_hdr_scale, luminance), glow_bloom);
+
+ color = min(color * feedback, vec3(glow_luminance_cap));
+
+ frag_color = vec4(luminance_multiplier * color, 1.0);
+#endif // MODE_FILTER
+
+#ifdef MODE_DOWNSAMPLE
+ vec2 half_pixel = pixel_size * 0.5;
+ vec4 color = textureLod(source_color, uv_interp, 0.0) * 4.0;
+ color += textureLod(source_color, uv_interp - half_pixel, 0.0);
+ color += textureLod(source_color, uv_interp + half_pixel, 0.0);
+ color += textureLod(source_color, uv_interp - vec2(half_pixel.x, -half_pixel.y), 0.0);
+ color += textureLod(source_color, uv_interp + vec2(half_pixel.x, -half_pixel.y), 0.0);
+ frag_color = color / 8.0;
+#endif // MODE_DOWNSAMPLE
+
+#ifdef MODE_UPSAMPLE
+ vec2 half_pixel = pixel_size * 0.5;
+
+ vec4 color = textureLod(source_color, uv_interp + vec2(-half_pixel.x * 2.0, 0.0), 0.0);
+ color += textureLod(source_color, uv_interp + vec2(-half_pixel.x, half_pixel.y), 0.0) * 2.0;
+ color += textureLod(source_color, uv_interp + vec2(0.0, half_pixel.y * 2.0), 0.0);
+ color += textureLod(source_color, uv_interp + vec2(half_pixel.x, half_pixel.y), 0.0) * 2.0;
+ color += textureLod(source_color, uv_interp + vec2(half_pixel.x * 2.0, 0.0), 0.0);
+ color += textureLod(source_color, uv_interp + vec2(half_pixel.x, -half_pixel.y), 0.0) * 2.0;
+ color += textureLod(source_color, uv_interp + vec2(0.0, -half_pixel.y * 2.0), 0.0);
+ color += textureLod(source_color, uv_interp + vec2(-half_pixel.x, -half_pixel.y), 0.0) * 2.0;
+
+ frag_color = color / 12.0;
+#endif // MODE_UPSAMPLE
+}
diff --git a/drivers/gles3/shaders/effects/post.glsl b/drivers/gles3/shaders/effects/post.glsl
new file mode 100644
index 0000000000..e61171c92a
--- /dev/null
+++ b/drivers/gles3/shaders/effects/post.glsl
@@ -0,0 +1,96 @@
+/* clang-format off */
+#[modes]
+mode_default = #define MODE_DEFAULT
+// mode_glow = #define MODE_GLOW
+
+#[specializations]
+
+USE_MULTIVIEW = false
+USE_GLOW = false
+USE_LUMINANCE_MULTIPLIER = false
+
+#[vertex]
+layout(location = 0) in vec2 vertex_attrib;
+
+/* clang-format on */
+
+out vec2 uv_interp;
+
+void main() {
+ uv_interp = vertex_attrib * 0.5 + 0.5;
+ gl_Position = vec4(vertex_attrib, 1.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+/* clang-format on */
+
+#include "../tonemap_inc.glsl"
+
+#ifdef USE_MULTIVIEW
+uniform sampler2DArray source_color; // texunit:0
+#else
+uniform sampler2D source_color; // texunit:0
+#endif // USE_MULTIVIEW
+
+uniform float view;
+uniform float luminance_multiplier;
+
+#ifdef USE_GLOW
+uniform sampler2D glow_color; // texunit:1
+uniform vec2 pixel_size;
+uniform float glow_intensity;
+
+vec4 get_glow_color(vec2 uv) {
+ vec2 half_pixel = pixel_size * 0.5;
+
+ vec4 color = textureLod(glow_color, uv + vec2(-half_pixel.x * 2.0, 0.0), 0.0);
+ color += textureLod(glow_color, uv + vec2(-half_pixel.x, half_pixel.y), 0.0) * 2.0;
+ color += textureLod(glow_color, uv + vec2(0.0, half_pixel.y * 2.0), 0.0);
+ color += textureLod(glow_color, uv + vec2(half_pixel.x, half_pixel.y), 0.0) * 2.0;
+ color += textureLod(glow_color, uv + vec2(half_pixel.x * 2.0, 0.0), 0.0);
+ color += textureLod(glow_color, uv + vec2(half_pixel.x, -half_pixel.y), 0.0) * 2.0;
+ color += textureLod(glow_color, uv + vec2(0.0, -half_pixel.y * 2.0), 0.0);
+ color += textureLod(glow_color, uv + vec2(-half_pixel.x, -half_pixel.y), 0.0) * 2.0;
+
+ return color / 12.0;
+}
+#endif // USE_GLOW
+
+in vec2 uv_interp;
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+#ifdef USE_MULTIVIEW
+ vec4 color = texture(source_color, vec3(uv_interp, view));
+#else
+ vec4 color = texture(source_color, uv_interp);
+#endif
+
+#ifdef USE_GLOW
+ vec4 glow = get_glow_color(uv_interp) * glow_intensity;
+
+ // Just use softlight...
+ glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f));
+ color.rgb = max((color.rgb + glow.rgb) - (color.rgb * glow.rgb), vec3(0.0));
+#endif // USE_GLOW
+
+#ifdef USE_LUMINANCE_MULTIPLIER
+ color = color / luminance_multiplier;
+#endif
+
+ color.rgb = srgb_to_linear(color.rgb);
+ color.rgb = apply_tonemapping(color.rgb, white);
+ color.rgb = linear_to_srgb(color.rgb);
+
+#ifdef USE_BCS
+ color.rgb = apply_bcs(color.rgb, bcs);
+#endif
+
+#ifdef USE_COLOR_CORRECTION
+ color.rgb = apply_color_correction(color.rgb, color_correction);
+#endif
+
+ frag_color = color;
+}
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 667cbb3d90..2aeec42e15 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -28,6 +28,7 @@ LIGHT_USE_PSSM4 = false
LIGHT_USE_PSSM_BLEND = false
BASE_PASS = true
USE_ADDITIVE_LIGHTING = false
+APPLY_TONEMAPPING = true
// We can only use one type of light per additive pass. This means that if USE_ADDITIVE_LIGHTING is defined, and
// these are false, we are doing a directional light pass.
ADDITIVE_OMNI = false
@@ -185,18 +186,17 @@ layout(std140) uniform SceneData { // ubo:2
uint fog_mode;
float fog_density;
float fog_height;
- float fog_height_density;
+ float fog_height_density;
float fog_depth_curve;
- float pad;
+ float fog_sun_scatter;
float fog_depth_begin;
vec3 fog_light_color;
float fog_depth_end;
- float fog_sun_scatter;
-
float shadow_bias;
+ float luminance_multiplier;
uint camera_visible_layers;
bool pancake_shadows;
}
@@ -676,18 +676,17 @@ layout(std140) uniform SceneData { // ubo:2
uint fog_mode;
float fog_density;
float fog_height;
- float fog_height_density;
+ float fog_height_density;
float fog_depth_curve;
- float pad;
+ float fog_sun_scatter;
float fog_depth_begin;
vec3 fog_light_color;
float fog_depth_end;
- float fog_sun_scatter;
-
float shadow_bias;
+ float luminance_multiplier;
uint camera_visible_layers;
bool pancake_shadows;
}
@@ -1758,7 +1757,9 @@ void main() {
// Tonemap before writing as we are writing to an sRGB framebuffer
frag_color.rgb *= exposure;
+#ifdef APPLY_TONEMAPPING
frag_color.rgb = apply_tonemapping(frag_color.rgb, white);
+#endif
frag_color.rgb = linear_to_srgb(frag_color.rgb);
#ifdef USE_BCS
@@ -1973,7 +1974,9 @@ void main() {
// Tonemap before writing as we are writing to an sRGB framebuffer
additive_light_color *= exposure;
+#ifdef APPLY_TONEMAPPING
additive_light_color = apply_tonemapping(additive_light_color, white);
+#endif
additive_light_color = linear_to_srgb(additive_light_color);
#ifdef USE_BCS
@@ -1986,6 +1989,9 @@ void main() {
frag_color.rgb += additive_light_color;
#endif // USE_ADDITIVE_LIGHTING
+
+ frag_color.rgb *= scene_data.luminance_multiplier;
+
#endif // !RENDER_MATERIAL
-#endif //!MODE_RENDER_DEPTH
+#endif // !MODE_RENDER_DEPTH
}
diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl
index 9f9c22cf6d..b10ea12e6e 100644
--- a/drivers/gles3/shaders/sky.glsl
+++ b/drivers/gles3/shaders/sky.glsl
@@ -12,6 +12,7 @@ mode_cubemap_quarter_res = #define USE_CUBEMAP_PASS \n#define USE_QUARTER_RES_PA
USE_MULTIVIEW = false
USE_INVERTED_Y = true
+APPLY_TONEMAPPING = true
#[vertex]
@@ -103,6 +104,7 @@ uniform mat4 orientation;
uniform vec4 projection;
uniform vec3 position;
uniform float time;
+uniform float sky_energy_multiplier;
uniform float luminance_multiplier;
uniform float fog_aerial_perspective;
@@ -195,12 +197,14 @@ void main() {
}
- color *= luminance_multiplier;
+ color *= sky_energy_multiplier;
// Convert to Linear for tonemapping so color matches scene shader better
color = srgb_to_linear(color);
color *= exposure;
+#ifdef APPLY_TONEMAPPING
color = apply_tonemapping(color, white);
+#endif
color = linear_to_srgb(color);
#ifdef USE_BCS
@@ -211,10 +215,10 @@ void main() {
color = apply_color_correction(color, color_correction);
#endif
- frag_color.rgb = color;
+ frag_color.rgb = color * luminance_multiplier;
frag_color.a = alpha;
#ifdef USE_DEBANDING
- frag_color.rgb += interleaved_gradient_noise(gl_FragCoord.xy) * luminance_multiplier;
+ frag_color.rgb += interleaved_gradient_noise(gl_FragCoord.xy) * sky_energy_multiplier * luminance_multiplier;
#endif
}
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
index 33bb808856..bd96442328 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -47,6 +47,13 @@
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
#endif
+RenderSceneBuffersGLES3::RenderSceneBuffersGLES3() {
+ for (int i = 0; i < 4; i++) {
+ glow.levels[i].color = 0;
+ glow.levels[i].fbo = 0;
+ }
+}
+
RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
free_render_buffer_data();
}
@@ -137,9 +144,22 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
//use_debanding = p_config->get_use_debanding();
view_count = config->multiview_supported ? p_config->get_view_count() : 1;
- ERR_FAIL_COND(view_count == 0);
bool use_multiview = view_count > 1;
+ // Get color format data from our render target so we match those
+ if (render_target.is_valid()) {
+ color_internal_format = texture_storage->render_target_get_color_internal_format(render_target);
+ color_format = texture_storage->render_target_get_color_format(render_target);
+ color_type = texture_storage->render_target_get_color_type(render_target);
+ color_format_size = texture_storage->render_target_get_color_format_size(render_target);
+ } else {
+ // reflection probe? or error?
+ color_internal_format = GL_RGBA8;
+ color_format = GL_RGBA;
+ color_type = GL_UNSIGNED_BYTE;
+ color_format_size = 4;
+ }
+
// Check our scaling mode
if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && internal_size.x == 0 && internal_size.y == 0) {
// Disable, no size set.
@@ -153,14 +173,38 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
}
- bool use_internal_buffer = scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF; // TODO also need this if doing post processing like glow
+ // Check if we support MSAA.
+ if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && internal_size.x == 0 && internal_size.y == 0) {
+ // Disable, no size set.
+ msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
+ } else if (!use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_supported && !config->rt_msaa_supported) {
+ WARN_PRINT_ONCE("MSAA is not supported on this device.");
+ msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
+ } else if (use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_multiview_supported && !config->rt_msaa_multiview_supported) {
+ WARN_PRINT_ONCE("Multiview MSAA is not supported on this device.");
+ msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
+ }
+
+ // We don't create our buffers right away because post effects can be made active at any time and change our buffer configuration.
+}
+
+void RenderSceneBuffersGLES3::_check_render_buffers() {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ ERR_FAIL_COND(view_count == 0);
+
+ bool use_internal_buffer = scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF || glow.glow_enabled;
+ uint32_t depth_format_size = 3;
+ bool use_multiview = view_count > 1;
+
+ if ((!use_internal_buffer || internal3d.color != 0) && (msaa3d.mode == RS::VIEWPORT_MSAA_DISABLED || msaa3d.color != 0)) {
+ // already setup!
+ return;
+ }
+
if (use_internal_buffer) {
// Setup our internal buffer.
- bool is_transparent = texture_storage->render_target_get_transparent(render_target);
- GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
- GLuint color_format = GL_RGBA;
- GLuint color_type = is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
-
GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
// Create our color buffer.
@@ -178,7 +222,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.color, internal_size.x * internal_size.y * view_count * 4, "3D color texture");
+ GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.color, internal_size.x * internal_size.y * view_count * color_format_size, "3D color texture");
// Create our depth buffer.
glGenTextures(1, &internal3d.depth);
@@ -195,7 +239,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.depth, internal_size.x * internal_size.y * view_count * 3, "3D depth texture");
+ GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size, "3D depth texture");
// Create our internal 3D FBO.
// Note that if MSAA is used and our rt_msaa_* extensions are available, this is only used for blitting and effects.
@@ -224,18 +268,6 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
- // Check if we support MSAA.
- if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && internal_size.x == 0 && internal_size.y == 0) {
- // Disable, no size set.
- msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
- } else if (!use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_supported && !config->rt_msaa_supported) {
- WARN_PRINT_ONCE("MSAA is not supported on this device.");
- msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
- } else if (use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_multiview_supported && !config->rt_msaa_multiview_supported) {
- WARN_PRINT_ONCE("Multiview MSAA is not supported on this device.");
- msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
- }
-
if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED) {
// Setup MSAA.
const GLsizei samples[] = { 1, 2, 4, 8 };
@@ -255,9 +287,6 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
msaa3d.needs_resolve = true;
msaa3d.check_fbo_cache = false;
- bool is_transparent = texture_storage->render_target_get_transparent(render_target);
- GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
-
// Create our color buffer.
glGenRenderbuffers(1, &msaa3d.color);
glBindRenderbuffer(GL_RENDERBUFFER, msaa3d.color);
@@ -282,6 +311,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
_clear_msaa3d_buffers();
+ msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
WARN_PRINT("Could not create 3D MSAA buffers, status: " + texture_storage->get_framebuffer_error(status));
}
@@ -293,9 +323,6 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
msaa3d.needs_resolve = true;
msaa3d.check_fbo_cache = false;
- bool is_transparent = texture_storage->render_target_get_transparent(render_target);
- GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
-
// Create our color buffer.
glGenTextures(1, &msaa3d.color);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.color);
@@ -306,7 +333,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, color_internal_format, internal_size.x, internal_size.y, view_count, GL_TRUE);
#endif
- GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.color, internal_size.x * internal_size.y * view_count * 4 * msaa3d.samples, "MSAA 3D color texture");
+ GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.color, internal_size.x * internal_size.y * view_count * color_format_size * msaa3d.samples, "MSAA 3D color texture");
// Create our depth buffer.
glGenTextures(1, &msaa3d.depth);
@@ -318,7 +345,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, GL_TRUE);
#endif
- GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * msaa3d.samples, "MSAA 3D depth texture");
+ GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size * msaa3d.samples, "MSAA 3D depth texture");
// Create our MSAA 3D FBO.
glGenFramebuffers(1, &msaa3d.fbo);
@@ -330,6 +357,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
_clear_msaa3d_buffers();
+ msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
WARN_PRINT("Could not create 3D MSAA buffers, status: " + texture_storage->get_framebuffer_error(status));
}
@@ -358,6 +386,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
_clear_msaa3d_buffers();
+ msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
WARN_PRINT("Could not create 3D MSAA framebuffer, status: " + texture_storage->get_framebuffer_error(status));
}
@@ -435,13 +464,9 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de
glBindFramebuffer(GL_FRAMEBUFFER, backbuffer3d.fbo);
- bool is_transparent = texture_storage->render_target_get_transparent(render_target);
- GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
- GLuint color_format = GL_RGBA;
- GLuint color_type = is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
-
bool use_multiview = view_count > 1 && GLES3::Config::get_singleton()->multiview_supported;
GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
+ uint32_t depth_format_size = 3;
if (backbuffer3d.color == 0 && p_need_color) {
glGenTextures(1, &backbuffer3d.color);
@@ -458,7 +483,7 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.color, internal_size.x * internal_size.y * view_count * 4, "3D Back buffer color texture");
+ GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.color, internal_size.x * internal_size.y * view_count * color_format_size, "3D Back buffer color texture");
#ifndef IOS_ENABLED
if (use_multiview) {
@@ -486,7 +511,7 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.depth, internal_size.x * internal_size.y * view_count * 3, "3D back buffer depth texture");
+ GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size, "3D back buffer depth texture");
#ifndef IOS_ENABLED
if (use_multiview) {
@@ -526,21 +551,101 @@ void RenderSceneBuffersGLES3::_clear_back_buffers() {
}
}
+void RenderSceneBuffersGLES3::set_glow_enabled(bool p_glow_enabled) {
+ if (glow.glow_enabled != p_glow_enabled) {
+ glow.glow_enabled = p_glow_enabled;
+
+ // Clear our main buffers, this can impact them.
+ _clear_msaa3d_buffers();
+ _clear_intermediate_buffers();
+ }
+}
+
+void RenderSceneBuffersGLES3::check_glow_buffers() {
+ if (glow.levels[0].color != 0) {
+ // already have these setup..
+ return;
+ }
+
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ Size2i level_size = internal_size;
+ for (int i = 0; i < 4; i++) {
+ level_size.x = MAX(level_size.x >> 1, 4);
+ level_size.y = MAX(level_size.y >> 1, 4);
+
+ glow.levels[i].size = level_size;
+
+ // Create our texture
+ glGenTextures(1, &glow.levels[i].color);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, glow.levels[i].color);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, level_size.x, level_size.y, 0, color_format, color_type, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+
+ GLES3::Utilities::get_singleton()->texture_allocated_data(glow.levels[i].color, level_size.x * level_size.y * color_format_size, String("Glow buffer ") + String::num_int64(i));
+
+ // Create our FBO
+ glGenFramebuffers(1, &glow.levels[i].fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, glow.levels[i].fbo);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glow.levels[i].color, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ WARN_PRINT("Could not create glow buffers, status: " + texture_storage->get_framebuffer_error(status));
+ _clear_glow_buffers();
+ break;
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+void RenderSceneBuffersGLES3::_clear_glow_buffers() {
+ for (int i = 0; i < 4; i++) {
+ if (glow.levels[i].fbo != 0) {
+ glDeleteFramebuffers(1, &glow.levels[i].fbo);
+ glow.levels[i].fbo = 0;
+ }
+
+ if (glow.levels[i].color != 0) {
+ GLES3::Utilities::get_singleton()->texture_free_data(glow.levels[i].color);
+ glow.levels[i].color = 0;
+ }
+ }
+}
+
void RenderSceneBuffersGLES3::free_render_buffer_data() {
_clear_msaa3d_buffers();
_clear_intermediate_buffers();
_clear_back_buffers();
+ _clear_glow_buffers();
}
GLuint RenderSceneBuffersGLES3::get_render_fbo() {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLuint rt_fbo = 0;
+ _check_render_buffers();
+
if (msaa3d.check_fbo_cache) {
GLuint color = texture_storage->render_target_get_color(render_target);
GLuint depth = texture_storage->render_target_get_depth(render_target);
rt_fbo = _rt_get_cached_fbo(color, depth, msaa3d.samples, view_count);
+ if (rt_fbo == 0) {
+ // Somehow couldn't obtain this? Just render without MSAA.
+ rt_fbo = texture_storage->render_target_get_fbo(render_target);
+ }
} else if (msaa3d.fbo != 0) {
// We have an MSAA fbo, render to our MSAA buffer
return msaa3d.fbo;
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
index 39aa1fb973..8d03d3438d 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.h
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -33,6 +33,7 @@
#ifdef GLES3_ENABLED
+#include "drivers/gles3/effects/glow.h"
#include "servers/rendering/storage/render_scene_buffers.h"
#include "platform_gl.h"
@@ -52,6 +53,12 @@ public:
RID render_target;
+ // Color format details from our render target
+ GLuint color_internal_format = GL_RGBA8;
+ GLuint color_format = GL_RGBA;
+ GLuint color_type = GL_UNSIGNED_BYTE;
+ uint32_t color_format_size = 4;
+
struct FBDEF {
GLuint color = 0;
GLuint depth = 0;
@@ -74,31 +81,24 @@ public:
FBDEF backbuffer3d; // our back buffer
- // Built-in textures used for ping pong image processing and blurring.
- struct Blur {
- RID texture;
-
- struct Mipmap {
- RID texture;
- int width;
- int height;
- GLuint fbo;
- };
-
- Vector<Mipmap> mipmaps;
- };
-
- Blur blur[2]; //the second one starts from the first mipmap
+ // Buffers for our glow implementation
+ struct GLOW {
+ bool glow_enabled = false;
+ GLES3::Glow::GLOWLEVEL levels[4];
+ } glow;
private:
+ void _check_render_buffers();
void _clear_msaa3d_buffers();
void _clear_intermediate_buffers();
void _clear_back_buffers();
+ void _clear_glow_buffers();
void _rt_attach_textures(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count);
GLuint _rt_get_cached_fbo(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count);
public:
+ RenderSceneBuffersGLES3();
virtual ~RenderSceneBuffersGLES3();
virtual void configure(const RenderSceneBuffersConfiguration *p_config) override;
@@ -109,19 +109,45 @@ public:
void free_render_buffer_data();
void check_backbuffer(bool p_need_color, bool p_need_depth); // Check if we need to initialize our backbuffer.
+ void check_glow_buffers(); // Check if we need to initialise our glow buffers.
GLuint get_render_fbo();
- GLuint get_msaa3d_fbo() const { return msaa3d.fbo; }
- GLuint get_msaa3d_color() const { return msaa3d.color; }
- GLuint get_msaa3d_depth() const { return msaa3d.depth; }
- bool get_msaa_needs_resolve() const { return msaa3d.needs_resolve; }
- GLuint get_internal_fbo() const { return internal3d.fbo; }
- GLuint get_internal_color() const { return internal3d.color; }
- GLuint get_internal_depth() const { return internal3d.depth; }
+ GLuint get_msaa3d_fbo() {
+ _check_render_buffers();
+ return msaa3d.fbo;
+ }
+ GLuint get_msaa3d_color() {
+ _check_render_buffers();
+ return msaa3d.color;
+ }
+ GLuint get_msaa3d_depth() {
+ _check_render_buffers();
+ return msaa3d.depth;
+ }
+ bool get_msaa_needs_resolve() {
+ _check_render_buffers();
+ return msaa3d.needs_resolve;
+ }
+ GLuint get_internal_fbo() {
+ _check_render_buffers();
+ return internal3d.fbo;
+ }
+ GLuint get_internal_color() {
+ _check_render_buffers();
+ return internal3d.color;
+ }
+ GLuint get_internal_depth() {
+ _check_render_buffers();
+ return internal3d.depth;
+ }
GLuint get_backbuffer_fbo() const { return backbuffer3d.fbo; }
GLuint get_backbuffer() const { return backbuffer3d.color; }
GLuint get_backbuffer_depth() const { return backbuffer3d.depth; }
+ bool get_glow_enabled() const { return glow.glow_enabled; }
+ void set_glow_enabled(bool p_glow_enabled);
+ const GLES3::Glow::GLOWLEVEL *get_glow_buffers() const { return &glow.levels[0]; }
+
// Getters
_FORCE_INLINE_ RID get_render_target() const { return render_target; }
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index bd4793f4dc..e9df3c6fc8 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1981,10 +1981,25 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
Config *config = Config::get_singleton();
- rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2;
- rt->color_format = GL_RGBA;
- rt->color_type = rt->is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
- rt->image_format = Image::FORMAT_RGBA8;
+ if (rt->hdr) {
+ rt->color_internal_format = GL_RGBA16F;
+ rt->color_format = GL_RGBA;
+ rt->color_type = GL_FLOAT;
+ rt->color_format_size = 8;
+ rt->image_format = Image::FORMAT_RGBAF;
+ } else if (rt->is_transparent) {
+ rt->color_internal_format = GL_RGBA8;
+ rt->color_format = GL_RGBA;
+ rt->color_type = GL_UNSIGNED_BYTE;
+ rt->color_format_size = 4;
+ rt->image_format = Image::FORMAT_RGBA8;
+ } else {
+ rt->color_internal_format = GL_RGB10_A2;
+ rt->color_format = GL_RGBA;
+ rt->color_type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ rt->color_format_size = 4;
+ rt->image_format = Image::FORMAT_RGBA8;
+ }
glDisable(GL_SCISSOR_TEST);
glColorMask(1, 1, 1, 1);
@@ -2023,7 +2038,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
texture->gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
texture->gl_set_repeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- GLES3::Utilities::get_singleton()->texture_allocated_data(rt->color, rt->size.x * rt->size.y * rt->view_count * 4, "Render target color texture");
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->color, rt->size.x * rt->size.y * rt->view_count * rt->color_format_size, "Render target color texture");
}
#ifndef IOS_ENABLED
if (use_multiview) {
@@ -2194,7 +2209,7 @@ void GLES3::TextureStorage::check_backbuffer(RenderTarget *rt, const bool uses_s
} else {
glTexImage2D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
}
- GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, rt->size.x * rt->size.y * rt->view_count * 4, "Render target backbuffer color texture (3D)");
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, rt->size.x * rt->size.y * rt->view_count * rt->color_format_size, "Render target backbuffer color texture (3D)");
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -2548,6 +2563,54 @@ RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) con
return rt->msaa;
}
+void TextureStorage::render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL(rt);
+ ERR_FAIL_COND(rt->direct_to_screen);
+ if (p_use_hdr_2d == rt->hdr) {
+ return;
+ }
+
+ _clear_render_target(rt);
+ rt->hdr = p_use_hdr_2d;
+ _update_render_target(rt);
+}
+
+bool TextureStorage::render_target_is_using_hdr(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL_V(rt, false);
+
+ return rt->hdr;
+}
+
+GLuint TextureStorage::render_target_get_color_internal_format(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL_V(rt, GL_RGBA8);
+
+ return rt->color_internal_format;
+}
+
+GLuint TextureStorage::render_target_get_color_format(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL_V(rt, GL_RGBA);
+
+ return rt->color_format;
+}
+
+GLuint TextureStorage::render_target_get_color_type(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL_V(rt, GL_UNSIGNED_BYTE);
+
+ return rt->color_type;
+}
+
+uint32_t TextureStorage::render_target_get_color_format_size(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL_V(rt, 4);
+
+ return rt->color_format_size;
+}
+
void TextureStorage::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL(rt);
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 91bb676711..ef310262c7 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -347,9 +347,11 @@ struct RenderTarget {
GLuint backbuffer = 0;
GLuint backbuffer_depth = 0;
+ bool hdr = false; // For Compatibility this effects both 2D and 3D rendering!
GLuint color_internal_format = GL_RGBA8;
GLuint color_format = GL_RGBA;
GLuint color_type = GL_UNSIGNED_BYTE;
+ uint32_t color_format_size = 4;
Image::Format image_format = Image::FORMAT_RGBA8;
GLuint sdf_texture_write = 0;
@@ -631,14 +633,19 @@ public:
virtual void render_target_set_msaa_needs_resolve(RID p_render_target, bool p_needs_resolve) override {}
virtual bool render_target_get_msaa_needs_resolve(RID p_render_target) const override { return false; }
virtual void render_target_do_msaa_resolve(RID p_render_target) override {}
- virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) override {}
- virtual bool render_target_is_using_hdr(RID p_render_target) const override { return false; }
+ virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) override;
+ virtual bool render_target_is_using_hdr(RID p_render_target) const override;
// new
void render_target_set_as_unused(RID p_render_target) override {
render_target_clear_used(p_render_target);
}
+ GLuint render_target_get_color_internal_format(RID p_render_target) const;
+ GLuint render_target_get_color_format(RID p_render_target) const;
+ GLuint render_target_get_color_type(RID p_render_target) const;
+ uint32_t render_target_get_color_format_size(RID p_render_target) const;
+
void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override;
bool render_target_is_clear_requested(RID p_render_target) override;
Color render_target_get_clear_request_color(RID p_render_target) override;