소스 검색

Merge pull request #61164 from clayjohn/GLES3-2D

Rémi Verschelde 3 년 전
부모
커밋
a19e02e8d8

+ 1 - 0
drivers/gles3/SCsub

@@ -6,3 +6,4 @@ env.add_source_files(env.drivers_sources, "*.cpp")
 
 SConscript("shaders/SCsub")
 SConscript("storage/SCsub")
+SConscript("effects/SCsub")

+ 5 - 0
drivers/gles3/effects/SCsub

@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.drivers_sources, "*.cpp")

+ 164 - 0
drivers/gles3/effects/copy_effects.cpp

@@ -0,0 +1,164 @@
+/*************************************************************************/
+/*  copy_effects.cpp                                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 "copy_effects.h"
+
+using namespace GLES3;
+
+CopyEffects *CopyEffects::singleton = nullptr;
+
+CopyEffects *CopyEffects::get_singleton() {
+	return singleton;
+}
+
+CopyEffects::CopyEffects() {
+	singleton = this;
+
+	copy.shader.initialize();
+	copy.shader_version = copy.shader.version_create();
+	copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::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
+	}
+
+	{ // Screen Quad
+
+		glGenBuffers(1, &quad);
+		glBindBuffer(GL_ARRAY_BUFFER, quad);
+
+		const float qv[12] = {
+			-1.0f,
+			-1.0f,
+			1.0f,
+			-1.0f,
+			1.0f,
+			1.0f,
+			-1.0f,
+			-1.0f,
+			1.0f,
+			1.0f,
+			-1.0f,
+			1.0f,
+		};
+
+		glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 12, qv, GL_STATIC_DRAW);
+		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+
+		glGenVertexArrays(1, &quad_array);
+		glBindVertexArray(quad_array);
+		glBindBuffer(GL_ARRAY_BUFFER, quad);
+		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
+	}
+}
+
+CopyEffects::~CopyEffects() {
+	singleton = nullptr;
+	glDeleteBuffers(1, &screen_triangle);
+	glDeleteVertexArrays(1, &screen_triangle_array);
+	glDeleteBuffers(1, &quad);
+	glDeleteVertexArrays(1, &quad_array);
+}
+
+void CopyEffects::copy_to_rect(const Rect2i &p_rect) {
+	copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
+	copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
+	glBindVertexArray(quad_array);
+	glDrawArrays(GL_TRIANGLES, 0, 6);
+	glBindVertexArray(0);
+}
+
+void CopyEffects::copy_screen() {
+	copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);
+	glBindVertexArray(screen_triangle_array);
+	glDrawArrays(GL_TRIANGLES, 0, 3);
+	glBindVertexArray(0);
+}
+
+void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
+	GLuint framebuffers[2];
+	glGenFramebuffers(2, framebuffers);
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
+	glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, 0);
+
+	Rect2i source_region = p_region;
+	Rect2i dest_region = p_region;
+	for (int i = 1; i < p_mipmap_count; i++) {
+		dest_region.position.x >>= 1;
+		dest_region.position.y >>= 1;
+		dest_region.size.x = MAX(1, dest_region.size.x >> 1);
+		dest_region.size.y = MAX(1, dest_region.size.y >> 1);
+		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[i % 2]);
+		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, i);
+		glBlitFramebuffer(source_region.position.x, source_region.position.y, source_region.size.x, source_region.size.y,
+				dest_region.position.x, dest_region.position.y, dest_region.size.x, dest_region.size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+		glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[i % 2]);
+		source_region = dest_region;
+	}
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+	glDeleteFramebuffers(2, framebuffers);
+}
+
+void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) {
+	copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
+	copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_region.position.x, p_region.position.y, p_region.size.x, p_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
+	copy.shader.version_set_uniform(CopyShaderGLES3::COLOR_IN, p_color, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
+	glBindVertexArray(quad_array);
+	glDrawArrays(GL_TRIANGLES, 0, 6);
+	glBindVertexArray(0);
+}
+#endif // GLES3_ENABLED

+ 35 - 13
drivers/gles3/texture_loader_gles3.h → drivers/gles3/effects/copy_effects.h

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  texture_loader_gles3.h                                               */
+/*  copy_effects.h                                                       */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -28,24 +28,46 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#ifndef TEXTURE_LOADER_OPENGL_H
-#define TEXTURE_LOADER_OPENGL_H
+#ifndef COPY_GL_H
+#define COPY_GL_H
 
 #ifdef GLES3_ENABLED
 
-#include "core/io/resource_loader.h"
-#include "scene/resources/texture.h"
+#include "../shaders/copy.glsl.gen.h"
+
+namespace GLES3 {
+
+class CopyEffects {
+private:
+	struct Copy {
+		CopyShaderGLES3 shader;
+		RID shader_version;
+	} copy;
+
+	static CopyEffects *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;
+
+	// Use for rect-based effects.
+	GLuint quad = 0;
+	GLuint quad_array = 0;
 
-class ResourceFormatGLES2Texture : public ResourceFormatLoader {
 public:
-	virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
-	virtual void get_recognized_extensions(List<String> *p_extensions) const;
-	virtual bool handles_type(const String &p_type) const;
-	virtual String get_resource_type(const String &p_path) const;
+	static CopyEffects *get_singleton();
+
+	CopyEffects();
+	~CopyEffects();
 
-	virtual ~ResourceFormatGLES2Texture() {}
+	// These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array.
+	void copy_to_rect(const Rect2i &p_rect);
+	void copy_screen();
+	void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
+	void set_color(const Color &p_color, const Rect2i &p_region);
 };
 
-#endif // GLES3_ENABLED
+} //namespace GLES3
 
-#endif // TEXTURE_LOADER_OPENGL_H
+#endif // GLES3_ENABLED
+#endif // !COPY_GL_H

+ 261 - 140
drivers/gles3/rasterizer_canvas_gles3.cpp

@@ -119,12 +119,11 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
 	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
 	GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
 
-	texture_storage->frame.current_rt = nullptr;
-
-	texture_storage->_set_current_render_target(p_to_render_target);
-
 	Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse();
 
+	// Clear out any state that may have been left from the 3D pass.
+	reset_canvas();
+
 	// TODO: Setup Directional Lights
 
 	// TODO: Setup lights
@@ -156,6 +155,9 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
 		state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
 		state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y;
 
+		// TODO: temporary, this should be set at the top of this function
+		glViewport(0, 0, render_target_size.x, render_target_size.y);
+
 		state_buffer.time = state.time;
 		state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel;
 
@@ -177,7 +179,6 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
 		state_buffer.sdf_to_tex[2] = -sdf_tex_rect.position.x / sdf_tex_rect.size.width;
 		state_buffer.sdf_to_tex[3] = -sdf_tex_rect.position.y / sdf_tex_rect.size.height;
 
-		//print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale));
 		state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5);
 		glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_LOCATION, state.canvas_state_buffer);
 		glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), &state_buffer, GL_STREAM_DRAW);
@@ -193,17 +194,100 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
 		state.default_repeat = p_default_repeat;
 	}
 
-	state.current_tex = RID();
-	state.current_tex_ptr = nullptr;
-	state.current_normal = RID();
-	state.current_specular = RID();
-	state.canvas_texscreen_used = false;
-
 	r_sdf_used = false;
 	int item_count = 0;
+	bool backbuffer_cleared = false;
+	bool time_used = false;
+	bool material_screen_texture_found = false;
+	Rect2 back_buffer_rect;
+	bool backbuffer_copy = false;
 
 	Item *ci = p_item_list;
+	Item *canvas_group_owner = nullptr;
+
 	while (ci) {
+		if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
+			backbuffer_copy = true;
+
+			if (ci->copy_back_buffer->full) {
+				back_buffer_rect = Rect2();
+			} else {
+				back_buffer_rect = ci->copy_back_buffer->rect;
+			}
+		}
+
+		// Check material for something that may change flow of rendering, but do not bind for now.
+		RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
+		if (material.is_valid()) {
+			GLES3::CanvasMaterialData *md = static_cast<GLES3::CanvasMaterialData *>(material_storage->material_get_data(material, RS::SHADER_CANVAS_ITEM));
+			if (md && md->shader_data->valid) {
+				if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {
+					if (!material_screen_texture_found) {
+						backbuffer_copy = true;
+						back_buffer_rect = Rect2();
+					}
+				}
+
+				if (md->shader_data->uses_sdf) {
+					r_sdf_used = true;
+				}
+				if (md->shader_data->uses_time) {
+					time_used = true;
+				}
+			}
+		}
+
+		if (ci->canvas_group_owner != nullptr) {
+			if (canvas_group_owner == nullptr) {
+				// Canvas group begins here, render until before this item
+
+				_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+				item_count = 0;
+
+				Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
+
+				if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_OPAQUE) {
+					texture_storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false);
+				} else if (!backbuffer_cleared) {
+					texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0));
+					backbuffer_cleared = true;
+				}
+
+				backbuffer_copy = false;
+				canvas_group_owner = ci->canvas_group_owner; //continue until owner found
+			}
+
+			ci->canvas_group_owner = nullptr; //must be cleared
+		}
+
+		if (!backbuffer_cleared && canvas_group_owner == nullptr && ci->canvas_group != nullptr && !backbuffer_copy) {
+			texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0));
+			backbuffer_cleared = true;
+		}
+
+		if (ci == canvas_group_owner) {
+			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true);
+			item_count = 0;
+
+			if (ci->canvas_group->blur_mipmaps) {
+				texture_storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, ci->global_rect_cache);
+			}
+
+			canvas_group_owner = nullptr;
+		}
+
+		if (backbuffer_copy) {
+			//render anything pending, including clearing if no items
+
+			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+			item_count = 0;
+
+			texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, true);
+
+			backbuffer_copy = false;
+			material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
+		}
+
 		// just add all items for now
 		items[item_count++] = ci;
 
@@ -215,27 +299,52 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
 
 		ci = ci->next;
 	}
+
+	if (time_used) {
+		RenderingServerDefault::redraw_request();
+	}
+
+	// Clear out state used in 2D pass
+	reset_canvas();
 }
 
 void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) {
+	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
 	GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
 	Item *current_clip = nullptr;
 
 	Transform2D canvas_transform_inverse = p_canvas_transform_inverse;
 
-	RID framebuffer;
-	Vector<Color> clear_colors;
-
-	canvas_begin();
+	canvas_begin(p_to_render_target, p_to_backbuffer);
 
 	RID prev_material;
 	uint32_t index = 0;
+	GLES3::CanvasShaderData::BlendMode last_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX;
+	GLES3::CanvasShaderData *shader_data_cache = nullptr;
 
+	state.current_tex = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
+	state.current_tex_ptr = nullptr;
+	state.current_normal = RID();
+	state.current_specular = RID();
+	state.canvas_texscreen_used = false;
 	state.current_shader_version = state.canvas_shader_default_version;
 
 	for (int i = 0; i < p_item_count; i++) {
 		Item *ci = items[i];
 
+		if (current_clip != ci->final_clip_owner) {
+			_render_batch(index);
+
+			current_clip = ci->final_clip_owner;
+			//setup clip
+			if (current_clip) {
+				glEnable(GL_SCISSOR_TEST);
+				glScissor(current_clip->final_clip_rect.position.x, current_clip->final_clip_rect.position.y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y);
+			} else {
+				glDisable(GL_SCISSOR_TEST);
+			}
+		}
+
 		RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
 
 		if (material.is_null() && ci->canvas_group != nullptr) {
@@ -243,6 +352,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
 		}
 
 		if (material != prev_material) {
+			_render_batch(index);
 			GLES3::CanvasMaterialData *material_data = nullptr;
 			if (material.is_valid()) {
 				material_data = static_cast<GLES3::CanvasMaterialData *>(material_storage->material_get_data(material, RS::SHADER_CANVAS_ITEM));
@@ -252,22 +362,86 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
 					// Bind uniform buffer and textures
 					material_data->bind_uniforms();
 					state.current_shader_version = material_data->shader_data->version;
+					shader_data_cache = material_data->shader_data;
 				} else {
 					state.current_shader_version = state.canvas_shader_default_version;
+					shader_data_cache = nullptr;
 				}
 			} else {
 				state.current_shader_version = state.canvas_shader_default_version;
+				shader_data_cache = nullptr;
 			}
 			prev_material = material;
 		}
 
+		GLES3::CanvasShaderData::BlendMode blend_mode = shader_data_cache ? shader_data_cache->blend_mode : GLES3::CanvasShaderData::BLEND_MODE_MIX;
+
+		if (last_blend_mode != blend_mode) {
+			if (last_blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
+				// re-enable it
+				glEnable(GL_BLEND);
+			} else if (blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
+				// disable it
+				glDisable(GL_BLEND);
+			}
+
+			switch (blend_mode) {
+				case GLES3::CanvasShaderData::BLEND_MODE_DISABLED: {
+					// Nothing to do here.
+
+				} break;
+				case GLES3::CanvasShaderData::BLEND_MODE_MIX: {
+					glBlendEquation(GL_FUNC_ADD);
+					if (state.transparent_render_target) {
+						glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+					} else {
+						glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
+					}
+
+				} break;
+				case GLES3::CanvasShaderData::BLEND_MODE_ADD: {
+					glBlendEquation(GL_FUNC_ADD);
+					if (state.transparent_render_target) {
+						glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE);
+					} else {
+						glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
+					}
+
+				} break;
+				case GLES3::CanvasShaderData::BLEND_MODE_SUB: {
+					glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+					if (state.transparent_render_target) {
+						glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE);
+					} else {
+						glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
+					}
+				} break;
+				case GLES3::CanvasShaderData::BLEND_MODE_MUL: {
+					glBlendEquation(GL_FUNC_ADD);
+					if (state.transparent_render_target) {
+						glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO);
+					} else {
+						glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE);
+					}
+
+				} break;
+				case GLES3::CanvasShaderData::BLEND_MODE_PMALPHA: {
+					glBlendEquation(GL_FUNC_ADD);
+					if (state.transparent_render_target) {
+						glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+					} else {
+						glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
+					}
+
+				} break;
+			}
+			last_blend_mode = blend_mode;
+		}
+
 		_render_item(p_to_render_target, ci, canvas_transform_inverse, current_clip, p_lights, index);
 	}
 	// Render last command
-	state.end_batch = true;
 	_render_batch(index);
-
-	canvas_end();
 }
 
 void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index) {
@@ -289,8 +463,7 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 
 	uint32_t base_flags = 0;
 
-	RID last_texture;
-	Size2 texpixel_size;
+	bool reclip = false;
 
 	bool skipping = false;
 
@@ -326,21 +499,20 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 					current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
 				}
 
-				if (rect->texture != last_texture || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_RECT) {
-					state.end_batch = true;
+				if (rect->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_RECT) {
 					_render_batch(r_index);
 
 					state.current_primitive_points = 0;
 					state.current_command = Item::Command::TYPE_RECT;
 				}
-				_bind_canvas_texture(rect->texture, current_filter, current_repeat, r_index, last_texture, texpixel_size);
+				_bind_canvas_texture(rect->texture, current_filter, current_repeat, r_index);
 				GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_QUAD);
 
 				Rect2 src_rect;
 				Rect2 dst_rect;
 
 				if (rect->texture != RID()) {
-					src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
+					src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * state.current_pixel_size, rect->source.size * state.current_pixel_size) : Rect2(0, 0, 1, 1);
 					dst_rect = Rect2(rect->rect.position, rect->rect.size);
 
 					if (dst_rect.size.width < 0) {
@@ -408,8 +580,6 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 				//_render_batch(r_index);
 				r_index++;
 				if (r_index >= state.max_instances_per_batch - 1) {
-					//r_index--;
-					state.end_batch = true;
 					_render_batch(r_index);
 				}
 			} break;
@@ -426,18 +596,18 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 
 				//bind textures
 
-				_bind_canvas_texture(p_draw_list, np->texture, current_filter, current_repeat, index, last_texture, texpixel_size);
+				_bind_canvas_texture(p_draw_list, np->texture, current_filter, current_repeat, index);
 
 				Rect2 src_rect;
 				Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y);
 
 				if (np->texture == RID()) {
-					texpixel_size = Size2(1, 1);
+					state.current_pixel_size = Size2(1, 1);
 					src_rect = Rect2(0, 0, 1, 1);
 
 				} else {
 					if (np->source != Rect2()) {
-						src_rect = Rect2(np->source.position.x * texpixel_size.width, np->source.position.y * texpixel_size.height, np->source.size.x * texpixel_size.width, np->source.size.y * texpixel_size.height);
+						src_rect = Rect2(np->source.position.x * state.current_pixel_size.width, np->source.position.y * state.current_pixel_size.height, np->source.size.x * state.current_pixel_size.width, np->source.size.y * state.current_pixel_size.height);
 						state.instance_data_array[r_index].color_texture_pixel_size[0] = 1.0 / np->source.size.width;
 						state.instance_data_array[r_index].color_texture_pixel_size[1] = 1.0 / np->source.size.height;
 
@@ -478,8 +648,8 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 				RD::get_singleton()->draw_list_draw(p_draw_list, true);
 
 				// Restore if overridden.
-				state.instance_data_array[r_index].color_texture_pixel_size[0] = texpixel_size.x;
-				state.instance_data_array[r_index].color_texture_pixel_size[1] = texpixel_size.y;
+				state.instance_data_array[r_index].color_texture_pixel_size[0] = state.current_pixel_size.x;
+				state.instance_data_array[r_index].color_texture_pixel_size[1] = state.current_pixel_size.y;
 */
 			} break;
 
@@ -489,14 +659,13 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 				PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
 				ERR_CONTINUE(!pb);
 
-				if (polygon->texture != last_texture || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_POLYGON) {
-					state.end_batch = true;
+				if (polygon->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_POLYGON) {
 					_render_batch(r_index);
 
 					state.current_primitive_points = 0;
 					state.current_command = Item::Command::TYPE_POLYGON;
 				}
-				_bind_canvas_texture(polygon->texture, current_filter, current_repeat, r_index, last_texture, texpixel_size);
+				_bind_canvas_texture(polygon->texture, current_filter, current_repeat, r_index);
 				GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_ATTRIBUTES);
 
 				state.current_primitive = polygon->primitive;
@@ -549,13 +718,12 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 			case Item::Command::TYPE_PRIMITIVE: {
 				const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
 
-				if (last_texture != default_canvas_texture || state.current_primitive_points != primitive->point_count || state.current_command != Item::Command::TYPE_PRIMITIVE) {
-					state.end_batch = true;
+				if (state.current_primitive_points != primitive->point_count || state.current_command != Item::Command::TYPE_PRIMITIVE) {
 					_render_batch(r_index);
 					state.current_primitive_points = primitive->point_count;
 					state.current_command = Item::Command::TYPE_PRIMITIVE;
 				}
-				_bind_canvas_texture(RID(), current_filter, current_repeat, r_index, last_texture, texpixel_size);
+				_bind_canvas_texture(RID(), current_filter, current_repeat, r_index);
 				GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_PRIMITIVE);
 
 				for (uint32_t j = 0; j < MIN(3u, primitive->point_count); j++) {
@@ -589,8 +757,6 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 					r_index++;
 				}
 				if (r_index >= state.max_instances_per_batch - 1) {
-					//r_index--;
-					state.end_batch = true;
 					_render_batch(r_index);
 				}
 			} break;
@@ -643,14 +809,13 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 					break;
 				}
 
-				if (texture != last_texture || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_PRIMITIVE) {
-					state.end_batch = true;
+				if (texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_PRIMITIVE) {
 					_render_batch(r_index);
 					state.current_primitive_points = 0;
 					state.current_command = c->type;
 				}
 
-				_bind_canvas_texture(texture, current_filter, current_repeat, r_index, last_texture, texpixel_size);
+				_bind_canvas_texture(texture, current_filter, current_repeat, r_index);
 
 				uint32_t surf_count = storage->mesh_get_surface_count(mesh);
 
@@ -684,20 +849,19 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 			} break;
 
 			case Item::Command::TYPE_CLIP_IGNORE: {
-				/*
 				const Item::CommandClipIgnore *ci = static_cast<const Item::CommandClipIgnore *>(c);
 				if (current_clip) {
 					if (ci->ignore != reclip) {
 						if (ci->ignore) {
-							RD::get_singleton()->draw_list_disable_scissor(p_draw_list);
+							glDisable(GL_SCISSOR_TEST);
 							reclip = true;
 						} else {
-							RD::get_singleton()->draw_list_enable_scissor(p_draw_list, current_clip->final_clip_rect);
+							// Scissor area is already set
+							glEnable(GL_SCISSOR_TEST);
 							reclip = false;
 						}
 					}
 				}
-				*/
 			} break;
 			case Item::Command::TYPE_ANIMATION_SLICE: {
 				/*
@@ -713,10 +877,15 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
 
 		c = c->next;
 	}
+
+	if (current_clip && reclip) {
+		//will make it re-enable clipping if needed afterwards
+		current_clip = nullptr;
+	}
 }
 
 void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
-	if (state.end_batch && r_index > 0) {
+	if (r_index > 0) {
 		// If the previous operation is not done yet, allocate a new buffer
 		if (state.fences[state.current_buffer] != GLsync()) {
 			GLint syncStatus;
@@ -748,7 +917,6 @@ void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
 
 		state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
 		state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
-		state.end_batch = false;
 		//copy the new data into the base of the batch
 		for (int i = 0; i < 4; i++) {
 			state.instance_data_array[0].modulation[i] = state.instance_data_array[r_index].modulation[i];
@@ -771,27 +939,6 @@ void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
 	}
 }
 
-// TODO maybe dont use
-void RasterizerCanvasGLES3::_end_batch(const uint32_t p_index) {
-	for (int i = 0; i < 4; i++) {
-		state.instance_data_array[p_index].modulation[i] = 0.0;
-		state.instance_data_array[p_index].ninepatch_margins[i] = 0.0;
-		state.instance_data_array[p_index].src_rect[i] = 0.0;
-		state.instance_data_array[p_index].dst_rect[i] = 0.0;
-	}
-	state.instance_data_array[p_index].flags = uint32_t(0);
-	state.instance_data_array[p_index].color_texture_pixel_size[0] = 0.0;
-	state.instance_data_array[p_index].color_texture_pixel_size[1] = 0.0;
-
-	state.instance_data_array[p_index].pad[0] = 0.0;
-	state.instance_data_array[p_index].pad[1] = 0.0;
-
-	state.instance_data_array[p_index].lights[0] = uint32_t(0);
-	state.instance_data_array[p_index].lights[1] = uint32_t(0);
-	state.instance_data_array[p_index].lights[2] = uint32_t(0);
-	state.instance_data_array[p_index].lights[3] = uint32_t(0);
-}
-
 RID RasterizerCanvasGLES3::light_create() {
 	return RID();
 }
@@ -831,49 +978,56 @@ bool RasterizerCanvasGLES3::free(RID p_rid) {
 void RasterizerCanvasGLES3::update() {
 }
 
-void RasterizerCanvasGLES3::canvas_begin() {
+void RasterizerCanvasGLES3::canvas_begin(RID p_to_render_target, bool p_to_backbuffer) {
 	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+	GLES3::Config *config = GLES3::Config::get_singleton();
 
-	state.using_transparent_rt = false;
+	GLES3::RenderTarget *render_target = texture_storage->get_render_target(p_to_render_target);
 
-	if (texture_storage->frame.current_rt) {
-		glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->frame.current_rt->fbo);
-		state.using_transparent_rt = texture_storage->frame.current_rt->flags[GLES3::TextureStorage::RENDER_TARGET_TRANSPARENT];
+	if (p_to_backbuffer) {
+		glBindFramebuffer(GL_FRAMEBUFFER, render_target->backbuffer_fbo);
+		glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 4);
+		GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
+		glBindTexture(GL_TEXTURE_2D, tex->tex_id);
+	} else {
+		glBindFramebuffer(GL_FRAMEBUFFER, render_target->fbo);
+		glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 4);
+		glBindTexture(GL_TEXTURE_2D, render_target->backbuffer);
+	}
+
+	if (render_target->is_transparent) {
+		state.transparent_render_target = true;
+		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+	} else {
+		state.transparent_render_target = false;
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	}
 
-	if (texture_storage->frame.current_rt && texture_storage->frame.current_rt->clear_requested) {
-		const Color &col = texture_storage->frame.current_rt->clear_color;
+	if (render_target && render_target->clear_requested) {
+		const Color &col = render_target->clear_color;
 		glClearColor(col.r, col.g, col.b, col.a);
 
 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-		texture_storage->frame.current_rt->clear_requested = false;
+		render_target->clear_requested = false;
 	}
 
-	reset_canvas();
-
 	glActiveTexture(GL_TEXTURE0);
 	GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
 	glBindTexture(GL_TEXTURE_2D, tex->tex_id);
 }
 
-void RasterizerCanvasGLES3::canvas_end() {
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-	glBindBuffer(GL_UNIFORM_BUFFER, 0);
-}
-
-void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, RID &r_last_texture, Size2 &r_texpixel_size) {
+void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index) {
 	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+	GLES3::Config *config = GLES3::Config::get_singleton();
 
 	if (p_texture == RID()) {
-		p_texture = default_canvas_texture;
+		p_texture = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
 	}
 
-	if (r_last_texture == p_texture) {
+	if (state.current_tex == p_texture) {
 		return; //nothing to do, its the same
 	}
-
-	state.end_batch = true;
-	_render_batch(r_index);
+	state.current_tex = p_texture;
 
 	GLES3::CanvasTexture *ct = nullptr;
 
@@ -888,12 +1042,12 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
 
 		ct = t->canvas_texture;
 	} else {
-		ct = GLES3::TextureStorage::get_singleton()->get_canvas_texture(p_texture);
+		ct = texture_storage->get_canvas_texture(p_texture);
 	}
 
 	if (!ct) {
 		// Invalid Texture RID.
-		_bind_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat, r_index, r_last_texture, r_texpixel_size);
+		_bind_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat, r_index);
 		return;
 	}
 
@@ -906,18 +1060,17 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
 	GLES3::Texture *texture = texture_storage->get_texture(ct->diffuse);
 
 	if (!texture) {
-		state.current_tex = RID();
-		state.current_tex_ptr = nullptr;
-		ct->size_cache = Size2i(1, 1);
-
+		state.current_tex = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
+		GLES3::Texture *tex = texture_storage->get_texture(state.current_tex);
+		state.current_tex_ptr = tex;
+		ct->size_cache = Size2i(tex->width, tex->height);
 		glActiveTexture(GL_TEXTURE0);
-		GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
 		glBindTexture(GL_TEXTURE_2D, tex->tex_id);
 	} else {
 		glActiveTexture(GL_TEXTURE0);
 		glBindTexture(GL_TEXTURE_2D, texture->tex_id);
 
-		state.current_tex = ct->diffuse;
+		state.current_tex = p_texture;
 		state.current_tex_ptr = texture;
 		ct->size_cache = Size2i(texture->width, texture->height);
 
@@ -935,7 +1088,7 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
 		glBindTexture(GL_TEXTURE_2D, tex->tex_id);
 
 	} else {
-		glActiveTexture(GL_TEXTURE0 + storage->config->max_texture_image_units - 6);
+		glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
 		glBindTexture(GL_TEXTURE_2D, normal_map->tex_id);
 		state.current_normal = ct->normal_map;
 		ct->use_normal_cache = true;
@@ -948,11 +1101,11 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
 	if (!specular_map) {
 		state.current_specular = RID();
 		ct->use_specular_cache = false;
-		glActiveTexture(GL_TEXTURE0 + storage->config->max_texture_image_units - 7);
+		glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
 		GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
 		glBindTexture(GL_TEXTURE_2D, tex->tex_id);
 	} else {
-		glActiveTexture(GL_TEXTURE0 + storage->config->max_texture_image_units - 7);
+		glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
 		glBindTexture(GL_TEXTURE_2D, specular_map->tex_id);
 		state.current_specular = ct->specular;
 		ct->use_specular_cache = true;
@@ -977,34 +1130,19 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
 	state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.g * 255.0, 0, 255)) << 8;
 	state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.r * 255.0, 0, 255));
 
-	r_texpixel_size.x = 1.0 / float(ct->size_cache.x);
-	r_texpixel_size.y = 1.0 / float(ct->size_cache.y);
-
-	state.instance_data_array[r_index].color_texture_pixel_size[0] = r_texpixel_size.x;
-	state.instance_data_array[r_index].color_texture_pixel_size[1] = r_texpixel_size.y;
+	state.current_pixel_size.x = 1.0 / float(ct->size_cache.x);
+	state.current_pixel_size.y = 1.0 / float(ct->size_cache.y);
 
-	r_last_texture = p_texture;
-}
-
-void RasterizerCanvasGLES3::_set_uniforms() {
+	state.instance_data_array[r_index].color_texture_pixel_size[0] = state.current_pixel_size.x;
+	state.instance_data_array[r_index].color_texture_pixel_size[1] = state.current_pixel_size.y;
 }
 
 void RasterizerCanvasGLES3::reset_canvas() {
-	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
-
 	glDisable(GL_CULL_FACE);
 	glDisable(GL_DEPTH_TEST);
 	glDisable(GL_SCISSOR_TEST);
-	glDisable(GL_DITHER);
 	glEnable(GL_BLEND);
-
-	// Default to Mix.
-	glBlendEquation(GL_FUNC_ADD);
-	if (texture_storage->frame.current_rt && texture_storage->frame.current_rt->flags[GLES3::TextureStorage::RENDER_TARGET_TRANSPARENT]) {
-		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-	} else {
-		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
-	}
+	glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
 
 	glBindBuffer(GL_ARRAY_BUFFER, 0);
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -1218,8 +1356,8 @@ RasterizerCanvasGLES3 *RasterizerCanvasGLES3::get_singleton() {
 RasterizerCanvasGLES3::RasterizerCanvasGLES3(RasterizerStorageGLES3 *p_storage) {
 	singleton = this;
 	storage = p_storage;
-	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
 	GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+	GLES3::Config *config = GLES3::Config::get_singleton();
 
 	// quad buffer
 	{
@@ -1342,8 +1480,7 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3(RasterizerStorageGLES3 *p_storage)
 		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 	}
 
-	//state.canvas_shadow_shader.init();
-	int uniform_max_size = storage->config->max_uniform_buffer_size;
+	int uniform_max_size = config->max_uniform_buffer_size;
 	if (uniform_max_size < 65536) {
 		state.max_lights_per_render = 64;
 		state.max_instances_per_batch = 128;
@@ -1379,14 +1516,6 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3(RasterizerStorageGLES3 *p_storage)
 	state.canvas_shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_create();
 	GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.canvas_shader_default_version, CanvasShaderGLES3::MODE_QUAD);
 
-	//state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_RGBA_SHADOWS, storage->config->use_rgba_2d_shadows);
-
-	//state.canvas_shader.bind();
-
-	//state.lens_shader.init();
-
-	//state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false));
-
 	{
 		default_canvas_group_shader = material_storage->shader_allocate();
 		material_storage->shader_initialize(default_canvas_group_shader);
@@ -1412,24 +1541,16 @@ void fragment() {
 		material_storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader);
 	}
 
-	default_canvas_texture = texture_storage->canvas_texture_allocate();
-	texture_storage->canvas_texture_initialize(default_canvas_texture);
-
-	state.using_light = nullptr;
-	state.using_transparent_rt = false;
-	state.using_skeleton = false;
 	state.current_shader_version = state.canvas_shader_default_version;
 	state.time = 0.0;
 }
 
 RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
-	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
 	GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
 
 	GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_free(state.canvas_shader_default_version);
 	material_storage->material_free(default_canvas_group_material);
 	material_storage->shader_free(default_canvas_group_shader);
-	texture_storage->canvas_texture_free(default_canvas_texture);
 	singleton = nullptr;
 
 	glDeleteBuffers(1, &data.canvas_quad_vertices);

+ 6 - 28
drivers/gles3/rasterizer_canvas_gles3.h

@@ -171,22 +171,11 @@ public:
 
 		InstanceData *instance_data_array = nullptr;
 		bool canvas_texscreen_used;
-		//CanvasShaderGLES3 canvas_shader;
 		RID canvas_shader_current_version;
 		RID canvas_shader_default_version;
-		//CanvasShadowShaderGLES3 canvas_shadow_shader;
-		//LensDistortedShaderGLES3 lens_shader;
-
-		bool using_texture_rect;
-
-		bool using_ninepatch;
-		bool using_skeleton;
-
-		Transform2D skeleton_transform;
-		Transform2D skeleton_transform_inverse;
-		Size2i skeleton_texture_size;
 
 		RID current_tex = RID();
+		Size2 current_pixel_size = Size2();
 		RID current_normal = RID();
 		RID current_specular = RID();
 		GLES3::Texture *current_tex_ptr;
@@ -195,14 +184,7 @@ public:
 		uint32_t current_primitive_points = 0;
 		Item::Command::Type current_command = Item::Command::TYPE_RECT;
 
-		bool end_batch = false;
-
-		Transform3D vp;
-		Light *using_light = nullptr;
-		bool using_shadow;
-		bool using_transparent_rt;
-
-		// FROM RD Renderer
+		bool transparent_render_target = false;
 
 		double time = 0.0;
 
@@ -224,16 +206,13 @@ public:
 
 	RasterizerStorageGLES3 *storage = nullptr;
 
-	void _set_uniforms();
-
-	void canvas_begin();
-	void canvas_end();
+	void canvas_begin(RID p_to_render_target, bool p_to_backbuffer);
 
 	//virtual void draw_window_margins(int *black_margin, RID *black_image) override;
 	void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
 
-	virtual void reset_canvas();
-	virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache);
+	void reset_canvas();
+	void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache);
 
 	virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override;
 
@@ -252,7 +231,7 @@ public:
 	bool free(RID p_rid) override;
 	void update() override;
 
-	void _bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, RID &r_last_texture, Size2 &r_texpixel_size);
+	void _bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index);
 
 	struct PolygonBuffers {
 		GLuint vertex_buffer;
@@ -273,7 +252,6 @@ public:
 	void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false);
 	void _render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index);
 	void _render_batch(uint32_t &p_max_index);
-	void _end_batch(const uint32_t p_index);
 	void _allocate_instance_data_buffer();
 
 	void set_time(double p_time);

+ 2 - 8
drivers/gles3/rasterizer_gles3.cpp

@@ -268,6 +268,7 @@ RasterizerGLES3::RasterizerGLES3() {
 	mesh_storage = memnew(GLES3::MeshStorage);
 	particles_storage = memnew(GLES3::ParticlesStorage);
 	light_storage = memnew(GLES3::LightStorage);
+	copy_effects = memnew(GLES3::CopyEffects);
 	storage = memnew(RasterizerStorageGLES3);
 	canvas = memnew(RasterizerCanvasGLES3(storage));
 	scene = memnew(RasterizerSceneGLES3(storage));
@@ -281,7 +282,6 @@ void RasterizerGLES3::prepare_for_blitting_render_targets() {
 
 void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect) {
 	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
-	ERR_FAIL_COND(texture_storage->frame.current_rt);
 
 	GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
 	ERR_FAIL_COND(!rt);
@@ -304,12 +304,9 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
 
 // is this p_screen useless in a multi window environment?
 void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) {
-	// do this once off for all blits
-	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+	// All blits are going to the system framebuffer, so just bind once.
 	glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
 
-	texture_storage->frame.current_rt = nullptr;
-
 	for (int i = 0; i < p_amount; i++) {
 		const BlitToScreen &blit = p_render_targets[i];
 
@@ -339,8 +336,6 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
 	}
 	glClear(GL_COLOR_BUFFER_BIT);
 
-	canvas->canvas_begin();
-
 	RID texture = texture_storage->texture_allocate();
 	texture_storage->texture_2d_initialize(texture, p_image);
 
@@ -368,7 +363,6 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
 	glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 1);
 	glBindTexture(GL_TEXTURE_2D, t->tex_id);
 	glBindTexture(GL_TEXTURE_2D, 0);
-	canvas->canvas_end();
 
 	texture_storage->texture_free(texture);
 

+ 2 - 0
drivers/gles3/rasterizer_gles3.h

@@ -33,6 +33,7 @@
 
 #ifdef GLES3_ENABLED
 
+#include "effects/copy_effects.h"
 #include "rasterizer_canvas_gles3.h"
 #include "rasterizer_scene_gles3.h"
 #include "rasterizer_storage_gles3.h"
@@ -58,6 +59,7 @@ protected:
 	GLES3::MeshStorage *mesh_storage = nullptr;
 	GLES3::ParticlesStorage *particles_storage = nullptr;
 	GLES3::LightStorage *light_storage = nullptr;
+	GLES3::CopyEffects *copy_effects = nullptr;
 	RasterizerStorageGLES3 *storage = nullptr;
 	RasterizerCanvasGLES3 *canvas = nullptr;
 	RasterizerSceneGLES3 *scene = nullptr;

+ 1 - 109
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -36,20 +36,6 @@
 
 #ifdef GLES3_ENABLED
 
-void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type) {
-#ifdef GLES_OVER_GL
-
-	for (int i = 0; i < levels; i++) {
-		glTexImage2D(target, i, internalformat, width, height, 0, format, type, nullptr);
-		width = MAX(1, (width / 2));
-		height = MAX(1, (height / 2));
-	}
-
-#else
-	glTexStorage2D(target, levels, internalformat, width, height);
-#endif
-}
-
 uint64_t RasterizerSceneGLES3::auto_exposure_counter = 2;
 
 RasterizerSceneGLES3 *RasterizerSceneGLES3::singleton = nullptr;
@@ -2480,100 +2466,6 @@ RID RasterizerSceneGLES3::render_buffers_create() {
 	return render_buffers_owner.make_rid(rb);
 }
 
-/* BACK FBO */
-/* For MSAA */
-/*
-#ifndef JAVASCRIPT_ENABLED
-	if (rt->msaa >= RS::VIEWPORT_MSAA_2X && rt->msaa <= RS::VIEWPORT_MSAA_8X) {
-		rt->multisample_active = true;
-
-		static const int msaa_value[] = { 0, 2, 4, 8, 16 };
-		int msaa = msaa_value[rt->msaa];
-
-		int max_samples = 0;
-		glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
-		if (msaa > max_samples) {
-			WARN_PRINT("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples));
-			msaa = max_samples;
-		}
-
-		//regular fbo
-		glGenFramebuffers(1, &rt->multisample_fbo);
-		bind_framebuffer(rt->multisample_fbo);
-
-		glGenRenderbuffers(1, &rt->multisample_depth);
-		glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_depth);
-		glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_buffer_internalformat, rt->size.x, rt->size.y);
-
-		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->multisample_depth);
-
-		glGenRenderbuffers(1, &rt->multisample_color);
-		glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_color);
-		glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->size.x, rt->size.y);
-
-		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->multisample_color);
-
-		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-
-		if (status != GL_FRAMEBUFFER_COMPLETE) {
-			// Delete allocated resources and default to no MSAA
-			WARN_PRINT_ONCE("Cannot allocate back framebuffer for MSAA");
-			printf("err status: %x\n", status);
-			rt->multisample_active = false;
-
-			glDeleteFramebuffers(1, &rt->multisample_fbo);
-			rt->multisample_fbo = 0;
-
-			glDeleteRenderbuffers(1, &rt->multisample_depth);
-			rt->multisample_depth = 0;
-
-			glDeleteRenderbuffers(1, &rt->multisample_color);
-			rt->multisample_color = 0;
-		}
-
-		glBindRenderbuffer(GL_RENDERBUFFER, 0);
-		bind_framebuffer(0);
-
-	} else
-#endif // JAVASCRIPT_ENABLED
-	{
-		rt->multisample_active = false;
-	}
-	*/
-
-// copy texscreen buffers
-//	if (!(rt->flags[RendererStorage::RENDER_TARGET_NO_SAMPLING])) {
-/*
-if (false) {
-glGenTextures(1, &rt->copy_screen_effect.color);
-glBindTexture(GL_TEXTURE_2D, rt->copy_screen_effect.color);
-
-if (rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) {
-	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->size.x, rt->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
-} else {
-	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rt->size.x, rt->size.y, 0, GL_RGB, GL_UNSIGNED_BYTE, 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);
-
-glGenFramebuffers(1, &rt->copy_screen_effect.fbo);
-bind_framebuffer(rt->copy_screen_effect.fbo);
-glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->copy_screen_effect.color, 0);
-
-glClearColor(0, 0, 0, 0);
-glClear(GL_COLOR_BUFFER_BIT);
-
-GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-if (status != GL_FRAMEBUFFER_COMPLETE) {
-	_clear_render_target(rt);
-	ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
-}
-}
-*/
-
 void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) {
 	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
 
@@ -2595,7 +2487,7 @@ void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_
 
 	GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
 
-	rb->is_transparent = rt->flags[RendererTextureStorage::RENDER_TARGET_TRANSPARENT];
+	rb->is_transparent = rt->is_transparent;
 
 	// framebuffer
 	glGenFramebuffers(1, &rb->framebuffer);

+ 0 - 43
drivers/gles3/rasterizer_scene_gles3.h

@@ -553,49 +553,6 @@ protected:
 		};
 
 		Blur blur[2]; //the second one starts from the first mipmap
-
-		/*
-		GLuint fbo = 0;
-		GLuint color = 0;
-		GLuint depth = 0;
-
-		GLuint multisample_fbo = 0;
-		GLuint multisample_color = 0;
-		GLuint multisample_depth = 0;
-		bool multisample_active = false;
-
-		struct Effect {
-			GLuint fbo = 0;
-			int width = 0;
-			int height = 0;
-
-			GLuint color = 0;
-
-			Effect() {
-			}
-		};
-
-		Effect copy_screen_effect;
-
-		struct MipMaps {
-			struct Size {
-				GLuint fbo;
-				GLuint color;
-				int width;
-				int height;
-			};
-
-			Vector<Size> sizes;
-			GLuint color = 0;
-			int levels = 0;
-
-			MipMaps() {
-			}
-		};
-
-		MipMaps mip_maps[2];
-
-		*/
 	};
 
 	bool screen_space_roughness_limiter = false;

+ 2 - 8
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -225,7 +225,7 @@ RID RasterizerStorageGLES3::canvas_light_shadow_buffer_create(int p_width) {
 
 	glGenRenderbuffers(1, &cls->depth);
 	glBindRenderbuffer(GL_RENDERBUFFER, cls->depth);
-	glRenderbufferStorage(GL_RENDERBUFFER, config->depth_buffer_internalformat, cls->size, cls->height);
+	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height);
 	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth);
 
 	glGenTextures(1, &cls->distance);
@@ -453,11 +453,8 @@ bool RasterizerStorageGLES3::has_os_feature(const String &p_feature) const {
 	if (p_feature == "bptc") {
 		return config->bptc_supported;
 	}
-	if (p_feature == "etc") {
-		return config->etc_supported;
-	}
 
-	if (p_feature == "etc2") {
+	if (p_feature == "etc" || p_feature == "etc2") {
 		return config->etc2_supported;
 	}
 
@@ -619,9 +616,6 @@ void RasterizerStorageGLES3::initialize() {
 void RasterizerStorageGLES3::finalize() {
 }
 
-void RasterizerStorageGLES3::_copy_screen() {
-	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-}
 void RasterizerStorageGLES3::update_memory_info() {
 }
 

+ 0 - 42
drivers/gles3/rasterizer_storage_gles3.h

@@ -258,8 +258,6 @@ public:
 	void initialize();
 	void finalize();
 
-	void _copy_screen();
-
 	void update_memory_info() override;
 	uint64_t get_rendering_info(RS::RenderingInfo p_info) override;
 
@@ -297,9 +295,6 @@ public:
 		return String();
 	}
 
-	void buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target = GL_ARRAY_BUFFER, GLenum p_usage = GL_DYNAMIC_DRAW, bool p_optional_orphan = false) const;
-	bool safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const;
-
 	//bool validate_framebuffer(); // Validate currently bound framebuffer, does not touch global state
 	String get_framebuffer_error(GLenum p_status);
 
@@ -307,43 +302,6 @@ public:
 	~RasterizerStorageGLES3();
 };
 
-inline bool RasterizerStorageGLES3::safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const {
-	r_offset_after = p_offset + p_data_size;
-#ifdef DEBUG_ENABLED
-	// we are trying to write across the edge of the buffer
-	if (r_offset_after > p_total_buffer_size) {
-		return false;
-	}
-#endif
-	glBufferSubData(p_target, p_offset, p_data_size, p_data);
-	return true;
-}
-
-// standardize the orphan / upload in one place so it can be changed per platform as necessary, and avoid future
-// bugs causing pipeline stalls
-inline void RasterizerStorageGLES3::buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target, GLenum p_usage, bool p_optional_orphan) const {
-	// Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData
-	// Was previously #ifndef GLES_OVER_GL however this causes stalls on desktop mac also (and possibly other)
-	if (!p_optional_orphan || (config->should_orphan)) {
-		glBufferData(p_target, p_buffer_size, nullptr, p_usage);
-#ifdef RASTERIZER_EXTRA_CHECKS
-		// fill with garbage off the end of the array
-		if (p_buffer_size) {
-			unsigned int start = p_offset + p_data_size;
-			unsigned int end = start + 1024;
-			if (end < p_buffer_size) {
-				uint8_t *garbage = (uint8_t *)alloca(1024);
-				for (int n = 0; n < 1024; n++) {
-					garbage[n] = Math::random(0, 255);
-				}
-				glBufferSubData(p_target, start, 1024, garbage);
-			}
-		}
-#endif
-	}
-	glBufferSubData(p_target, p_offset, p_data_size, p_data);
-}
-
 inline String RasterizerStorageGLES3::get_framebuffer_error(GLenum p_status) {
 #if defined(DEBUG_ENABLED) && defined(GLES_OVER_GL)
 	if (p_status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {

+ 1 - 1
drivers/gles3/shader_gles3.cpp

@@ -673,7 +673,7 @@ void ShaderGLES3::initialize(const String &p_general_defines, int p_base_texture
 		print_verbose("Shader '" + name + "' SHA256: " + base_sha256);
 	}
 
-	glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units);
+	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_image_units);
 }
 
 void ShaderGLES3::set_shader_cache_dir(const String &p_dir) {

+ 1 - 0
drivers/gles3/shader_gles3.h

@@ -31,6 +31,7 @@
 #ifndef SHADER_OPENGL_H
 #define SHADER_OPENGL_H
 
+#include "core/math/camera_matrix.h"
 #include "core/os/mutex.h"
 #include "core/string/string_builder.h"
 #include "core/templates/hash_map.h"

+ 18 - 163
drivers/gles3/shaders/copy.glsl

@@ -1,204 +1,59 @@
 /* clang-format off */
 #[modes]
 
-mode_default =
-mode_cubemap = #define USE_CUBEMAP
-mode_panorama = #define USE_PANORAMA
+mode_default = #define MODE_SIMPLE_COPY
 mode_copy_section = #define USE_COPY_SECTION
-mode_asym_pano = #define USE_ASYM_PANO
-mode_no_alpha = #define USE_NO_ALPHA
-mode_custom_alpha = #define USE_CUSTOM_ALPHA
-mode_multiplier = #define USE_MULTIPLIER
-mode_sep_cbcr_texture = #define USE_SEP_CBCR_TEXTURE
-mode_ycbcr_to_rgb = #define USE_YCBCR_TO_RGB
+mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
+mode_mipmap = #define MODE_MIPMAP
+mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
 
 #[specializations]
 
-
 #[vertex]
 
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-precision highp float;
-precision highp int;
-#endif
-
-layout(location = 0) in highp vec4 vertex_attrib;
-/* clang-format on */
-
-#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
-layout(location = 4) in vec3 cube_in;
-#else
-layout(location = 4) in vec2 uv_in;
-#endif
-
-layout(location = 5) in vec2 uv2_in;
+layout(location = 0) in vec2 vertex_attrib;
 
-#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
-out vec3 cube_interp;
-#else
 out vec2 uv_interp;
-#endif
-out vec2 uv2_interp;
+/* clang-format on */
 
 #ifdef USE_COPY_SECTION
 uniform highp vec4 copy_section;
-#elif defined(USE_DISPLAY_TRANSFORM)
-uniform highp mat4 display_transform;
 #endif
 
 void main() {
-#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
-	cube_interp = cube_in;
-#elif defined(USE_ASYM_PANO)
-	uv_interp = vertex_attrib.xy;
-#else
-	uv_interp = uv_in;
-#endif
-
-	uv2_interp = uv2_in;
-	gl_Position = vertex_attrib;
+	uv_interp = vertex_attrib * 0.5 + 0.5;
+	gl_Position = vec4(vertex_attrib, 1.0, 1.0);
 
 #ifdef USE_COPY_SECTION
+	gl_Position.xy = (copy_section.xy + (uv_interp.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0;
 	uv_interp = copy_section.xy + uv_interp * copy_section.zw;
-	gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0;
-#elif defined(USE_DISPLAY_TRANSFORM)
-	uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy;
 #endif
 }
 
 /* clang-format off */
 #[fragment]
 
-#define M_PI 3.14159265359
-
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-#if defined(USE_HIGHP_PRECISION)
-precision highp float;
-precision highp int;
-#else
-precision mediump float;
-precision mediump int;
-#endif
-#endif
-
-#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
-in vec3 cube_interp;
-#else
 in vec2 uv_interp;
-#endif
 /* clang-format on */
-
-#ifdef USE_ASYM_PANO
-uniform highp mat4 pano_transform;
-uniform highp vec4 asym_proj;
-#endif
-
-#ifdef USE_CUBEMAP
-uniform samplerCube source_cube; // texunit:0
-#else
-uniform sampler2D source; // texunit:0
-#endif
-
-#ifdef USE_SEP_CBCR_TEXTURE
-uniform sampler2D CbCr; //texunit:1
-#endif
-
-in vec2 uv2_interp;
-
-#ifdef USE_MULTIPLIER
-uniform float multiplier;
+#ifdef MODE_SIMPLE_COLOR
+uniform vec4 color_in;
 #endif
 
-#ifdef USE_CUSTOM_ALPHA
-uniform float custom_alpha;
+#ifdef MODE_GAUSSIAN_BLUR
+uniform highp vec2 pixel_size;
 #endif
 
-#if defined(USE_PANORAMA) || defined(USE_ASYM_PANO)
-uniform highp mat4 sky_transform;
-
-vec4 texturePanorama(sampler2D pano, vec3 normal) {
-	vec2 st = vec2(
-			atan(normal.x, normal.z),
-			acos(normal.y));
-
-	if (st.x < 0.0)
-		st.x += M_PI * 2.0;
-
-	st /= vec2(M_PI * 2.0, M_PI);
-
-	return texture(pano, st);
-}
-
-#endif
+uniform sampler2D source; // texunit:0
 
 layout(location = 0) out vec4 frag_color;
 
 void main() {
-#ifdef USE_PANORAMA
-
-	vec3 cube_normal = normalize(cube_interp);
-	cube_normal.z = -cube_normal.z;
-	cube_normal = mat3(sky_transform) * cube_normal;
-	cube_normal.z = -cube_normal.z;
-
-	vec4 color = texturePanorama(source, cube_normal);
-
-#elif defined(USE_ASYM_PANO)
-
-	// When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result.
-	// Asymmetrical projection means the center of projection is no longer in the center of the screen but shifted.
-	// The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image.
-
-	vec3 cube_normal;
-	cube_normal.z = -1.0;
-	cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y;
-	cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a;
-	cube_normal = mat3(sky_transform) * mat3(pano_transform) * cube_normal;
-	cube_normal.z = -cube_normal.z;
-
-	vec4 color = texturePanorama(source, normalize(cube_normal.xyz));
-
-#elif defined(USE_CUBEMAP)
-	vec4 color = texture(source_cube, normalize(cube_interp));
-#elif defined(USE_SEP_CBCR_TEXTURE)
-	vec4 color;
-	color.r = texture(source, uv_interp).r;
-	color.gb = texture(CbCr, uv_interp).rg - vec2(0.5, 0.5);
-	color.a = 1.0;
-#else
+#ifdef MODE_SIMPLE_COPY
 	vec4 color = texture(source, uv_interp);
+	frag_color = color;
 #endif
 
-#ifdef USE_YCBCR_TO_RGB
-	// YCbCr -> RGB conversion
-
-	// Using BT.601, which is the standard for SDTV is provided as a reference
-	color.rgb = mat3(
-						vec3(1.00000, 1.00000, 1.00000),
-						vec3(0.00000, -0.34413, 1.77200),
-						vec3(1.40200, -0.71414, 0.00000)) *
-			color.rgb;
-#endif
-
-#ifdef USE_NO_ALPHA
-	color.a = 1.0;
-#endif
-
-#ifdef USE_CUSTOM_ALPHA
-	color.a = custom_alpha;
-#endif
-
-#ifdef USE_MULTIPLIER
-	color.rgb *= multiplier;
+#ifdef MODE_SIMPLE_COLOR
+	frag_color = color_in;
 #endif
-
-	frag_color = color;
 }

+ 10 - 58
drivers/gles3/storage/config.cpp

@@ -55,82 +55,34 @@ Config::Config() {
 		}
 	}
 
-	keep_original_textures = true; // false
-	depth_internalformat = GL_DEPTH_COMPONENT;
-	depth_type = GL_UNSIGNED_INT;
-
-	srgb_decode_supported = extensions.has("GL_EXT_texture_sRGB_decode");
-	etc2_supported = true;
+	bptc_supported = extensions.has("GL_ARB_texture_compression_bptc") || extensions.has("EXT_texture_compression_bptc");
 #ifdef GLES_OVER_GL
 	float_texture_supported = true;
+	etc2_supported = false;
 	s3tc_supported = true;
-	etc_supported = false; // extensions.has("GL_OES_compressed_ETC1_RGB8_texture");
-	bptc_supported = extensions.has("GL_ARB_texture_compression_bptc") || extensions.has("EXT_texture_compression_bptc");
-	rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc") || extensions.has("EXT_texture_compression_rgtc");
-	support_npot_repeat_mipmap = true;
-	depth_buffer_internalformat = GL_DEPTH_COMPONENT24;
+	rgtc_supported = true; //RGTC - core since OpenGL version 3.0
 #else
 	float_texture_supported = extensions.has("GL_ARB_texture_float") || extensions.has("GL_OES_texture_float");
-	s3tc_supported = extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc");
-	etc_supported = extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || extensions.has("WEBGL_compressed_texture_etc1");
-	bptc_supported = false;
-	rgtc_supported = false;
-	support_npot_repeat_mipmap = extensions.has("GL_OES_texture_npot");
-
-#ifdef JAVASCRIPT_ENABLED
-	// RenderBuffer internal format must be 16 bits in WebGL,
-	// but depth_texture should default to 32 always
-	// if the implementation doesn't support 32, it should just quietly use 16 instead
-	// https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/
-	depth_buffer_internalformat = GL_DEPTH_COMPONENT16;
-	depth_type = GL_UNSIGNED_INT;
-#else
-	// on mobile check for 24 bit depth support for RenderBufferStorage
-	if (extensions.has("GL_OES_depth24")) {
-		depth_buffer_internalformat = _DEPTH_COMPONENT24_OES;
-		depth_type = GL_UNSIGNED_INT;
-	} else {
-		depth_buffer_internalformat = GL_DEPTH_COMPONENT16;
-		depth_type = GL_UNSIGNED_SHORT;
-	}
-#endif
+	etc2_supported = true;
+	s3tc_supported = extensions.has("GL_EXT_texture_compression_dxt1") || extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc");
+	rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc") || extensions.has("EXT_texture_compression_rgtc");
 #endif
 
 #ifdef GLES_OVER_GL
 	use_rgba_2d_shadows = false;
-	use_rgba_3d_shadows = false;
-	support_depth_cubemaps = true;
 #else
 	use_rgba_2d_shadows = !(float_texture_supported && extensions.has("GL_EXT_texture_rg"));
-	use_rgba_3d_shadows = false;
-	support_depth_cubemaps = extensions.has("GL_OES_depth_texture_cube_map");
-#endif
-
-#ifdef GLES_OVER_GL
-	support_32_bits_indices = true;
-#else
-	support_32_bits_indices = extensions.has("GL_OES_element_index_uint");
 #endif
 
-#ifdef GLES_OVER_GL
-	support_write_depth = true;
-#elif defined(JAVASCRIPT_ENABLED)
-	support_write_depth = false;
-#else
-	support_write_depth = extensions.has("GL_EXT_frag_depth");
-#endif
+	glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &max_vertex_texture_image_units);
+	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_image_units);
+	glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
+	glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size);
 
-	//picky requirements for these
-	support_shadow_cubemaps = support_write_depth && support_depth_cubemaps;
 	// the use skeleton software path should be used if either float texture is not supported,
 	// OR max_vertex_texture_image_units is zero
 	use_skeleton_software = (float_texture_supported == false) || (max_vertex_texture_image_units == 0);
 
-	glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &max_vertex_texture_image_units);
-	glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_texture_image_units);
-	glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
-	glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size);
-
 	support_anisotropic_filter = extensions.has("GL_EXT_texture_filter_anisotropic");
 	if (support_anisotropic_filter) {
 		glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic_level);

+ 2 - 23
drivers/gles3/storage/config.h

@@ -53,6 +53,8 @@ private:
 public:
 	bool use_nearest_mip_filter = false;
 	bool use_skeleton_software = false;
+	bool use_depth_prepass = true;
+	bool use_rgba_2d_shadows = false;
 
 	int max_vertex_texture_image_units = 0;
 	int max_texture_image_units = 0;
@@ -69,38 +71,15 @@ public:
 
 	bool float_texture_supported = false;
 	bool s3tc_supported = false;
-	bool latc_supported = false;
 	bool rgtc_supported = false;
 	bool bptc_supported = false;
-	bool etc_supported = false;
 	bool etc2_supported = false;
-	bool srgb_decode_supported = false;
-
-	bool keep_original_textures = false;
 
 	bool force_vertex_shading = false;
 
-	bool use_rgba_2d_shadows = false;
-	bool use_rgba_3d_shadows = false;
-
-	bool support_32_bits_indices = false;
-	bool support_write_depth = false;
-	bool support_npot_repeat_mipmap = false;
-	bool support_depth_cubemaps = false;
-	bool support_shadow_cubemaps = false;
 	bool support_anisotropic_filter = false;
 	float anisotropic_level = 0.0f;
 
-	GLuint depth_internalformat = 0;
-	GLuint depth_type = 0;
-	GLuint depth_buffer_internalformat = 0;
-
-	// in some cases the legacy render didn't orphan. We will mark these
-	// so the user can switch orphaning off for them.
-	bool should_orphan = true;
-
-	bool use_depth_prepass = true;
-
 	static Config *get_singleton() { return singleton; };
 
 	Config();

+ 9 - 13
drivers/gles3/storage/material_storage.cpp

@@ -1184,8 +1184,6 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
 				p_textures[k++] = gl_texture;
 			}
 		} else {
-			//bool srgb = p_use_linear_color && p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR;
-
 			for (int j = 0; j < textures.size(); j++) {
 				Texture *tex = TextureStorage::get_singleton()->get_texture(textures[j]);
 
@@ -1671,10 +1669,6 @@ ShaderCompiler::DefaultIdentifierActions actions;
 
 		shaders.compiler_sky.initialize(actions);
 	}
-
-	//shaders.copy.initialize();
-	//shaders.copy_version = shaders.copy.version_create(); //TODO
-	//shaders.copy.version_bind_shader(shaders.copy_version, CopyShaderGLES3::MODE_COPY_SECTION);
 }
 
 MaterialStorage::~MaterialStorage() {
@@ -2748,7 +2742,7 @@ void CanvasShaderData::set_code(const String &p_code) {
 
 	ShaderCompiler::GeneratedCode gen_code;
 
-	int blend_mode = BLEND_MODE_MIX;
+	int blend_modei = BLEND_MODE_MIX;
 	uses_screen_texture = false;
 
 	ShaderCompiler::IdentifierActions actions;
@@ -2756,12 +2750,12 @@ void CanvasShaderData::set_code(const String &p_code) {
 	actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT;
 	actions.entry_point_stages["light"] = ShaderCompiler::STAGE_FRAGMENT;
 
-	actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
-	actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
-	actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
-	actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
-	actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA);
-	actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED);
+	actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_modei, BLEND_MODE_ADD);
+	actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MIX);
+	actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_modei, BLEND_MODE_SUB);
+	actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MUL);
+	actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_modei, BLEND_MODE_PMALPHA);
+	actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_modei, BLEND_MODE_DISABLED);
 
 	actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
 	actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
@@ -2775,6 +2769,8 @@ void CanvasShaderData::set_code(const String &p_code) {
 		version = MaterialStorage::get_singleton()->shaders.canvas_shader.version_create();
 	}
 
+	blend_mode = BlendMode(blend_modei);
+
 #if 0
 	print_line("**compiling shader:");
 	print_line("**defines:\n");

+ 12 - 16
drivers/gles3/storage/material_storage.h

@@ -42,8 +42,6 @@
 #include "servers/rendering/shader_language.h"
 #include "servers/rendering/storage/material_storage.h"
 
-#include "drivers/gles3/shaders/copy.glsl.gen.h"
-
 #include "../shaders/canvas.glsl.gen.h"
 #include "../shaders/cubemap_filter.glsl.gen.h"
 #include "../shaders/scene.glsl.gen.h"
@@ -53,18 +51,6 @@ namespace GLES3 {
 
 /* Shader Structs */
 
-struct Shaders {
-	CanvasShaderGLES3 canvas_shader;
-	SkyShaderGLES3 sky_shader;
-	SceneShaderGLES3 scene_shader;
-	CubemapFilterShaderGLES3 cubemap_filter_shader;
-
-	ShaderCompiler compiler_canvas;
-	ShaderCompiler compiler_scene;
-	ShaderCompiler compiler_particles;
-	ShaderCompiler compiler_sky;
-};
-
 struct ShaderData {
 	virtual void set_code(const String &p_Code) = 0;
 	virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) = 0;
@@ -159,8 +145,8 @@ struct CanvasShaderData : public ShaderData {
 
 	bool valid;
 	RID version;
-	//PipelineVariants pipeline_variants;
 	String path;
+	BlendMode blend_mode = BLEND_MODE_MIX;
 
 	HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
 	Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
@@ -467,7 +453,17 @@ public:
 	MaterialStorage();
 	virtual ~MaterialStorage();
 
-	Shaders shaders;
+	struct Shaders {
+		CanvasShaderGLES3 canvas_shader;
+		SkyShaderGLES3 sky_shader;
+		SceneShaderGLES3 scene_shader;
+		CubemapFilterShaderGLES3 cubemap_filter_shader;
+
+		ShaderCompiler compiler_canvas;
+		ShaderCompiler compiler_scene;
+		ShaderCompiler compiler_particles;
+		ShaderCompiler compiler_sky;
+	} shaders;
 
 	/* GLOBAL VARIABLE API */
 

+ 151 - 299
drivers/gles3/storage/texture_storage.cpp

@@ -32,6 +32,7 @@
 
 #include "texture_storage.h"
 #include "config.h"
+#include "drivers/gles3/effects/copy_effects.h"
 
 using namespace GLES3;
 
@@ -55,8 +56,6 @@ TextureStorage::TextureStorage() {
 
 	system_fbo = 0;
 
-	frame.current_rt = nullptr;
-
 	{ //create default textures
 		{ // White Textures
 
@@ -247,7 +246,7 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS:
 
 /* Texture API */
 
-Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const {
+Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const {
 	Config *config = Config::get_singleton();
 	r_gl_format = 0;
 	Ref<Image> image = p_image;
@@ -295,14 +294,12 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 			r_gl_internal_format = GL_RGB8;
 			r_gl_format = GL_RGB;
 			r_gl_type = GL_UNSIGNED_BYTE;
-			//r_srgb = true;
 
 		} break;
 		case Image::FORMAT_RGBA8: {
 			r_gl_format = GL_RGBA;
 			r_gl_internal_format = GL_RGBA8;
 			r_gl_type = GL_UNSIGNED_BYTE;
-			//r_srgb = true;
 
 		} break;
 		case Image::FORMAT_RGBA4444: {
@@ -311,12 +308,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 			r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4;
 
 		} break;
-			//case Image::FORMAT_RGBA5551: {
-			//	r_gl_internal_format = GL_RGB5_A1;
-			//	r_gl_format = GL_RGBA;
-			//	r_gl_type = GL_UNSIGNED_SHORT_5_5_5_1;
-			//
-			//} break;
 		case Image::FORMAT_RF: {
 			r_gl_internal_format = GL_R32F;
 			r_gl_format = GL_RED;
@@ -376,8 +367,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
 				r_compressed = true;
-				//r_srgb = true;
-
 			} else {
 				need_decompress = true;
 			}
@@ -388,8 +377,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
 				r_compressed = true;
-				//r_srgb = true;
-
 			} else {
 				need_decompress = true;
 			}
@@ -400,8 +387,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
 				r_compressed = true;
-				//r_srgb = true;
-
 			} else {
 				need_decompress = true;
 			}
@@ -412,7 +397,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
 				r_compressed = true;
-
 			} else {
 				need_decompress = true;
 			}
@@ -433,8 +417,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
 				r_compressed = true;
-				//r_srgb = true;
-
 			} else {
 				need_decompress = true;
 			}
@@ -459,19 +441,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 				need_decompress = true;
 			}
 		} break;
-		case Image::FORMAT_ETC: {
-			if (config->etc_supported) {
-				r_gl_internal_format = _EXT_ETC1_RGB8_OES;
-				r_gl_format = GL_RGBA;
-				r_gl_type = GL_UNSIGNED_BYTE;
-				r_compressed = true;
-
-			} else {
-				need_decompress = true;
-			}
-
-		} break;
-		/*
 		case Image::FORMAT_ETC2_R11: {
 			if (config->etc2_supported) {
 				r_gl_internal_format = _EXT_COMPRESSED_R11_EAC;
@@ -516,13 +485,13 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 				need_decompress = true;
 			}
 		} break;
+		case Image::FORMAT_ETC:
 		case Image::FORMAT_ETC2_RGB8: {
 			if (config->etc2_supported) {
 				r_gl_internal_format = _EXT_COMPRESSED_RGB8_ETC2;
 				r_gl_format = GL_RGB;
 				r_gl_type = GL_UNSIGNED_BYTE;
 				r_compressed = true;
-				//r_srgb = true;
 
 			} else {
 				need_decompress = true;
@@ -534,7 +503,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
 				r_compressed = true;
-				//r_srgb = true;
 
 			} else {
 				need_decompress = true;
@@ -546,13 +514,11 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
 				r_gl_format = GL_RGBA;
 				r_gl_type = GL_UNSIGNED_BYTE;
 				r_compressed = true;
-				//r_srgb = true;
 
 			} else {
 				need_decompress = true;
 			}
 		} break;
-		*/
 		default: {
 			ERR_FAIL_V_MSG(Ref<Image>(), "Image Format: " + itos(p_format) + " is not supported by the OpenGL3 Renderer");
 		}
@@ -643,7 +609,7 @@ void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_im
 	texture.format = p_image->get_format();
 	texture.type = Texture::TYPE_2D;
 	texture.target = GL_TEXTURE_2D;
-	_get_gl_image_and_format(Ref<Image>(), texture.format, 0, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false);
+	_get_gl_image_and_format(Ref<Image>(), texture.format, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false);
 	//texture.total_data_size = p_image->get_image_data_size(); // verify that this returns size in bytes
 	texture.active = true;
 	glGenTextures(1, &texture.tex_id);
@@ -880,11 +846,6 @@ void TextureStorage::texture_set_detect_3d_callback(RID p_texture, RS::TextureDe
 }
 
 void TextureStorage::texture_set_detect_srgb_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
-	Texture *texture = texture_owner.get_or_null(p_texture);
-	ERR_FAIL_COND(!texture);
-
-	texture->detect_srgb = p_callback;
-	texture->detect_srgb_ud = p_userdata;
 }
 
 void TextureStorage::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
@@ -967,7 +928,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
 	// print_line("texture_set_data width " + itos (p_image->get_width()) + " height " + itos(p_image->get_height()));
 
 	Image::Format real_format;
-	Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), 0, real_format, format, internal_format, type, compressed, texture->resize_to_po2);
+	Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), real_format, format, internal_format, type, compressed, texture->resize_to_po2);
 	ERR_FAIL_COND(img.is_null());
 	if (texture->resize_to_po2) {
 		if (p_image->is_compressed()) {
@@ -1054,11 +1015,6 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
 
 	texture->stored_cube_sides |= (1 << p_layer);
 
-	//if ((texture->flags & TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != RenderingDevice::TEXTURE_TYPE_CUBE || texture->stored_cube_sides == (1 << 6) - 1)) {
-	//generate mipmaps if they were requested and the image does not contain them
-	//	glGenerateMipmap(texture->target);
-	//}
-
 	texture->mipmaps = mipmaps;
 }
 
@@ -1066,128 +1022,6 @@ void TextureStorage::texture_set_data_partial(RID p_texture, const Ref<Image> &p
 	ERR_PRINT("Not implemented yet, sorry :(");
 }
 
-/*
-Ref<Image> TextureStorage::texture_get_data(RID p_texture, int p_layer) const {
-	Texture *texture = texture_owner.get_or_null(p_texture);
-
-	ERR_FAIL_COND_V(!texture, Ref<Image>());
-	ERR_FAIL_COND_V(!texture->active, Ref<Image>());
-	ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>());
-
-
-#ifdef GLES_OVER_GL
-
-	Image::Format real_format;
-	GLenum gl_format;
-	GLenum gl_internal_format;
-	GLenum gl_type;
-	bool compressed;
-	_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, false);
-
-	PoolVector<uint8_t> data;
-
-	int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1);
-
-	data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
-	PoolVector<uint8_t>::Write wb = data.write();
-
-	glActiveTexture(GL_TEXTURE0);
-
-	glBindTexture(texture->target, texture->tex_id);
-
-	glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
-
-	for (int i = 0; i < texture->mipmaps; i++) {
-		int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i);
-
-		if (texture->compressed) {
-			glPixelStorei(GL_PACK_ALIGNMENT, 4);
-			glGetCompressedTexImage(texture->target, i, &wb[ofs]);
-		} else {
-			glPixelStorei(GL_PACK_ALIGNMENT, 1);
-			glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &wb[ofs]);
-		}
-	}
-
-	wb.release();
-
-	data.resize(data_size);
-
-	Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, real_format, data));
-
-	return Ref<Image>(img);
-#else
-
-	Image::Format real_format;
-	GLenum gl_format;
-	GLenum gl_internal_format;
-	GLenum gl_type;
-	bool compressed;
-	_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, texture->resize_to_po2);
-
-	PoolVector<uint8_t> data;
-
-	int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false);
-
-	data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
-	PoolVector<uint8_t>::Write wb = data.write();
-
-	GLuint temp_framebuffer;
-	glGenFramebuffers(1, &temp_framebuffer);
-
-	GLuint temp_color_texture;
-	glGenTextures(1, &temp_color_texture);
-
-	glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
-
-	glBindTexture(GL_TEXTURE_2D, temp_color_texture);
-	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0);
-
-	glDepthMask(GL_FALSE);
-	glDisable(GL_DEPTH_TEST);
-	glDisable(GL_CULL_FACE);
-	glDisable(GL_BLEND);
-	glDepthFunc(GL_LEQUAL);
-	glColorMask(1, 1, 1, 1);
-	glActiveTexture(GL_TEXTURE0);
-	glBindTexture(GL_TEXTURE_2D, texture->tex_id);
-
-	glViewport(0, 0, texture->alloc_width, texture->alloc_height);
-
-	shaders.copy.bind();
-
-	glClearColor(0.0, 0.0, 0.0, 0.0);
-	glClear(GL_COLOR_BUFFER_BIT);
-	bind_quad_array();
-	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-	glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]);
-
-	glDeleteTextures(1, &temp_color_texture);
-
-	glBindFramebuffer(GL_FRAMEBUFFER, 0);
-	glDeleteFramebuffers(1, &temp_framebuffer);
-
-	wb.release();
-
-	data.resize(data_size);
-
-	Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data));
-	if (!texture->compressed) {
-		img->convert(real_format);
-	}
-
-	return Ref<Image>(img);
-
-#endif
-}
-*/
-
 Image::Format TextureStorage::texture_get_format(RID p_texture) const {
 	Texture *texture = texture_owner.get_or_null(p_texture);
 
@@ -1285,32 +1119,6 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const {
 
 GLuint TextureStorage::system_fbo = 0;
 
-void TextureStorage::_set_current_render_target(RID p_render_target) {
-	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
-
-	if (rt) {
-		if (rt->allocate_is_dirty) {
-			rt->allocate_is_dirty = false;
-			//_clear_render_target(rt);
-			//_update_render_target(rt);
-		}
-
-		frame.current_rt = rt;
-		ERR_FAIL_COND(!rt);
-
-		glViewport(rt->position.x, rt->position.y, rt->size.x, rt->size.y);
-
-		_dims.rt_width = rt->size.x;
-		_dims.rt_height = rt->size.y;
-		_dims.win_width = rt->size.x;
-		_dims.win_height = rt->size.y;
-
-	} else {
-		frame.current_rt = nullptr;
-		glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
-	}
-}
-
 void TextureStorage::_update_render_target(RenderTarget *rt) {
 	// do not allocate a render target with no size
 	if (rt->size.x <= 0 || rt->size.y <= 0) {
@@ -1318,14 +1126,14 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
 	}
 
 	// do not allocate a render target that is attached to the screen
-	if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) {
+	if (rt->direct_to_screen) {
 		rt->fbo = system_fbo;
 		return;
 	}
 
-	rt->color_internal_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? GL_RGBA8 : GL_RGB10_A2;
+	rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2;
 	rt->color_format = GL_RGBA;
-	rt->color_type = rt->flags[RENDER_TARGET_TRANSPARENT] ? GL_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
+	rt->color_type = rt->is_transparent ? GL_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
 	rt->image_format = Image::FORMAT_RGBA8;
 
 	glDisable(GL_SCISSOR_TEST);
@@ -1388,87 +1196,64 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
 
 	glClearColor(0, 0, 0, 0);
 	glClear(GL_COLOR_BUFFER_BIT);
+	glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
+}
 
+void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
+	ERR_FAIL_COND_MSG(rt->backbuffer_fbo != 0, "Cannot allocate RenderTarget backbuffer: already initialized.");
+	ERR_FAIL_COND(rt->direct_to_screen);
 	// Allocate mipmap chains for full screen blur
-	if (rt->size.x >= 2 && rt->size.y >= 2) {
-		for (int i = 0; i < 2; i++) {
-			ERR_FAIL_COND(rt->mip_maps[i].sizes.size());
-			int w = rt->size.x;
-			int h = rt->size.y;
-
-			if (i > 0) {
-				w >>= 1;
-				h >>= 1;
-			}
-
-			int level = 0;
-			GLsizei width = w;
-			GLsizei height = h;
+	// Limit mipmaps so smallest is 32x32 to avoid unnecessary framebuffer switches
+	int count = MAX(1, Image::get_image_required_mipmaps(rt->size.x, rt->size.y, Image::FORMAT_RGBA8) - 4);
+	if (rt->size.x > 40 && rt->size.y > 40) {
+		GLsizei width = rt->size.x;
+		GLsizei height = rt->size.y;
 
-			while (true) {
-				RenderTarget::MipMaps::Size mm;
-				mm.width = w;
-				mm.height = h;
-				rt->mip_maps[i].sizes.push_back(mm);
+		rt->mipmap_count = count;
 
-				w >>= 1;
-				h >>= 1;
+		glGenTextures(1, &rt->backbuffer);
+		glBindTexture(GL_TEXTURE_2D, rt->backbuffer);
 
-				if (w < 2 || h < 2) {
-					break;
-				}
-
-				level++;
-			}
-
-			glGenTextures(1, &rt->mip_maps[i].color);
-			glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].color);
-
-			for (int l = 0; l < level + 1; l++) {
-				glTexImage2D(GL_TEXTURE_2D, l, rt->color_internal_format, width, height, 0, rt->color_format, rt->color_type, nullptr);
-				width = MAX(1, (width / 2));
-				height = MAX(1, (height / 2));
-			}
-#ifdef GLES_OVER_GL
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level);
-#endif
+		for (int l = 0; l < count; l++) {
+			glTexImage2D(GL_TEXTURE_2D, l, rt->color_internal_format, width, height, 0, rt->color_format, rt->color_type, nullptr);
+			width = MAX(1, (width / 2));
+			height = MAX(1, (height / 2));
+		}
 
-			for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) {
-				RenderTarget::MipMaps::Size &mm = rt->mip_maps[i].sizes.write[j];
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count - 1);
 
-				glGenFramebuffers(1, &mm.fbo);
-				bind_framebuffer(mm.fbo);
+		glGenFramebuffers(1, &rt->backbuffer_fbo);
+		glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
 
-				glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->mip_maps[i].color, j);
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, 0);
 
-				GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-				if (status != GL_FRAMEBUFFER_COMPLETE) {
-					WARN_PRINT_ONCE("Cannot allocate mipmaps for canvas screen blur. Status: " + get_framebuffer_error(status));
-					bind_framebuffer_system();
-					return;
-				}
+		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+		if (status != GL_FRAMEBUFFER_COMPLETE) {
+			WARN_PRINT_ONCE("Cannot allocate mipmaps for canvas screen blur. Status: " + get_framebuffer_error(status));
+			glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
+			return;
+		}
 
-				glClearColor(1.0, 0.0, 1.0, 0.0);
-				glClear(GL_COLOR_BUFFER_BIT);
-			}
+		// Initialize all levels to opaque Magenta.
+		for (int j = 0; j < count; j++) {
+			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, j);
+			glClearColor(1.0, 0.0, 1.0, 1.0);
+			glClear(GL_COLOR_BUFFER_BIT);
+		}
 
-			rt->mip_maps[i].levels = level;
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, 0);
 
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);
-		}
-		rt->mip_maps_allocated = true;
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);
 	}
-
-	bind_framebuffer_system();
 }
 
 void TextureStorage::_clear_render_target(RenderTarget *rt) {
 	// there is nothing to clear when DIRECT_TO_SCREEN is used
-	if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) {
+	if (rt->direct_to_screen) {
 		return;
 	}
 
@@ -1504,17 +1289,11 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
 	tex->height = 0;
 	tex->active = false;
 
-	for (int i = 0; i < 2; i++) {
-		if (rt->mip_maps[i].sizes.size()) {
-			for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) {
-				glDeleteFramebuffers(1, &rt->mip_maps[i].sizes[j].fbo);
-			}
-
-			glDeleteTextures(1, &rt->mip_maps[i].color);
-			rt->mip_maps[i].sizes.clear();
-			rt->mip_maps[i].levels = 0;
-			rt->mip_maps[i].color = 0;
-		}
+	if (rt->backbuffer_fbo != 0) {
+		glDeleteFramebuffers(1, &rt->backbuffer_fbo);
+		glDeleteTextures(1, &rt->backbuffer);
+		rt->backbuffer = 0;
+		rt->backbuffer_fbo = 0;
 	}
 }
 
@@ -1523,9 +1302,6 @@ RID TextureStorage::render_target_create() {
 	//render_target.was_used = false;
 	render_target.clear_requested = false;
 
-	for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) {
-		render_target.flags[i] = false;
-	}
 	Texture t;
 	t.active = true;
 	t.render_target = &render_target;
@@ -1568,9 +1344,6 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in
 
 	rt->size = Size2i(p_width, p_height);
 
-	// print_line("render_target_set_size " + itos(p_render_target.get_id()) + ", w " + itos(p_width) + " h " + itos(p_height));
-
-	rt->allocate_is_dirty = true;
 	_update_render_target(rt);
 }
 
@@ -1642,7 +1415,6 @@ void TextureStorage::render_target_set_external_texture(RID p_render_target, uns
 			t->gl_format_cache = 0;
 			t->gl_internal_format_cache = 0;
 			t->gl_type_cache = 0;
-			t->srgb = false;
 			t->total_data_size = 0;
 			t->mipmaps = 1;
 			t->active = true;
@@ -1688,29 +1460,28 @@ void TextureStorage::render_target_set_external_texture(RID p_render_target, uns
 	}
 }
 
-void TextureStorage::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {
+void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_transparent) {
 	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
 	ERR_FAIL_COND(!rt);
 
-	// When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as
-	// those functions change how they operate depending on the value of DIRECT_TO_SCREEN
-	if (p_flag == RENDER_TARGET_DIRECT_TO_SCREEN && p_value != rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) {
-		_clear_render_target(rt);
-		rt->flags[p_flag] = p_value;
-		_update_render_target(rt);
-	}
+	rt->is_transparent = p_transparent;
 
-	rt->flags[p_flag] = p_value;
+	_clear_render_target(rt);
+	_update_render_target(rt);
+}
 
-	switch (p_flag) {
-		case RENDER_TARGET_TRANSPARENT: {
-			//must reset for these formats
-			_clear_render_target(rt);
-			_update_render_target(rt);
-		} break;
-		default: {
-		}
+void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) {
+	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+	ERR_FAIL_COND(!rt);
+
+	if (p_direct_to_screen == rt->direct_to_screen) {
+		return;
 	}
+	// When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as
+	// those functions change how they operate depending on the value of DIRECT_TO_SCREEN
+	_clear_render_target(rt);
+	rt->direct_to_screen = p_direct_to_screen;
+	_update_render_target(rt);
 }
 
 bool TextureStorage::render_target_was_used(RID p_render_target) {
@@ -1772,4 +1543,85 @@ Rect2i TextureStorage::render_target_get_sdf_rect(RID p_render_target) const {
 void TextureStorage::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
 }
 
+void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) {
+	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+	ERR_FAIL_COND(!rt);
+	ERR_FAIL_COND(rt->direct_to_screen);
+
+	if (rt->backbuffer_fbo == 0) {
+		_create_render_target_backbuffer(rt);
+	}
+
+	Rect2i region;
+	if (p_region == Rect2i()) {
+		region.size = rt->size;
+	} else {
+		region = Rect2i(Size2i(), rt->size).intersection(p_region);
+		if (region.size == Size2i()) {
+			return; //nothing to do
+		}
+	}
+
+	glDisable(GL_BLEND);
+	//single texture copy for backbuffer
+	glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_2D, rt->color);
+	GLES3::CopyEffects::get_singleton()->copy_screen();
+
+	if (p_gen_mipmaps) {
+		GLES3::CopyEffects::get_singleton()->bilinear_blur(rt->backbuffer, rt->mipmap_count, region);
+		glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+	}
+
+	glEnable(GL_BLEND); // 2D almost always uses blend.
+}
+
+void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) {
+	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+	ERR_FAIL_COND(!rt);
+	ERR_FAIL_COND(rt->direct_to_screen);
+
+	if (rt->backbuffer_fbo == 0) {
+		_create_render_target_backbuffer(rt);
+	}
+
+	Rect2i region;
+	if (p_region == Rect2i()) {
+		// Just do a full screen clear;
+		glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+		glClearColor(p_color.r, p_color.g, p_color.b, p_color.a);
+		glClear(GL_COLOR_BUFFER_BIT);
+	} else {
+		region = Rect2i(Size2i(), rt->size).intersection(p_region);
+		if (region.size == Size2i()) {
+			return; //nothing to do
+		}
+		glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+		GLES3::CopyEffects::get_singleton()->set_color(p_color, region);
+	}
+}
+
+void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) {
+	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+	ERR_FAIL_COND(!rt);
+
+	if (rt->backbuffer_fbo == 0) {
+		_create_render_target_backbuffer(rt);
+	}
+
+	Rect2i region;
+	if (p_region == Rect2i()) {
+		region.size = rt->size;
+	} else {
+		region = Rect2i(Size2i(), rt->size).intersection(p_region);
+		if (region.size == Size2i()) {
+			return; //nothing to do
+		}
+	}
+
+	GLES3::CopyEffects::get_singleton()->bilinear_blur(rt->backbuffer, rt->mipmap_count, region);
+	glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+}
+
 #endif // GLES3_ENABLED

+ 25 - 68
drivers/gles3/storage/texture_storage.h

@@ -71,6 +71,17 @@ namespace GLES3 {
 #define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
 #define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
 
+#define _EXT_COMPRESSED_R11_EAC 0x9270
+#define _EXT_COMPRESSED_SIGNED_R11_EAC 0x9271
+#define _EXT_COMPRESSED_RG11_EAC 0x9272
+#define _EXT_COMPRESSED_SIGNED_RG11_EAC 0x9273
+#define _EXT_COMPRESSED_RGB8_ETC2 0x9274
+#define _EXT_COMPRESSED_SRGB8_ETC2 0x9275
+#define _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
+#define _EXT_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
+#define _EXT_COMPRESSED_RGBA8_ETC2_EAC 0x9278
+#define _EXT_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
+
 #define _GL_TEXTURE_EXTERNAL_OES 0x8D65
 
 #ifdef GLES_OVER_GL
@@ -161,8 +172,6 @@ struct Texture {
 
 	bool compressed = false;
 
-	bool srgb = false;
-
 	bool resize_to_po2 = false;
 
 	bool active = false;
@@ -179,9 +188,6 @@ struct Texture {
 	RS::TextureDetectCallback detect_3d_callback = nullptr;
 	void *detect_3d_callback_ud = nullptr;
 
-	RS::TextureDetectCallback detect_srgb = nullptr;
-	void *detect_srgb_ud = nullptr;
-
 	RS::TextureDetectCallback detect_normal_callback = nullptr;
 	void *detect_normal_callback_ud = nullptr;
 
@@ -213,8 +219,6 @@ struct Texture {
 		redraw_if_visible = o.redraw_if_visible;
 		detect_3d_callback = o.detect_3d_callback;
 		detect_3d_callback_ud = o.detect_3d_callback_ud;
-		detect_srgb = o.detect_srgb;
-		detect_srgb_ud = o.detect_srgb_ud;
 		detect_normal_callback = o.detect_normal_callback;
 		detect_normal_callback_ud = o.detect_normal_callback_ud;
 		detect_roughness_callback = o.detect_roughness_callback;
@@ -311,21 +315,6 @@ private:
 };
 
 struct RenderTarget {
-	struct MipMaps {
-		struct Size {
-			GLuint fbo;
-			int width;
-			int height;
-		};
-
-		Vector<Size> sizes;
-		GLuint color = 0;
-		int levels = 0;
-
-		MipMaps() {
-		}
-	};
-
 	struct External {
 		GLuint fbo = 0;
 		GLuint color = 0;
@@ -338,23 +327,21 @@ struct RenderTarget {
 
 	Point2i position = Point2i(0, 0);
 	Size2i size = Size2i(0, 0);
+	int mipmap_count = 1;
 	RID self;
 	GLuint fbo = 0;
 	GLuint color = 0;
+	GLuint backbuffer_fbo = 0;
+	GLuint backbuffer = 0;
 
 	GLuint color_internal_format = GL_RGBA8;
 	GLuint color_format = GL_RGBA;
 	GLuint color_type = GL_UNSIGNED_BYTE;
 	Image::Format image_format = Image::FORMAT_RGBA8;
 
-	MipMaps mip_maps[2];
-	bool mip_maps_allocated = false;
-
-	bool flags[RendererTextureStorage::RENDER_TARGET_FLAG_MAX];
+	bool is_transparent = false;
+	bool direct_to_screen = false;
 
-	// instead of allocating sized render targets immediately,
-	// defer this for faster startup
-	bool allocate_is_dirty = false;
 	bool used_in_frame = false;
 	RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
 
@@ -364,9 +351,6 @@ struct RenderTarget {
 	bool clear_requested = false;
 
 	RenderTarget() {
-		for (int i = 0; i < RendererTextureStorage::RENDER_TARGET_FLAG_MAX; ++i) {
-			flags[i] = false;
-		}
 	}
 };
 
@@ -384,28 +368,15 @@ private:
 
 	mutable RID_Owner<Texture> texture_owner;
 
-	Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const;
+	Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const;
 
 	/* Render Target API */
 
 	mutable RID_Owner<RenderTarget> render_target_owner;
 
-	// make access easier to these
-	struct Dimensions {
-		// render target
-		int rt_width;
-		int rt_height;
-
-		// window
-		int win_width;
-		int win_height;
-		Dimensions() {
-			rt_width = 0;
-			rt_height = 0;
-			win_width = 0;
-			win_height = 0;
-		}
-	} _dims;
+	void _clear_render_target(RenderTarget *rt);
+	void _update_render_target(RenderTarget *rt);
+	void _create_render_target_backbuffer(RenderTarget *rt);
 
 public:
 	static TextureStorage *get_singleton();
@@ -522,20 +493,9 @@ public:
 
 	static GLuint system_fbo;
 
-	// TODO this should be moved back to storage or removed
-	struct Frame {
-		GLES3::RenderTarget *current_rt;
-	} frame;
-
 	RenderTarget *get_render_target(RID p_rid) { return render_target_owner.get_or_null(p_rid); };
 	bool owns_render_target(RID p_rid) { return render_target_owner.owns(p_rid); };
 
-	// TODO these internals should be private
-	void _clear_render_target(RenderTarget *rt);
-	void _update_render_target(RenderTarget *rt);
-	void _create_render_target_backbuffer(RenderTarget *rt);
-	void _set_current_render_target(RID p_render_target);
-
 	virtual RID render_target_create() override;
 	virtual void render_target_free(RID p_rid) override;
 	virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override;
@@ -544,7 +504,8 @@ public:
 	virtual RID render_target_get_texture(RID p_render_target) override;
 	virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override;
 
-	virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override;
+	virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override;
+	virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override;
 	virtual bool render_target_was_used(RID p_render_target) override;
 	void render_target_clear_used(RID p_render_target);
 
@@ -563,13 +524,9 @@ public:
 	Rect2i render_target_get_sdf_rect(RID p_render_target) const override;
 	void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override;
 
-	void bind_framebuffer(GLuint framebuffer) {
-		glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
-	}
-
-	void bind_framebuffer_system() {
-		glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
-	}
+	void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps);
+	void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color);
+	void render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region);
 
 	String get_framebuffer_error(GLenum p_status);
 };

+ 0 - 112
drivers/gles3/texture_loader_gles3.cpp

@@ -1,112 +0,0 @@
-/*************************************************************************/
-/*  texture_loader_gles3.cpp                                             */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* 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.                */
-/*************************************************************************/
-
-#include "texture_loader_gles3.h"
-
-#ifdef GLES3_ENABLED
-
-#include "core/io/file_access.h"
-#include "core/string/print_string.h"
-
-#include <string.h>
-
-Ref<Resource> ResourceFormatGLES2Texture::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
-	unsigned int width = 8;
-	unsigned int height = 8;
-
-	//We just use some format
-	Image::Format fmt = Image::FORMAT_RGB8;
-	int rowsize = 3 * width;
-
-	Vector<uint8_t> dstbuff;
-
-	dstbuff.resize(rowsize * height);
-
-	uint8_t **row_p = memnew_arr(uint8_t *, height);
-
-	for (unsigned int i = 0; i < height; i++) {
-		row_p[i] = nullptr; // No colors any more, I want them to turn black.
-	}
-
-	memdelete_arr(row_p);
-
-	Ref<Image> img = memnew(Image(width, height, 0, fmt, dstbuff));
-
-	Ref<ImageTexture> texture = memnew(ImageTexture);
-	texture->create_from_image(img);
-
-	if (r_error) {
-		*r_error = OK;
-	}
-
-	return texture;
-}
-
-void ResourceFormatGLES2Texture::get_recognized_extensions(List<String> *p_extensions) const {
-	p_extensions->push_back("bmp");
-	p_extensions->push_back("dds");
-	p_extensions->push_back("exr");
-	p_extensions->push_back("jpeg");
-	p_extensions->push_back("jpg");
-	p_extensions->push_back("hdr");
-	p_extensions->push_back("pkm");
-	p_extensions->push_back("png");
-	p_extensions->push_back("pvr");
-	p_extensions->push_back("svg");
-	p_extensions->push_back("tga");
-	p_extensions->push_back("webp");
-}
-
-bool ResourceFormatGLES2Texture::handles_type(const String &p_type) const {
-	return ClassDB::is_parent_class(p_type, "Texture2D");
-}
-
-String ResourceFormatGLES2Texture::get_resource_type(const String &p_path) const {
-	String extension = p_path.get_extension().to_lower();
-	if (
-			extension == "bmp" ||
-			extension == "dds" ||
-			extension == "exr" ||
-			extension == "jpeg" ||
-			extension == "jpg" ||
-			extension == "hdr" ||
-			extension == "pkm" ||
-			extension == "png" ||
-			extension == "pvr" ||
-			extension == "svg" ||
-			extension == "tga" ||
-			extension == "webp") {
-		return "ImageTexture";
-	}
-
-	return "";
-}
-
-#endif

+ 2 - 1
servers/rendering/dummy/storage/texture_storage.h

@@ -152,7 +152,8 @@ public:
 	virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override {}
 	virtual RID render_target_get_texture(RID p_render_target) override { return RID(); }
 	virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override {}
-	virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override {}
+	virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override {}
+	virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override {}
 	virtual bool render_target_was_used(RID p_render_target) override { return false; }
 	virtual void render_target_set_as_unused(RID p_render_target) override {}
 

+ 7 - 7
servers/rendering/renderer_rd/storage_rd/texture_storage.cpp

@@ -2075,7 +2075,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
 	//until we implement support for HDR monitors (and render target is attached to screen), this is enough.
 	rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
 	rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
-	rt->image_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8;
+	rt->image_format = rt->is_transparent ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8;
 
 	RD::TextureFormat rd_format;
 	RD::TextureView rd_view;
@@ -2127,7 +2127,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
 		//so transparent can be supported
 		RD::TextureView view;
 		view.format_override = rt->color_format;
-		if (!rt->flags[RENDER_TARGET_TRANSPARENT]) {
+		if (!rt->is_transparent) {
 			view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
 		}
 		tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->color);
@@ -2194,9 +2194,6 @@ RID TextureStorage::render_target_create() {
 	render_target.was_used = false;
 	render_target.clear_requested = false;
 
-	for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) {
-		render_target.flags[i] = false;
-	}
 	_update_render_target(&render_target);
 	return render_target_owner.make_rid(render_target);
 }
@@ -2240,13 +2237,16 @@ RID TextureStorage::render_target_get_texture(RID p_render_target) {
 void TextureStorage::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
 }
 
-void TextureStorage::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {
+void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_is_transparent) {
 	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
 	ERR_FAIL_COND(!rt);
-	rt->flags[p_flag] = p_value;
+	rt->is_transparent = p_is_transparent;
 	_update_render_target(rt);
 }
 
+void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_value) {
+}
+
 bool TextureStorage::render_target_was_used(RID p_render_target) {
 	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
 	ERR_FAIL_COND_V(!rt, false);

+ 3 - 2
servers/rendering/renderer_rd/storage_rd/texture_storage.h

@@ -207,7 +207,7 @@ struct RenderTarget {
 	RD::DataFormat color_format_srgb = RD::DATA_FORMAT_R4G4_UNORM_PACK8;
 	Image::Format image_format = Image::FORMAT_L8;
 
-	bool flags[RendererTextureStorage::RENDER_TARGET_FLAG_MAX];
+	bool is_transparent = false;
 
 	bool sdf_enabled = false;
 
@@ -525,7 +525,8 @@ public:
 	virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override;
 	virtual RID render_target_get_texture(RID p_render_target) override;
 	virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override;
-	virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override;
+	virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override;
+	virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override;
 	virtual bool render_target_was_used(RID p_render_target) override;
 	virtual void render_target_set_as_unused(RID p_render_target) override;
 

+ 2 - 2
servers/rendering/renderer_viewport.cpp

@@ -866,7 +866,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
 		RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
 	}
 
-	RSG::texture_storage->render_target_set_flag(viewport->render_target, RendererTextureStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable);
+	RSG::texture_storage->render_target_set_direct_to_screen(viewport->render_target, p_enable);
 	viewport->viewport_render_direct_to_screen = p_enable;
 
 	// if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation
@@ -980,7 +980,7 @@ void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool
 	Viewport *viewport = viewport_owner.get_or_null(p_viewport);
 	ERR_FAIL_COND(!viewport);
 
-	RSG::texture_storage->render_target_set_flag(viewport->render_target, RendererTextureStorage::RENDER_TARGET_TRANSPARENT, p_enabled);
+	RSG::texture_storage->render_target_set_transparent(viewport->render_target, p_enabled);
 	viewport->transparent_bg = p_enabled;
 }
 

+ 2 - 7
servers/rendering/storage/texture_storage.h

@@ -111,12 +111,6 @@ public:
 
 	/* RENDER TARGET */
 
-	enum RenderTargetFlags {
-		RENDER_TARGET_TRANSPARENT,
-		RENDER_TARGET_DIRECT_TO_SCREEN,
-		RENDER_TARGET_FLAG_MAX
-	};
-
 	virtual RID render_target_create() = 0;
 	virtual void render_target_free(RID p_rid) = 0;
 
@@ -124,7 +118,8 @@ public:
 	virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) = 0;
 	virtual RID render_target_get_texture(RID p_render_target) = 0;
 	virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0;
-	virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0;
+	virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) = 0;
+	virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) = 0;
 	virtual bool render_target_was_used(RID p_render_target) = 0;
 	virtual void render_target_set_as_unused(RID p_render_target) = 0;