소스 검색

WIP New GLES3 Shader Compiler

Uses versions and specializations (more similar to RenderingDevice version)
reduz 3 년 전
부모
커밋
98ac002c34

+ 34 - 34
drivers/gles3/rasterizer_canvas_base_gles3.cpp

@@ -118,9 +118,9 @@ void RasterizerCanvasBaseGLES3::canvas_begin() {
 	state.using_large_vertex = false;
 	state.using_modulate = false;
 
-	state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_LIGHT_ANGLE, false);
-	state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_MODULATE, false);
-	state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_LARGE_VERTEX, false);
+	state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_ATTRIB_LIGHT_ANGLE, false);
+	state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_ATTRIB_MODULATE, false);
+	state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_ATTRIB_LARGE_VERTEX, false);
 	state.canvas_shader.bind();
 
 	int viewport_x, viewport_y, viewport_width, viewport_height;
@@ -248,29 +248,29 @@ void RasterizerCanvasBaseGLES3::canvas_end() {
 }
 
 void RasterizerCanvasBaseGLES3::draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src) {
-	state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y));
-	state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y));
+	state.canvas_shader.set_uniform(CanvasOldShaderGLES3::DST_RECT, Color(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y));
+	state.canvas_shader.set_uniform(CanvasOldShaderGLES3::SRC_RECT, Color(p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y));
 	_bind_quad_buffer();
 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 }
 
 void RasterizerCanvasBaseGLES3::_set_texture_rect_mode(bool p_texture_rect, bool p_light_angle, bool p_modulate, bool p_large_vertex) {
 	// always set this directly (this could be state checked)
-	state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_TEXTURE_RECT, p_texture_rect);
+	state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_TEXTURE_RECT, p_texture_rect);
 
 	if (state.using_light_angle != p_light_angle) {
 		state.using_light_angle = p_light_angle;
-		state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_LIGHT_ANGLE, p_light_angle);
+		state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_ATTRIB_LIGHT_ANGLE, p_light_angle);
 	}
 
 	if (state.using_modulate != p_modulate) {
 		state.using_modulate = p_modulate;
-		state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_MODULATE, p_modulate);
+		state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_ATTRIB_MODULATE, p_modulate);
 	}
 
 	if (state.using_large_vertex != p_large_vertex) {
 		state.using_large_vertex = p_large_vertex;
-		state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_LARGE_VERTEX, p_large_vertex);
+		state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_ATTRIB_LARGE_VERTEX, p_large_vertex);
 	}
 }
 
@@ -320,7 +320,7 @@ RasterizerStorageGLES3::Texture *RasterizerCanvasBaseGLES3::_bind_canvas_texture
 
 	if (p_normal_map == state.current_normal) {
 		//do none
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, state.current_normal.is_valid());
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::USE_DEFAULT_NORMAL, state.current_normal.is_valid());
 
 	} else if (p_normal_map.is_valid()) {
 		RasterizerStorageGLES3::Texture *normal_map = storage->texture_owner.get_or_null(p_normal_map);
@@ -329,7 +329,7 @@ RasterizerStorageGLES3::Texture *RasterizerCanvasBaseGLES3::_bind_canvas_texture
 			state.current_normal = RID();
 			glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2);
 			glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex);
-			state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, false);
+			state.canvas_shader.set_uniform(CanvasOldShaderGLES3::USE_DEFAULT_NORMAL, false);
 
 		} else {
 			if (normal_map->redraw_if_visible) { //check before proxy, because this is usually used with proxies
@@ -341,14 +341,14 @@ RasterizerStorageGLES3::Texture *RasterizerCanvasBaseGLES3::_bind_canvas_texture
 			glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2);
 			glBindTexture(GL_TEXTURE_2D, normal_map->tex_id);
 			state.current_normal = p_normal_map;
-			state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, true);
+			state.canvas_shader.set_uniform(CanvasOldShaderGLES3::USE_DEFAULT_NORMAL, true);
 		}
 
 	} else {
 		state.current_normal = RID();
 		glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2);
 		glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex);
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, false);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::USE_DEFAULT_NORMAL, false);
 	}
 
 	return tex_return;
@@ -432,44 +432,44 @@ void RasterizerCanvasBaseGLES3::_bind_quad_buffer() {
 }
 
 void RasterizerCanvasBaseGLES3::_set_uniforms() {
-	state.canvas_shader.set_uniform(CanvasShaderGLES3::PROJECTION_MATRIX, state.uniforms.projection_matrix);
-	state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
-	state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.uniforms.extra_matrix);
+	state.canvas_shader.set_uniform(CanvasOldShaderGLES3::PROJECTION_MATRIX, state.uniforms.projection_matrix);
+	state.canvas_shader.set_uniform(CanvasOldShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
+	state.canvas_shader.set_uniform(CanvasOldShaderGLES3::EXTRA_MATRIX, state.uniforms.extra_matrix);
 
-	state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, state.uniforms.final_modulate);
+	state.canvas_shader.set_uniform(CanvasOldShaderGLES3::FINAL_MODULATE, state.uniforms.final_modulate);
 
-	state.canvas_shader.set_uniform(CanvasShaderGLES3::TIME, storage->frame.time[0]);
+	state.canvas_shader.set_uniform(CanvasOldShaderGLES3::TIME, storage->frame.time[0]);
 
 	if (storage->frame.current_rt) {
 		Vector2 screen_pixel_size;
 		screen_pixel_size.x = 1.0 / storage->frame.current_rt->width;
 		screen_pixel_size.y = 1.0 / storage->frame.current_rt->height;
 
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, screen_pixel_size);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::SCREEN_PIXEL_SIZE, screen_pixel_size);
 	}
 
 	if (state.using_skeleton) {
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM, state.skeleton_transform);
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM_INVERSE, state.skeleton_transform_inverse);
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TEXTURE_SIZE, state.skeleton_texture_size);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::SKELETON_TRANSFORM, state.skeleton_transform);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::SKELETON_TRANSFORM_INVERSE, state.skeleton_transform_inverse);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::SKELETON_TEXTURE_SIZE, state.skeleton_texture_size);
 	}
 
 	if (state.using_light) {
 		Light *light = state.using_light;
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_MATRIX, light->light_shader_xform);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::LIGHT_MATRIX, light->light_shader_xform);
 		Transform2D basis_inverse = light->light_shader_xform.affine_inverse().orthonormalized();
 		basis_inverse.elements[2] = Vector2();
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_MATRIX_INVERSE, basis_inverse);
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_LOCAL_MATRIX, light->xform_cache.affine_inverse());
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_COLOR, light->color * light->energy);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::LIGHT_MATRIX_INVERSE, basis_inverse);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::LIGHT_LOCAL_MATRIX, light->xform_cache.affine_inverse());
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::LIGHT_COLOR, light->color * light->energy);
 		//		state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_POS, light->light_shader_pos);
 		// FTODO
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_POS, light->light_shader_xform.elements[2]);
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_HEIGHT, light->height);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::LIGHT_POS, light->light_shader_xform.elements[2]);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::LIGHT_HEIGHT, light->height);
 
 		// FTODO
 		//state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_OUTSIDE_ALPHA, light->mode == RS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0);
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_OUTSIDE_ALPHA, 0.0f);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::LIGHT_OUTSIDE_ALPHA, 0.0f);
 
 		if (state.using_shadow) {
 			// FTODO
@@ -749,7 +749,7 @@ void RasterizerCanvasBaseGLES3::_legacy_draw_poly_triangles(Item::CommandPolygon
 
 	if (texture) {
 		Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
-		state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
+		state.canvas_shader.set_uniform(CanvasOldShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
 	}
 
 	_draw_polygon(pd.indices.ptr(), pd.indices.size(), pd.points.size(), pd.points.ptr(), pd.uvs.ptr(), pd.colors.ptr(), pd.colors.size() == 1, nullptr, nullptr);
@@ -788,7 +788,7 @@ void RasterizerCanvasBaseGLES3::_legacy_draw_primitive(Item::CommandPrimitive *p
 	glDisableVertexAttribArray(RS::ARRAY_COLOR);
 	glVertexAttrib4fv(RS::ARRAY_COLOR, p_pr->colors[0].components);
 
-	state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
+	state.canvas_shader.set_uniform(CanvasOldShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
 
 	_draw_gui_primitive(p_pr->point_count, p_pr->points, NULL, NULL);
 }
@@ -806,7 +806,7 @@ void RasterizerCanvasBaseGLES3::_legacy_draw_line(Item::CommandPrimitive *p_pr,
 	glDisableVertexAttribArray(RS::ARRAY_COLOR);
 	glVertexAttrib4fv(RS::ARRAY_COLOR, p_pr->colors[0].components);
 
-	state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
+	state.canvas_shader.set_uniform(CanvasOldShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
 
 #ifdef GLES_OVER_GL
 //		if (line->antialiased)
@@ -1312,13 +1312,13 @@ void RasterizerCanvasBaseGLES3::initialize() {
 	state.canvas_shadow_shader.init();
 	state.canvas_shader.init();
 	_set_texture_rect_mode(true);
-	state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows);
+	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(CanvasShaderGLES3::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false));
+	state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false));
 
 	state.using_light = NULL;
 	state.using_transparent_rt = false;

+ 2 - 2
drivers/gles3/rasterizer_canvas_base_gles3.h

@@ -41,7 +41,7 @@
 #include "servers/rendering/renderer_canvas_render.h"
 #include "servers/rendering/renderer_compositor.h"
 
-#include "shaders/canvas.glsl.gen.h"
+#include "shaders/canvas_old.glsl.gen.h"
 #include "shaders/canvas_shadow.glsl.gen.h"
 #include "shaders/lens_distorted.glsl.gen.h"
 
@@ -94,7 +94,7 @@ public:
 		CanvasItemUBO canvas_item_ubo_data;
 		GLuint canvas_item_ubo;
 		bool canvas_texscreen_used;
-		CanvasShaderGLES3 canvas_shader;
+		CanvasOldShaderGLES3 canvas_shader;
 		CanvasShadowShaderGLES3 canvas_shadow_shader;
 		LensDistortedShaderGLES3 lens_shader;
 

+ 30 - 30
drivers/gles3/rasterizer_canvas_gles3.cpp

@@ -430,7 +430,7 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
 									texture = texture->get_ptr();
 
 									if (next_power_of_2(texture->alloc_width) != (unsigned int)texture->alloc_width && next_power_of_2(texture->alloc_height) != (unsigned int)texture->alloc_height) {
-										state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_FORCE_REPEAT, true);
+										state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_FORCE_REPEAT, true);
 										can_tile = false;
 									}
 								}
@@ -510,7 +510,7 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
 										flip_v = !flip_v;
 									}
 
-									state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
+									state.canvas_shader.set_uniform(CanvasOldShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
 
 									bool untile = false;
 
@@ -558,7 +558,7 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
 										Vector2(1.0, 0.0),
 									};
 
-									state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2());
+									state.canvas_shader.set_uniform(CanvasOldShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2());
 									_draw_gui_primitive(4, points, NULL, uvs);
 								}
 
@@ -589,8 +589,8 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
 										dst_rect.size.height *= -1;
 									}
 
-									state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
-									state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(0, 0, 1, 1));
+									state.canvas_shader.set_uniform(CanvasOldShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
+									state.canvas_shader.set_uniform(CanvasOldShaderGLES3::SRC_RECT, Color(0, 0, 1, 1));
 
 									glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 									storage->info.render._2d_draw_call_count++;
@@ -628,10 +628,10 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
 										dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform
 									}
 
-									state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
+									state.canvas_shader.set_uniform(CanvasOldShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
 
-									state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
-									state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y));
+									state.canvas_shader.set_uniform(CanvasOldShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
+									state.canvas_shader.set_uniform(CanvasOldShaderGLES3::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y));
 
 									glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 									storage->info.render._2d_draw_call_count++;
@@ -645,7 +645,7 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
 								glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 							}
 
-							state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_FORCE_REPEAT, false);
+							state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_FORCE_REPEAT, false);
 
 						} break;
 						case Item::Command::TYPE_NINEPATCH: {
@@ -678,7 +678,7 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
 							Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height);
 
 							// state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
-							state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
+							state.canvas_shader.set_uniform(CanvasOldShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
 
 							Rect2 source = np->source;
 							if (source.size.x == 0 && source.size.y == 0) {
@@ -1151,7 +1151,7 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
 						case Item::Command::TYPE_TRANSFORM: {
 							Item::CommandTransform *transform = static_cast<Item::CommandTransform *>(command);
 							state.uniforms.extra_matrix = transform->xform;
-							state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.uniforms.extra_matrix);
+							state.canvas_shader.set_uniform(CanvasOldShaderGLES3::EXTRA_MATRIX, state.uniforms.extra_matrix);
 						} break;
 
 						case Item::Command::TYPE_PARTICLES: {
@@ -1250,7 +1250,7 @@ void RasterizerCanvasGLES3::canvas_render_items_implementation(Item *p_item_list
 	ris.item_group_light = p_light;
 	ris.item_group_base_transform = p_base_transform;
 
-	state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, false);
+	state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_SKELETON, false);
 
 	state.current_tex = RID();
 	state.current_tex_ptr = NULL;
@@ -1270,7 +1270,7 @@ void RasterizerCanvasGLES3::canvas_render_items_implementation(Item *p_item_list
 		glDisable(GL_SCISSOR_TEST);
 	}
 
-	state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, false);
+	state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_SKELETON, false);
 }
 
 // Legacy non-batched implementation for regression testing.
@@ -1555,7 +1555,7 @@ void RasterizerCanvasGLES3::_legacy_canvas_render_item(Item *p_ci, RenderItemSta
 				}
 
 				if (!light_used) {
-					state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, true);
+					state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_LIGHTING, true);
 					light_used = true;
 				}
 
@@ -1563,20 +1563,20 @@ void RasterizerCanvasGLES3::_legacy_canvas_render_item(Item *p_ci, RenderItemSta
 				//bool has_shadow = light->shadow_buffer.is_valid() && p_ci->light_mask & light->item_shadow_mask;
 				bool has_shadow = light->use_shadow && p_ci->light_mask & light->item_shadow_mask;
 
-				state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, has_shadow);
+				state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_SHADOWS, has_shadow);
 				if (has_shadow) {
 					// FTODO
 					//state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_USE_GRADIENT, light->shadow_gradient_length > 0);
-					state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_USE_GRADIENT, false);
-					state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_NONE);
+					state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_USE_GRADIENT, false);
+					state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_NEAREST, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_NONE);
 					//state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF3);
-					state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, false);
-					state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF5);
-					state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, false);
+					state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_PCF3, false);
+					state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_PCF5, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF5);
+					state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_PCF7, false);
 					//state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF7);
 					//state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF9);
-					state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, false);
-					state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF13);
+					state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_PCF9, false);
+					state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_PCF13, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF13);
 				}
 
 				state.canvas_shader.bind();
@@ -1607,14 +1607,14 @@ void RasterizerCanvasGLES3::_legacy_canvas_render_item(Item *p_ci, RenderItemSta
 		}
 
 		if (light_used) {
-			state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, false);
-			state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, false);
-			state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST, false);
-			state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, false);
-			state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5, false);
-			state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, false);
-			state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, false);
-			state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, false);
+			state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_LIGHTING, false);
+			state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_SHADOWS, false);
+			state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_NEAREST, false);
+			state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_PCF3, false);
+			state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_PCF5, false);
+			state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_PCF7, false);
+			state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_PCF9, false);
+			state.canvas_shader.set_conditional(CanvasOldShaderGLES3::SHADOW_FILTER_PCF13, false);
 
 			state.canvas_shader.bind();
 

+ 1 - 1
drivers/gles3/rasterizer_gles3.cpp

@@ -31,7 +31,7 @@
 #include "rasterizer_gles3.h"
 
 #ifdef GLES3_BACKEND_ENABLED
-#include "shader_gles3.h"
+#include "shader_old_gles3.h"
 
 #include "core/config/project_settings.h"
 #include "core/os/os.h"

+ 2 - 2
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -1559,8 +1559,8 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const {
 		return; //just invalid, but no error
 	}
 
-	ShaderCompilerGLES3::GeneratedCode gen_code;
-	ShaderCompilerGLES3::IdentifierActions *actions = NULL;
+	ShaderCompilerOLDGLES3::GeneratedCode gen_code;
+	ShaderCompilerOLDGLES3::IdentifierActions *actions = NULL;
 
 	switch (p_shader->mode) {
 		case RS::SHADER_CANVAS_ITEM: {

+ 7 - 7
drivers/gles3/rasterizer_storage_gles3.h

@@ -41,8 +41,8 @@
 #include "servers/rendering/renderer_compositor.h"
 #include "servers/rendering/renderer_storage.h"
 #include "servers/rendering/shader_language.h"
-#include "shader_compiler_gles3.h"
-#include "shader_gles3.h"
+#include "shader_compiler_old_gles3.h"
+#include "shader_old_gles3.h"
 
 #include "shaders/copy.glsl.gen.h"
 #include "shaders/cubemap_filter.glsl.gen.h"
@@ -134,14 +134,14 @@ public:
 	} resources;
 
 	mutable struct Shaders {
-		ShaderCompilerGLES3 compiler;
+		ShaderCompilerOLDGLES3 compiler;
 
 		CopyShaderGLES3 copy;
 		CubemapFilterShaderGLES3 cubemap_filter;
 
-		ShaderCompilerGLES3::IdentifierActions actions_canvas;
-		ShaderCompilerGLES3::IdentifierActions actions_scene;
-		ShaderCompilerGLES3::IdentifierActions actions_particles;
+		ShaderCompilerOLDGLES3::IdentifierActions actions_canvas;
+		ShaderCompilerOLDGLES3::IdentifierActions actions_scene;
+		ShaderCompilerOLDGLES3::IdentifierActions actions_particles;
 
 	} shaders;
 
@@ -567,7 +567,7 @@ public:
 		RID self;
 
 		RS::ShaderMode mode;
-		ShaderGLES3 *shader;
+		ShaderOLDGLES3 *shader;
 		String code;
 		SelfList<Material>::List materials;
 

+ 6 - 6
drivers/gles3/shader_compiler_gles3.cpp → drivers/gles3/shader_compiler_old_gles3.cpp

@@ -28,7 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#include "shader_compiler_gles3.h"
+#include "shader_compiler_old_gles3.h"
 #ifdef GLES3_BACKEND_ENABLED
 
 #include "core/config/project_settings.h"
@@ -213,7 +213,7 @@ static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNo
 	}
 }
 
-void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, StringBuilder &r_to_add, Set<StringName> &r_added) {
+void ShaderCompilerOLDGLES3::_dump_function_deps(SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, StringBuilder &r_to_add, Set<StringName> &r_added) {
 	int fidx = -1;
 
 	for (int i = 0; i < p_node->functions.size(); i++) {
@@ -272,7 +272,7 @@ void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const Stri
 	}
 }
 
-String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope) {
+String ShaderCompilerOLDGLES3::_dump_node_code(SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope) {
 	StringBuilder code;
 
 	switch (p_node->type) {
@@ -852,13 +852,13 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 	return code.as_string();
 }
 
-ShaderLanguage::DataType ShaderCompilerGLES3::_get_variable_type(const StringName &p_type) {
+ShaderLanguage::DataType ShaderCompilerOLDGLES3::_get_variable_type(const StringName &p_type) {
 	//	RS::GlobalVariableType gvt = ((RasterizerStorageRD *)(RendererStorage::base_singleton))->global_variable_get_type_internal(p_type);
 	RS::GlobalVariableType gvt = RS::GLOBAL_VAR_TYPE_MAX;
 	return RS::global_variable_type_get_shader_datatype(gvt);
 }
 
-Error ShaderCompilerGLES3::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) {
+Error ShaderCompilerOLDGLES3::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) {
 	ShaderLanguage::VaryingFunctionNames var_names;
 
 	ShaderLanguage::ShaderCompileInfo info;
@@ -901,7 +901,7 @@ Error ShaderCompilerGLES3::compile(RS::ShaderMode p_mode, const String &p_code,
 	return OK;
 }
 
-ShaderCompilerGLES3::ShaderCompilerGLES3() {
+ShaderCompilerOLDGLES3::ShaderCompilerOLDGLES3() {
 	/** CANVAS ITEM SHADER **/
 
 	actions[RS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy";

+ 4 - 4
drivers/gles3/shader_compiler_gles3.h → drivers/gles3/shader_compiler_old_gles3.h

@@ -28,8 +28,8 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#ifndef SHADER_COMPILER_OPENGL_H
-#define SHADER_COMPILER_OPENGL_H
+#ifndef SHADER_COMPILER_OLD_OPENGL_H
+#define SHADER_COMPILER_OLD_OPENGL_H
 
 #include "drivers/gles3/rasterizer_platforms.h"
 #ifdef GLES3_BACKEND_ENABLED
@@ -40,7 +40,7 @@
 #include "servers/rendering/shader_types.h"
 #include "servers/rendering_server.h"
 
-class ShaderCompilerGLES3 {
+class ShaderCompilerOLDGLES3 {
 public:
 	struct IdentifierActions {
 		Map<StringName, Pair<int *, int>> render_mode_values;
@@ -98,7 +98,7 @@ private:
 public:
 	Error compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code);
 
-	ShaderCompilerGLES3();
+	ShaderCompilerOLDGLES3();
 };
 
 #endif // GLES3_BACKEND_ENABLED

+ 486 - 911
drivers/gles3/shader_gles3.cpp

@@ -29,378 +29,301 @@
 /*************************************************************************/
 
 #include "shader_gles3.h"
-#include "drivers/gles3/rasterizer_platforms.h"
 #ifdef GLES3_BACKEND_ENABLED
 
-#include "rasterizer_gles3.h"
-#include "rasterizer_storage_gles3.h"
+#include "core/io/compression.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
 
-#include "core/config/project_settings.h"
-#include "core/os/memory.h"
-#include "core/string/print_string.h"
-#include "core/string/string_builder.h"
+void ShaderGLES3::_add_stage(const char *p_code, StageType p_stage_type) {
+	Vector<String> lines = String(p_code).split("\n");
 
-// #define DEBUG_OPENGL
+	String text;
 
-// #include "shaders/copy.glsl.gen.h"
+	for (int i = 0; i < lines.size(); i++) {
+		String l = lines[i];
+		bool push_chunk = false;
 
-#ifdef DEBUG_OPENGL
+		StageTemplate::Chunk chunk;
 
-#define DEBUG_TEST_ERROR(m_section)                                         \
-	{                                                                       \
-		uint32_t err = glGetError();                                        \
-		if (err) {                                                          \
-			print_line("OpenGL Error #" + itos(err) + " at: " + m_section); \
-		}                                                                   \
-	}
-#else
-
-#define DEBUG_TEST_ERROR(m_section)
-
-#endif
-
-ShaderGLES3 *ShaderGLES3::active = NULL;
-
-//#define DEBUG_SHADER
-
-#ifdef DEBUG_SHADER
-
-#define DEBUG_PRINT(m_text) print_line(m_text);
-
-#else
-
-#define DEBUG_PRINT(m_text)
-
-#endif
-
-GLint ShaderGLES3::get_uniform_location(int p_index) const {
-	ERR_FAIL_COND_V(!version, -1);
-
-	return version->uniform_location[p_index];
-}
+		if (l.begins_with("#GLOBALS")) {
+			switch (p_stage_type) {
+				case STAGE_TYPE_VERTEX:
+					chunk.type = StageTemplate::Chunk::TYPE_VERTEX_GLOBALS;
+					break;
+				case STAGE_TYPE_FRAGMENT:
+					chunk.type = StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS;
+					break;
+				default: {
+				}
+			}
 
-bool ShaderGLES3::bind() {
-	if (active != this || !version || new_conditional_version.key != conditional_version.key) {
-		conditional_version = new_conditional_version;
-		version = get_current_version();
-	} else {
-		return false;
-	}
+			push_chunk = true;
+		} else if (l.begins_with("#MATERIAL_UNIFORMS")) {
+			chunk.type = StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS;
+			push_chunk = true;
+		} else if (l.begins_with("#CODE")) {
+			chunk.type = StageTemplate::Chunk::TYPE_CODE;
+			push_chunk = true;
+			chunk.code = l.replace_first("#CODE", String()).replace(":", "").strip_edges().to_upper();
+		} else {
+			text += l + "\n";
+		}
 
-	ERR_FAIL_COND_V(!version, false);
+		if (push_chunk) {
+			if (text != String()) {
+				StageTemplate::Chunk text_chunk;
+				text_chunk.type = StageTemplate::Chunk::TYPE_TEXT;
+				text_chunk.text = text.utf8();
+				stage_templates[p_stage_type].chunks.push_back(text_chunk);
+				text = String();
+			}
+			stage_templates[p_stage_type].chunks.push_back(chunk);
+		}
 
-	if (!version->ok) { //broken, unable to bind (do not throw error, you saw it before already when it failed compilation).
-		glUseProgram(0);
-		return false;
+		if (text != String()) {
+			StageTemplate::Chunk text_chunk;
+			text_chunk.type = StageTemplate::Chunk::TYPE_TEXT;
+			text_chunk.text = text.utf8();
+			stage_templates[p_stage_type].chunks.push_back(text_chunk);
+			text = String();
+		}
 	}
-
-	glUseProgram(version->id);
-
-	DEBUG_TEST_ERROR("use program");
-
-	active = this;
-	uniforms_dirty = true;
-
-	return true;
-}
-
-void ShaderGLES3::unbind() {
-	version = NULL;
-	glUseProgram(0);
-	uniforms_dirty = true;
-	active = NULL;
 }
 
-static void _display_error_with_code(const String &p_error, const Vector<const char *> &p_code) {
-	int line = 1;
-	String total_code;
-
-	for (int i = 0; i < p_code.size(); i++) {
-		total_code += String(p_code[i]);
-	}
-
-	Vector<String> lines = String(total_code).split("\n");
+void ShaderGLES3::_setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name, int p_uniform_count, const char **p_uniform_names, int p_ubo_count, const UBOPair *p_ubos, int p_texture_count, const TexUnitPair *p_tex_units, int p_specialization_count, const Specialization *p_specializations, int p_variant_count, const char **p_variants) {
+	name = p_name;
 
-	for (int j = 0; j < lines.size(); j++) {
-		print_line(itos(line) + ": " + lines[j]);
-		line++;
+	if (p_vertex_code) {
+		_add_stage(p_vertex_code, STAGE_TYPE_VERTEX);
 	}
-
-	ERR_PRINT(p_error);
-}
-
-static String _mkid(const String &p_id) {
-	String id = "m_" + p_id;
-	return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl
-}
-
-ShaderGLES3::Version *ShaderGLES3::get_current_version() {
-	if (!valid)
-		return nullptr;
-
-	Version *_v = version_map.getptr(conditional_version);
-
-	if (_v) {
-		if (conditional_version.code_version != 0) {
-			CustomCode *cc = custom_code_map.getptr(conditional_version.code_version);
-			ERR_FAIL_COND_V(!cc, _v);
-			if (cc->version == _v->code_version)
-				return _v;
-		} else {
-			return _v;
-		}
+	if (p_fragment_code) {
+		_add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT);
 	}
 
-	if (!_v)
-		version_map[conditional_version] = Version();
-
-	Version &v = version_map[conditional_version];
-
-	if (!_v) {
-		v.uniform_location = memnew_arr(GLint, uniform_count);
-	} else {
-		if (v.ok) {
-			glDeleteShader(v.vert_id);
-			glDeleteShader(v.frag_id);
-			glDeleteProgram(v.id);
-			v.id = 0;
+	uniform_names = p_uniform_names;
+	uniform_count = p_uniform_count;
+	ubo_pairs = p_ubos;
+	ubo_count = p_ubo_count;
+	texunit_pairs = p_tex_units;
+	texunit_pair_count = p_texture_count;
+	specializations = p_specializations;
+	specialization_count = p_specialization_count;
+	specialization_default_mask = 0;
+	for (int i = 0; i < specialization_count; i++) {
+		if (specializations[i].defalut_value) {
+			specialization_default_mask |= (1 << i);
 		}
 	}
+	variant_defines = p_variants;
+	variant_count = p_variant_count;
+
+	StringBuilder tohash;
+	/*
+	tohash.append("[SpirvCacheKey]");
+	tohash.append(RenderingDevice::get_singleton()->shader_get_spirv_cache_key());
+	tohash.append("[BinaryCacheKey]");
+	tohash.append(RenderingDevice::get_singleton()->shader_get_binary_cache_key());
+	*/
+	tohash.append("[Vertex]");
+	tohash.append(p_vertex_code ? p_vertex_code : "");
+	tohash.append("[Fragment]");
+	tohash.append(p_fragment_code ? p_fragment_code : "");
+
+	base_sha256 = tohash.as_string().sha256_text();
+}
 
-	v.ok = false;
+RID ShaderGLES3::version_create() {
+	//initialize() was never called
+	ERR_FAIL_COND_V(variant_count == 0, RID());
 
-	Vector<const char *> strings;
+	Version version;
+	return version_owner.make_rid(version);
+}
 
+void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization) {
 #ifdef GLES_OVER_GL
-	strings.push_back("#version 330\n");
-	strings.push_back("#define USE_GLES_OVER_GL\n");
+	builder.append("#version 330\n");
+	builder.append("#define USE_GLES_OVER_GL\n");
 #else
-	strings.push_back("#version 300 es\n");
-//angle does not like
-#ifdef JAVASCRIPT_ENABLED
-	strings.push_back("#define USE_HIGHP_PRECISION\n");
+	builder.append("#version 300 es\n");
 #endif
 
-	//if (GLOBAL_GET("rendering/opengl/compatibility/enable_high_float.Android")) {
-	// enable USE_HIGHP_PRECISION but safeguarded by an availability check as highp support is optional in OpenGL
-	// see Section 4.5.4 of the GLSL_ES_Specification_1.00
-	//strings.push_back("#ifdef GL_FRAGMENT_PRECISION_HIGH\n  #define USE_HIGHP_PRECISION\n#endif\n");
-	//}
-
-#endif
-
-#ifdef ANDROID_ENABLED
-	strings.push_back("#define ANDROID_ENABLED\n");
-#endif
-
-	for (int i = 0; i < custom_defines.size(); i++) {
-		strings.push_back(custom_defines[i].get_data());
-		strings.push_back("\n");
-	}
-
-	for (int j = 0; j < conditional_count; j++) {
-		bool enable = (conditional_version.version & (1 << j)) > 0;
-
-		if (enable) {
-			strings.push_back(conditional_defines[j]);
-			DEBUG_PRINT(conditional_defines[j]);
+	for (int i = 0; i < specialization_count; i++) {
+		if (p_specialization & (1 << uint32_t(i))) {
+			builder.append("#define " + String(specializations[i].name) + "\n");
 		}
 	}
-
-	// keep them around during the function
-	CharString code_string;
-	CharString code_string2;
-	CharString code_globals;
-
-	CustomCode *cc = NULL;
-
-	if (conditional_version.code_version > 0) {
-		cc = custom_code_map.getptr(conditional_version.code_version);
-
-		ERR_FAIL_COND_V(!cc, NULL);
-		v.code_version = cc->version;
-	}
-
-	// program
-
-	v.id = glCreateProgram();
-	ERR_FAIL_COND_V(v.id == 0, NULL);
-
-	if (cc) {
-		for (int i = 0; i < cc->custom_defines.size(); i++) {
-			strings.push_back(cc->custom_defines.write[i]);
-			DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i].get_data()));
+	if (p_version->uniforms.size()) {
+		builder.append("#define MATERIAL_UNIFORMS_USED\n");
+	}
+	for (const KeyValue<StringName, CharString> &E : p_version->code_sections) {
+		builder.append(String("#define ") + String(E.key) + "_CODE_USED\n");
+	}
+
+	builder.append("\n"); //make sure defines begin at newline
+	builder.append(general_defines.get_data());
+	builder.append(variant_defines[p_variant]);
+	for (int j = 0; j < p_version->custom_defines.size(); j++) {
+		builder.append(p_version->custom_defines[j].get_data());
+	}
+	builder.append("\n"); //make sure defines begin at newline
+
+	for (uint32_t i = 0; i < p_template.chunks.size(); i++) {
+		const StageTemplate::Chunk &chunk = p_template.chunks[i];
+		switch (chunk.type) {
+			case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
+				builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
+			} break;
+			case StageTemplate::Chunk::TYPE_VERTEX_GLOBALS: {
+				builder.append(p_version->vertex_globals.get_data()); // vertex globals
+			} break;
+			case StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS: {
+				builder.append(p_version->fragment_globals.get_data()); // fragment globals
+			} break;
+			case StageTemplate::Chunk::TYPE_CODE: {
+				if (p_version->code_sections.has(chunk.code)) {
+					builder.append(p_version->code_sections[chunk.code].get_data());
+				}
+			} break;
+			case StageTemplate::Chunk::TYPE_TEXT: {
+				builder.append(chunk.text.get_data());
+			} break;
 		}
 	}
+}
 
-	// vertex shader
-
-	int string_base_size = strings.size();
-
-	strings.push_back(vertex_code0.get_data());
-
-	if (cc) {
-		code_globals = cc->vertex_globals.ascii();
-		strings.push_back(code_globals.get_data());
-	}
-
-	strings.push_back(vertex_code1.get_data());
+static void _display_error_with_code(const String &p_error, const String &p_code) {
+	int line = 1;
+	Vector<String> lines = p_code.split("\n");
 
-	if (cc) {
-		code_string = cc->vertex.ascii();
-		strings.push_back(code_string.get_data());
+	for (int j = 0; j < lines.size(); j++) {
+		print_line(itos(line) + ": " + lines[j]);
+		line++;
 	}
 
-	strings.push_back(vertex_code2.get_data());
-
-#ifdef DEBUG_SHADER
-
-	DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data()));
-
-#endif
-
-	v.vert_id = glCreateShader(GL_VERTEX_SHADER);
-	glShaderSource(v.vert_id, strings.size(), &strings[0], NULL);
-	glCompileShader(v.vert_id);
+	ERR_PRINT(p_error);
+}
 
+void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_t p_variant, Version *p_version, uint64_t p_specialization) {
+	spec.id = glCreateProgram();
+	spec.ok = false;
 	GLint status;
 
-	glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status);
-	if (status == GL_FALSE) {
-		GLsizei iloglen;
-		glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen);
-
-		if (iloglen < 0) {
-			glDeleteShader(v.vert_id);
-			glDeleteProgram(v.id);
-			v.id = 0;
+	//vertex stage
+	{
+		StringBuilder builder;
+		_build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX], p_specialization);
+
+		spec.vert_id = glCreateShader(GL_VERTEX_SHADER);
+		String builder_string = builder.as_string();
+		CharString cs = builder_string.utf8();
+		const char *cstr = cs.ptr();
+		glShaderSource(spec.vert_id, 1, &cstr, nullptr);
+		glCompileShader(spec.vert_id);
+
+		glGetShaderiv(spec.vert_id, GL_COMPILE_STATUS, &status);
+		if (status == GL_FALSE) {
+			GLsizei iloglen;
+			glGetShaderiv(spec.vert_id, GL_INFO_LOG_LENGTH, &iloglen);
+
+			if (iloglen < 0) {
+				glDeleteShader(spec.vert_id);
+				glDeleteProgram(spec.id);
+				spec.id = 0;
+
+				ERR_PRINT("No OpenGL vertex shader compiler log. What the frick?");
+			} else {
+				if (iloglen == 0) {
+					iloglen = 4096; // buggy driver (Adreno 220+)
+				}
 
-			ERR_PRINT("No OpenGL vertex shader compiler log. What the frick?");
-		} else {
-			if (iloglen == 0) {
-				iloglen = 4096; // buggy driver (Adreno 220+)
-			}
+				char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
+				ilogmem[iloglen] = '\0';
+				glGetShaderInfoLog(spec.vert_id, iloglen, &iloglen, ilogmem);
 
-			char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
-			ilogmem[iloglen] = '\0';
-			glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem);
+				String err_string = name + ": Vertex shader compilation failed:\n";
 
-			String err_string = get_shader_name() + ": Vertex shader compilation failed:\n";
+				err_string += ilogmem;
 
-			err_string += ilogmem;
+				_display_error_with_code(err_string, builder_string);
 
-			_display_error_with_code(err_string, strings);
+				Memory::free_static(ilogmem);
+				glDeleteShader(spec.vert_id);
+				glDeleteProgram(spec.id);
+				spec.id = 0;
+			}
 
-			Memory::free_static(ilogmem);
-			glDeleteShader(v.vert_id);
-			glDeleteProgram(v.id);
-			v.id = 0;
+			ERR_FAIL();
 		}
-
-		ERR_FAIL_V(NULL);
-	}
-
-	strings.resize(string_base_size);
-
-	// fragment shader
-
-	strings.push_back(fragment_code0.get_data());
-
-	if (cc) {
-		code_globals = cc->fragment_globals.ascii();
-		strings.push_back(code_globals.get_data());
 	}
 
-	strings.push_back(fragment_code1.get_data());
-
-	if (cc) {
-		code_string = cc->light.ascii();
-		strings.push_back(code_string.get_data());
-	}
-
-	strings.push_back(fragment_code2.get_data());
-
-	if (cc) {
-		code_string2 = cc->fragment.ascii();
-		strings.push_back(code_string2.get_data());
-	}
-
-	strings.push_back(fragment_code3.get_data());
+	//fragment stage
+	{
+		StringBuilder builder;
+		_build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT], p_specialization);
+
+		spec.vert_id = glCreateShader(GL_FRAGMENT_SHADER);
+		String builder_string = builder.as_string();
+		CharString cs = builder_string.utf8();
+		const char *cstr = cs.ptr();
+		glShaderSource(spec.vert_id, 1, &cstr, nullptr);
+		glCompileShader(spec.vert_id);
+
+		glGetShaderiv(spec.vert_id, GL_COMPILE_STATUS, &status);
+		if (status == GL_FALSE) {
+			GLsizei iloglen;
+			glGetShaderiv(spec.vert_id, GL_INFO_LOG_LENGTH, &iloglen);
+
+			if (iloglen < 0) {
+				glDeleteShader(spec.vert_id);
+				glDeleteProgram(spec.id);
+				spec.id = 0;
+
+				ERR_PRINT("No OpenGL vertex shader compiler log. What the frick?");
+			} else {
+				if (iloglen == 0) {
+					iloglen = 4096; // buggy driver (Adreno 220+)
+				}
 
-#ifdef DEBUG_SHADER
+				char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
+				ilogmem[iloglen] = '\0';
+				glGetShaderInfoLog(spec.vert_id, iloglen, &iloglen, ilogmem);
 
-	if (cc) {
-		DEBUG_PRINT("\nFragment Code:\n\n" + String(cc->fragment_globals));
-	}
-	DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string.get_data()));
-#endif
+				String err_string = name + ": Fragment shader compilation failed:\n";
 
-	v.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
-	glShaderSource(v.frag_id, strings.size(), &strings[0], NULL);
-	glCompileShader(v.frag_id);
+				err_string += ilogmem;
 
-	glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status);
-	if (status == GL_FALSE) {
-		GLsizei iloglen;
-		glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen);
+				_display_error_with_code(err_string, builder_string);
 
-		if (iloglen < 0) {
-			glDeleteShader(v.frag_id);
-			glDeleteShader(v.vert_id);
-			glDeleteProgram(v.id);
-			v.id = 0;
-
-			ERR_PRINT("No OpenGL fragment shader compiler log. What the frick?");
-		} else {
-			if (iloglen == 0) {
-				iloglen = 4096; // buggy driver (Adreno 220+)
+				Memory::free_static(ilogmem);
+				glDeleteShader(spec.vert_id);
+				glDeleteProgram(spec.id);
+				spec.id = 0;
 			}
 
-			char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
-			ilogmem[iloglen] = '\0';
-			glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem);
-
-			String err_string = get_shader_name() + ": Fragment shader compilation failed:\n";
-
-			err_string += ilogmem;
-
-			_display_error_with_code(err_string, strings);
-
-			Memory::free_static(ilogmem);
-			glDeleteShader(v.frag_id);
-			glDeleteShader(v.vert_id);
-			glDeleteProgram(v.id);
-			v.id = 0;
+			ERR_FAIL();
 		}
-
-		ERR_FAIL_V(NULL);
 	}
 
-	glAttachShader(v.id, v.frag_id);
-	glAttachShader(v.id, v.vert_id);
-
-	// bind the attribute locations. This has to be done before linking so that the
-	// linker doesn't assign some random indices
-
-	for (int i = 0; i < attribute_pair_count; i++) {
-		glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name);
-	}
+	glAttachShader(spec.id, spec.frag_id);
+	glAttachShader(spec.id, spec.vert_id);
 
-	glLinkProgram(v.id);
+	glLinkProgram(spec.id);
 
-	glGetProgramiv(v.id, GL_LINK_STATUS, &status);
+	glGetProgramiv(spec.id, GL_LINK_STATUS, &status);
 	if (status == GL_FALSE) {
 		GLsizei iloglen;
-		glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen);
+		glGetProgramiv(spec.id, GL_INFO_LOG_LENGTH, &iloglen);
 
 		if (iloglen < 0) {
-			glDeleteShader(v.frag_id);
-			glDeleteShader(v.vert_id);
-			glDeleteProgram(v.id);
-			v.id = 0;
+			glDeleteShader(spec.frag_id);
+			glDeleteShader(spec.vert_id);
+			glDeleteProgram(spec.id);
+			spec.id = 0;
 
 			ERR_PRINT("No OpenGL program link log. What the frick?");
-			ERR_FAIL_V(NULL);
+			ERR_FAIL();
 		}
 
 		if (iloglen == 0) {
@@ -409,33 +332,34 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() {
 
 		char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
 		ilogmem[iloglen] = '\0';
-		glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem);
+		glGetProgramInfoLog(spec.id, iloglen, &iloglen, ilogmem);
 
-		String err_string = get_shader_name() + ": Program linking failed:\n";
+		String err_string = name + ": Program linking failed:\n";
 
 		err_string += ilogmem;
 
-		_display_error_with_code(err_string, strings);
+		_display_error_with_code(err_string, String());
 
 		Memory::free_static(ilogmem);
-		glDeleteShader(v.frag_id);
-		glDeleteShader(v.vert_id);
-		glDeleteProgram(v.id);
-		v.id = 0;
+		glDeleteShader(spec.frag_id);
+		glDeleteShader(spec.vert_id);
+		glDeleteProgram(spec.id);
+		spec.id = 0;
 
-		ERR_FAIL_V(NULL);
+		ERR_FAIL();
 	}
 
 	// get uniform locations
 
-	glUseProgram(v.id);
+	glUseProgram(spec.id);
 
+	spec.uniform_location.resize(uniform_count);
 	for (int i = 0; i < uniform_count; i++) {
-		v.uniform_location[i] = glGetUniformLocation(v.id, uniform_names[i]);
+		spec.uniform_location[i] = glGetUniformLocation(spec.id, uniform_names[i]);
 	}
 
 	for (int i = 0; i < texunit_pair_count; i++) {
-		GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name);
+		GLint loc = glGetUniformLocation(spec.id, texunit_pairs[i].name);
 		if (loc >= 0) {
 			if (texunit_pairs[i].index < 0) {
 				glUniform1i(loc, max_image_units + texunit_pairs[i].index);
@@ -445,672 +369,323 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() {
 		}
 	}
 
-	if (cc) {
-		// uniforms
-		for (int i = 0; i < cc->custom_uniforms.size(); i++) {
-			String native_uniform_name = _mkid(cc->custom_uniforms[i]);
-			GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data());
-			v.custom_uniform_locations[cc->custom_uniforms[i]] = location;
-		}
-
-		// textures
-		for (int i = 0; i < cc->texture_uniforms.size(); i++) {
-			String native_uniform_name = _mkid(cc->texture_uniforms[i]);
-			GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data());
-			v.custom_uniform_locations[cc->texture_uniforms[i]] = location;
-			glUniform1i(location, i);
+	for (int i = 0; i < ubo_count; i++) {
+		GLint loc = glGetUniformLocation(spec.id, ubo_pairs[i].name);
+		if (loc >= 0) {
+			glUniform1i(loc, ubo_pairs[i].index);
 		}
 	}
-
-	glUseProgram(0);
-	v.ok = true;
-
-	if (cc) {
-		cc->versions.insert(conditional_version.version);
+	// textures
+	for (int i = 0; i < p_version->texture_uniforms.size(); i++) {
+		String native_uniform_name = p_version->texture_uniforms[i];
+		GLint location = glGetUniformLocation(spec.id, (native_uniform_name).ascii().get_data());
+		glUniform1i(location, i + base_texture_index);
 	}
 
-	return &v;
-}
-
-GLint ShaderGLES3::get_uniform_location(const String &p_name) const {
-	ERR_FAIL_COND_V(!version, -1);
-	return glGetUniformLocation(version->id, p_name.ascii().get_data());
+	glUseProgram(0);
+	spec.ok = true;
 }
 
-void ShaderGLES3::setup(
-		const char **p_conditional_defines,
-		int p_conditional_count,
-		const char **p_uniform_names,
-		int p_uniform_count,
-		const AttributePair *p_attribute_pairs,
-		int p_attribute_count,
-		const TexUnitPair *p_texunit_pairs,
-		int p_texunit_pair_count,
-		const char *p_vertex_code,
-		const char *p_fragment_code,
-		int p_vertex_code_start,
-		int p_fragment_code_start) {
-	ERR_FAIL_COND(version);
-
-	conditional_version.key = 0;
-	new_conditional_version.key = 0;
-	uniform_count = p_uniform_count;
-	conditional_count = p_conditional_count;
-	conditional_defines = p_conditional_defines;
-	uniform_names = p_uniform_names;
-	vertex_code = p_vertex_code;
-	fragment_code = p_fragment_code;
-	texunit_pairs = p_texunit_pairs;
-	texunit_pair_count = p_texunit_pair_count;
-	vertex_code_start = p_vertex_code_start;
-	fragment_code_start = p_fragment_code_start;
-	attribute_pairs = p_attribute_pairs;
-	attribute_pair_count = p_attribute_count;
+RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_version) {
+	Version *version = version_owner.get_or_null(p_version);
+	RS::ShaderNativeSourceCode source_code;
+	ERR_FAIL_COND_V(!version, source_code);
 
-	{
-		String globals_tag = "\nVERTEX_SHADER_GLOBALS";
-		String code_tag = "\nVERTEX_SHADER_CODE";
-		String code = vertex_code;
-		int cpos = code.find(globals_tag);
-		if (cpos == -1) {
-			vertex_code0 = code.ascii();
-		} else {
-			vertex_code0 = code.substr(0, cpos).ascii();
-			code = code.substr(cpos + globals_tag.length(), code.length());
+	source_code.versions.resize(variant_count);
 
-			cpos = code.find(code_tag);
+	for (int i = 0; i < source_code.versions.size(); i++) {
+		//vertex stage
 
-			if (cpos == -1) {
-				vertex_code1 = code.ascii();
-			} else {
-				vertex_code1 = code.substr(0, cpos).ascii();
-				vertex_code2 = code.substr(cpos + code_tag.length(), code.length()).ascii();
-			}
-		}
-	}
+		{
+			StringBuilder builder;
+			_build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX], specialization_default_mask);
 
-	{
-		String globals_tag = "\nFRAGMENT_SHADER_GLOBALS";
-		String code_tag = "\nFRAGMENT_SHADER_CODE";
-		String light_code_tag = "\nLIGHT_SHADER_CODE";
-		String code = fragment_code;
-		int cpos = code.find(globals_tag);
-		if (cpos == -1) {
-			fragment_code0 = code.ascii();
-		} else {
-			fragment_code0 = code.substr(0, cpos).ascii();
-			code = code.substr(cpos + globals_tag.length(), code.length());
+			RS::ShaderNativeSourceCode::Version::Stage stage;
+			stage.name = "vertex";
+			stage.code = builder.as_string();
 
-			cpos = code.find(light_code_tag);
+			source_code.versions.write[i].stages.push_back(stage);
+		}
 
-			String code2;
+		//fragment stage
+		{
+			StringBuilder builder;
+			_build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT], specialization_default_mask);
 
-			if (cpos != -1) {
-				fragment_code1 = code.substr(0, cpos).ascii();
-				code2 = code.substr(cpos + light_code_tag.length(), code.length());
-			} else {
-				code2 = code;
-			}
+			RS::ShaderNativeSourceCode::Version::Stage stage;
+			stage.name = "fragment";
+			stage.code = builder.as_string();
 
-			cpos = code2.find(code_tag);
-			if (cpos == -1) {
-				fragment_code2 = code2.ascii();
-			} else {
-				fragment_code2 = code2.substr(0, cpos).ascii();
-				fragment_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii();
-			}
+			source_code.versions.write[i].stages.push_back(stage);
 		}
 	}
 
-	glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units);
-
-	valid = true;
+	return source_code;
 }
 
-void ShaderGLES3::finish() {
-	const VersionKey *V = NULL;
-
-	while ((V = version_map.next(V))) {
-		Version &v = version_map[*V];
-		glDeleteShader(v.vert_id);
-		glDeleteShader(v.frag_id);
-		glDeleteProgram(v.id);
-
-		if (v.uniform_location)
-			memdelete_arr(v.uniform_location);
-	}
-}
+String ShaderGLES3::_version_get_sha1(Version *p_version) const {
+	StringBuilder hash_build;
 
-void ShaderGLES3::clear_caches() {
-	const VersionKey *V = NULL;
+	hash_build.append("[uniforms]");
+	hash_build.append(p_version->uniforms.get_data());
+	hash_build.append("[vertex_globals]");
+	hash_build.append(p_version->vertex_globals.get_data());
+	hash_build.append("[fragment_globals]");
+	hash_build.append(p_version->fragment_globals.get_data());
 
-	while ((V = version_map.next(V))) {
-		Version &v = version_map[*V];
-		glDeleteShader(v.vert_id);
-		glDeleteShader(v.frag_id);
-		glDeleteProgram(v.id);
-		memdelete_arr(v.uniform_location);
+	Vector<StringName> code_sections;
+	for (const KeyValue<StringName, CharString> &E : p_version->code_sections) {
+		code_sections.push_back(E.key);
 	}
+	code_sections.sort_custom<StringName::AlphCompare>();
 
-	version_map.clear();
-
-	custom_code_map.clear();
-	version = NULL;
-	last_custom_code = 1;
-	uniforms_dirty = true;
-}
-
-uint32_t ShaderGLES3::create_custom_shader() {
-	custom_code_map[last_custom_code] = CustomCode();
-	custom_code_map[last_custom_code].version = 1;
-	return last_custom_code++;
-}
-
-void ShaderGLES3::set_custom_shader_code(uint32_t p_code_id,
-		const String &p_vertex,
-		const String &p_vertex_globals,
-		const String &p_fragment,
-		const String &p_light,
-		const String &p_fragment_globals,
-		const Vector<StringName> &p_uniforms,
-		const Vector<StringName> &p_texture_uniforms,
-		const Vector<CharString> &p_custom_defines) {
-	CustomCode *cc = custom_code_map.getptr(p_code_id);
-	ERR_FAIL_COND(!cc);
-
-	cc->vertex = p_vertex;
-	cc->vertex_globals = p_vertex_globals;
-	cc->fragment = p_fragment;
-	cc->fragment_globals = p_fragment_globals;
-	cc->light = p_light;
-	cc->custom_uniforms = p_uniforms;
-	cc->custom_defines = p_custom_defines;
-	cc->texture_uniforms = p_texture_uniforms;
-	cc->version++;
-}
-
-void ShaderGLES3::set_custom_shader(uint32_t p_code_id) {
-	new_conditional_version.code_version = p_code_id;
-}
-
-void ShaderGLES3::free_custom_shader(uint32_t p_code_id) {
-	ERR_FAIL_COND(!custom_code_map.has(p_code_id));
-	if (conditional_version.code_version == p_code_id) {
-		conditional_version.code_version = 0; //do not keep using a version that is going away
-		unbind();
+	for (int i = 0; i < code_sections.size(); i++) {
+		hash_build.append(String("[code:") + String(code_sections[i]) + "]");
+		hash_build.append(p_version->code_sections[code_sections[i]].get_data());
 	}
-
-	VersionKey key;
-	key.code_version = p_code_id;
-	for (Set<uint32_t>::Element *E = custom_code_map[p_code_id].versions.front(); E; E = E->next()) {
-		key.version = E->get();
-		ERR_CONTINUE(!version_map.has(key));
-		Version &v = version_map[key];
-
-		glDeleteShader(v.vert_id);
-		glDeleteShader(v.frag_id);
-		glDeleteProgram(v.id);
-		memdelete_arr(v.uniform_location);
-		v.id = 0;
-
-		version_map.erase(key);
+	for (int i = 0; i < p_version->custom_defines.size(); i++) {
+		hash_build.append("[custom_defines:" + itos(i) + "]");
+		hash_build.append(p_version->custom_defines[i].get_data());
 	}
 
-	custom_code_map.erase(p_code_id);
+	return hash_build.as_string().sha1_text();
 }
 
-void ShaderGLES3::use_material(void *p_material) {
-	RasterizerStorageGLES3::Material *material = (RasterizerStorageGLES3::Material *)p_material;
+//static const char *shader_file_header = "GLSC";
+//static const uint32_t cache_file_version = 2;
 
-	if (!material) {
-		return;
-	}
+bool ShaderGLES3::_load_from_cache(Version *p_version) {
+#if 0
+	String sha1 = _version_get_sha1(p_version);
+	String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
 
-	if (!material->shader) {
-		return;
+	FileAccessRef f = FileAccess::open(path, FileAccess::READ);
+	if (!f) {
+		return false;
 	}
 
-	Version *v = version_map.getptr(conditional_version);
-
-	// bind uniforms
-	for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) {
-		if (E->get().texture_order >= 0)
-			continue; // this is a texture, doesn't go here
-
-		Map<StringName, GLint>::Element *L = v->custom_uniform_locations.find(E->key());
-		if (!L || L->get() < 0)
-			continue; //uniform not valid
-
-		GLuint location = L->get();
-
-		Map<StringName, Variant>::Element *V = material->params.find(E->key());
-
-		if (V) {
-			switch (E->get().type) {
-				case ShaderLanguage::TYPE_BOOL: {
-					bool boolean = V->get();
-					glUniform1i(location, boolean ? 1 : 0);
-				} break;
-
-				case ShaderLanguage::TYPE_BVEC2: {
-					int flags = V->get();
-					glUniform2i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0);
-				} break;
-
-				case ShaderLanguage::TYPE_BVEC3: {
-					int flags = V->get();
-					glUniform3i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0);
-
-				} break;
-
-				case ShaderLanguage::TYPE_BVEC4: {
-					int flags = V->get();
-					glUniform4i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0, (flags & 8) ? 1 : 0);
-
-				} break;
-
-				case ShaderLanguage::TYPE_INT:
-				case ShaderLanguage::TYPE_UINT: {
-					int value = V->get();
-					glUniform1i(location, value);
-				} break;
-
-				case ShaderLanguage::TYPE_IVEC2:
-				case ShaderLanguage::TYPE_UVEC2: {
-					Array r = V->get();
-					const int count = 2;
-					if (r.size() == count) {
-						int values[count];
-						for (int i = 0; i < count; i++) {
-							values[i] = r[i];
-						}
-						glUniform2i(location, values[0], values[1]);
-					}
-
-				} break;
-
-				case ShaderLanguage::TYPE_IVEC3:
-				case ShaderLanguage::TYPE_UVEC3: {
-					Array r = V->get();
-					const int count = 3;
-					if (r.size() == count) {
-						int values[count];
-						for (int i = 0; i < count; i++) {
-							values[i] = r[i];
-						}
-						glUniform3i(location, values[0], values[1], values[2]);
-					}
-
-				} break;
-
-				case ShaderLanguage::TYPE_IVEC4:
-				case ShaderLanguage::TYPE_UVEC4: {
-					Array r = V->get();
-					const int count = 4;
-					if (r.size() == count) {
-						int values[count];
-						for (int i = 0; i < count; i++) {
-							values[i] = r[i];
-						}
-						glUniform4i(location, values[0], values[1], values[2], values[3]);
-					}
-
-				} break;
-
-				case ShaderLanguage::TYPE_FLOAT: {
-					float value = V->get();
-					glUniform1f(location, value);
-
-				} break;
-
-				case ShaderLanguage::TYPE_VEC2: {
-					Vector2 value = V->get();
-					glUniform2f(location, value.x, value.y);
-				} break;
-
-				case ShaderLanguage::TYPE_VEC3: {
-					Vector3 value = V->get();
-					glUniform3f(location, value.x, value.y, value.z);
-				} break;
-
-				case ShaderLanguage::TYPE_VEC4: {
-					if (V->get().get_type() == Variant::COLOR) {
-						Color value = V->get();
-						glUniform4f(location, value.r, value.g, value.b, value.a);
-					} else if (V->get().get_type() == Variant::QUATERNION) {
-						Quaternion value = V->get();
-						glUniform4f(location, value.x, value.y, value.z, value.w);
-					} else {
-						Plane value = V->get();
-						glUniform4f(location, value.normal.x, value.normal.y, value.normal.z, value.d);
-					}
-
-				} break;
-
-				case ShaderLanguage::TYPE_MAT2: {
-					Transform2D tr = V->get();
-					GLfloat matrix[4] = {
-						/* build a 16x16 matrix */
-						(GLfloat)tr.elements[0][0],
-						(GLfloat)tr.elements[0][1],
-						(GLfloat)tr.elements[1][0],
-						(GLfloat)tr.elements[1][1],
-					};
-					glUniformMatrix2fv(location, 1, GL_FALSE, matrix);
-
-				} break;
-
-				case ShaderLanguage::TYPE_MAT3: {
-					Basis val = V->get();
-
-					GLfloat mat[9] = {
-						(GLfloat)val.elements[0][0],
-						(GLfloat)val.elements[1][0],
-						(GLfloat)val.elements[2][0],
-						(GLfloat)val.elements[0][1],
-						(GLfloat)val.elements[1][1],
-						(GLfloat)val.elements[2][1],
-						(GLfloat)val.elements[0][2],
-						(GLfloat)val.elements[1][2],
-						(GLfloat)val.elements[2][2],
-					};
-
-					glUniformMatrix3fv(location, 1, GL_FALSE, mat);
-
-				} break;
-
-				case ShaderLanguage::TYPE_MAT4: {
-					Transform2D tr = V->get();
-					GLfloat matrix[16] = { /* build a 16x16 matrix */
-						(GLfloat)tr.elements[0][0],
-						(GLfloat)tr.elements[0][1],
-						(GLfloat)0,
-						(GLfloat)0,
-						(GLfloat)tr.elements[1][0],
-						(GLfloat)tr.elements[1][1],
-						(GLfloat)0,
-						(GLfloat)0,
-						(GLfloat)0,
-						(GLfloat)0,
-						(GLfloat)1,
-						(GLfloat)0,
-						(GLfloat)tr.elements[2][0],
-						(GLfloat)tr.elements[2][1],
-						(GLfloat)0,
-						(GLfloat)1
-					};
-
-					glUniformMatrix4fv(location, 1, GL_FALSE, matrix);
-
-				} break;
-
-				default: {
-					ERR_PRINT("ShaderNode type missing, bug?");
-				} break;
-			}
-		} else if (E->get().default_value.size()) {
-			const Vector<ShaderLanguage::ConstantNode::Value> &values = E->get().default_value;
-			switch (E->get().type) {
-				case ShaderLanguage::TYPE_BOOL: {
-					glUniform1i(location, values[0].boolean);
-				} break;
-
-				case ShaderLanguage::TYPE_BVEC2: {
-					glUniform2i(location, values[0].boolean, values[1].boolean);
-				} break;
-
-				case ShaderLanguage::TYPE_BVEC3: {
-					glUniform3i(location, values[0].boolean, values[1].boolean, values[2].boolean);
-				} break;
-
-				case ShaderLanguage::TYPE_BVEC4: {
-					glUniform4i(location, values[0].boolean, values[1].boolean, values[2].boolean, values[3].boolean);
-				} break;
-
-				case ShaderLanguage::TYPE_INT: {
-					glUniform1i(location, values[0].sint);
-				} break;
-
-				case ShaderLanguage::TYPE_IVEC2: {
-					glUniform2i(location, values[0].sint, values[1].sint);
-				} break;
-
-				case ShaderLanguage::TYPE_IVEC3: {
-					glUniform3i(location, values[0].sint, values[1].sint, values[2].sint);
-				} break;
-
-				case ShaderLanguage::TYPE_IVEC4: {
-					glUniform4i(location, values[0].sint, values[1].sint, values[2].sint, values[3].sint);
-				} break;
-
-				case ShaderLanguage::TYPE_UINT: {
-					glUniform1i(location, values[0].uint);
-				} break;
-
-				case ShaderLanguage::TYPE_UVEC2: {
-					glUniform2i(location, values[0].uint, values[1].uint);
-				} break;
-
-				case ShaderLanguage::TYPE_UVEC3: {
-					glUniform3i(location, values[0].uint, values[1].uint, values[2].uint);
-				} break;
-
-				case ShaderLanguage::TYPE_UVEC4: {
-					glUniform4i(location, values[0].uint, values[1].uint, values[2].uint, values[3].uint);
-				} break;
-
-				case ShaderLanguage::TYPE_FLOAT: {
-					glUniform1f(location, values[0].real);
-				} break;
-
-				case ShaderLanguage::TYPE_VEC2: {
-					glUniform2f(location, values[0].real, values[1].real);
-				} break;
+	char header[5] = { 0, 0, 0, 0, 0 };
+	f->get_buffer((uint8_t *)header, 4);
+	ERR_FAIL_COND_V(header != String(shader_file_header), false);
 
-				case ShaderLanguage::TYPE_VEC3: {
-					glUniform3f(location, values[0].real, values[1].real, values[2].real);
-				} break;
-
-				case ShaderLanguage::TYPE_VEC4: {
-					glUniform4f(location, values[0].real, values[1].real, values[2].real, values[3].real);
-				} break;
-
-				case ShaderLanguage::TYPE_MAT2: {
-					GLfloat mat[4];
-
-					for (int i = 0; i < 4; i++) {
-						mat[i] = values[i].real;
-					}
-
-					glUniformMatrix2fv(location, 1, GL_FALSE, mat);
-				} break;
-
-				case ShaderLanguage::TYPE_MAT3: {
-					GLfloat mat[9];
-
-					for (int i = 0; i < 9; i++) {
-						mat[i] = values[i].real;
-					}
-
-					glUniformMatrix3fv(location, 1, GL_FALSE, mat);
-
-				} break;
-
-				case ShaderLanguage::TYPE_MAT4: {
-					GLfloat mat[16];
-
-					for (int i = 0; i < 16; i++) {
-						mat[i] = values[i].real;
-					}
-
-					glUniformMatrix4fv(location, 1, GL_FALSE, mat);
+	uint32_t file_version = f->get_32();
+	if (file_version != cache_file_version) {
+		return false; // wrong version
+	}
 
-				} break;
+	uint32_t variant_count = f->get_32();
 
-				case ShaderLanguage::TYPE_SAMPLER2D: {
-				} break;
+	ERR_FAIL_COND_V(variant_count != (uint32_t)variant_count, false); //should not happen but check
 
-					/*
-				case ShaderLanguage::TYPE_SAMPLEREXT: {
-				} break;
-*/
-				case ShaderLanguage::TYPE_ISAMPLER2D: {
-				} break;
+	for (uint32_t i = 0; i < variant_count; i++) {
+		uint32_t variant_size = f->get_32();
+		ERR_FAIL_COND_V(variant_size == 0 && variants_enabled[i], false);
+		if (!variants_enabled[i]) {
+			continue;
+		}
+		Vector<uint8_t> variant_bytes;
+		variant_bytes.resize(variant_size);
 
-				case ShaderLanguage::TYPE_USAMPLER2D: {
-				} break;
+		uint32_t br = f->get_buffer(variant_bytes.ptrw(), variant_size);
 
-				case ShaderLanguage::TYPE_SAMPLERCUBE: {
-				} break;
+		ERR_FAIL_COND_V(br != variant_size, false);
 
-				case ShaderLanguage::TYPE_SAMPLER2DARRAY:
-				case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
-				case ShaderLanguage::TYPE_USAMPLER2DARRAY:
-				case ShaderLanguage::TYPE_SAMPLER3D:
-				case ShaderLanguage::TYPE_ISAMPLER3D:
-				case ShaderLanguage::TYPE_USAMPLER3D: {
-					// Not implemented in OpenGL
-				} break;
+		p_version->variant_data[i] = variant_bytes;
+	}
 
-				case ShaderLanguage::TYPE_VOID: {
-					// Nothing to do?
-				} break;
-				default: {
-					ERR_PRINT("ShaderNode type missing, bug?");
-				} break;
+	for (uint32_t i = 0; i < variant_count; i++) {
+		if (!variants_enabled[i]) {
+			MutexLock lock(variant_set_mutex);
+			p_version->variants[i] = RID();
+			continue;
+		}
+		RID shader = GLES3::get_singleton()->shader_create_from_bytecode(p_version->variant_data[i]);
+		if (shader.is_null()) {
+			for (uint32_t j = 0; j < i; j++) {
+				GLES3::get_singleton()->free(p_version->variants[i]);
 			}
-		} else { //zero
-
-			switch (E->get().type) {
-				case ShaderLanguage::TYPE_BOOL: {
-					glUniform1i(location, GL_FALSE);
-				} break;
+			ERR_FAIL_COND_V(shader.is_null(), false);
+		}
+		{
+			MutexLock lock(variant_set_mutex);
+			p_version->variants[i] = shader;
+		}
+	}
 
-				case ShaderLanguage::TYPE_BVEC2: {
-					glUniform2i(location, GL_FALSE, GL_FALSE);
-				} break;
+	memdelete_arr(p_version->variant_data); //clear stages
+	p_version->variant_data = nullptr;
+	p_version->valid = true;
+	return true;
+#endif
+	return false;
+}
 
-				case ShaderLanguage::TYPE_BVEC3: {
-					glUniform3i(location, GL_FALSE, GL_FALSE, GL_FALSE);
-				} break;
+void ShaderGLES3::_save_to_cache(Version *p_version) {
+#if 0
+	String sha1 = _version_get_sha1(p_version);
+	String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
 
-				case ShaderLanguage::TYPE_BVEC4: {
-					glUniform4i(location, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-				} break;
+	FileAccessRef f = FileAccess::open(path, FileAccess::WRITE);
+	ERR_FAIL_COND(!f);
+	f->store_buffer((const uint8_t *)shader_file_header, 4);
+	f->store_32(cache_file_version); //file version
+	uint32_t variant_count = variant_count;
+	f->store_32(variant_count); //variant count
 
-				case ShaderLanguage::TYPE_INT: {
-					glUniform1i(location, 0);
-				} break;
+	for (uint32_t i = 0; i < variant_count; i++) {
+		f->store_32(p_version->variant_data[i].size()); //stage count
+		f->store_buffer(p_version->variant_data[i].ptr(), p_version->variant_data[i].size());
+	}
 
-				case ShaderLanguage::TYPE_IVEC2: {
-					glUniform2i(location, 0, 0);
-				} break;
+	f->close();
+#endif
+}
 
-				case ShaderLanguage::TYPE_IVEC3: {
-					glUniform3i(location, 0, 0, 0);
-				} break;
+void ShaderGLES3::_clear_version(Version *p_version) {
+	for (int i = 0; i < variant_count; i++) {
+		for (OAHashMap<uint64_t, Version::Specialization>::Iterator it = p_version->variants[i].iter(); it.valid; it = p_version->variants[i].next_iter(it)) {
+			if (it.valid) {
+				glDeleteShader(it.value->vert_id);
+				glDeleteShader(it.value->frag_id);
+				glDeleteProgram(it.value->id);
+			}
+		}
+	}
 
-				case ShaderLanguage::TYPE_IVEC4: {
-					glUniform4i(location, 0, 0, 0, 0);
-				} break;
+	p_version->variants.clear();
+}
 
-				case ShaderLanguage::TYPE_UINT: {
-					glUniform1i(location, 0);
-				} break;
+void ShaderGLES3::_initialize_version(Version *p_version) {
+	ERR_FAIL_COND(p_version->variants.size() > 0);
+	p_version->variants.reserve(variant_count);
+	for (int i = 0; i < variant_count; i++) {
+		Version::Specialization spec;
+		_compile_specialization(spec, i, p_version, specialization_default_mask);
+		p_version->variants[i].insert(specialization_default_mask, spec);
+	}
+}
 
-				case ShaderLanguage::TYPE_UVEC2: {
-					glUniform2i(location, 0, 0);
-				} break;
+void ShaderGLES3::version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const Vector<StringName> &p_texture_uniforms, bool p_initialize) {
+	Version *version = version_owner.get_or_null(p_version);
+	ERR_FAIL_COND(!version);
 
-				case ShaderLanguage::TYPE_UVEC3: {
-					glUniform3i(location, 0, 0, 0);
-				} break;
+	_clear_version(version); //clear if existing
 
-				case ShaderLanguage::TYPE_UVEC4: {
-					glUniform4i(location, 0, 0, 0, 0);
-				} break;
+	version->vertex_globals = p_vertex_globals.utf8();
+	version->fragment_globals = p_fragment_globals.utf8();
+	version->uniforms = p_uniforms.utf8();
+	version->code_sections.clear();
+	version->texture_uniforms = p_texture_uniforms;
+	for (const KeyValue<String, String> &E : p_code) {
+		version->code_sections[StringName(E.key.to_upper())] = E.value.utf8();
+	}
 
-				case ShaderLanguage::TYPE_FLOAT: {
-					glUniform1f(location, 0);
-				} break;
+	version->custom_defines.clear();
+	for (int i = 0; i < p_custom_defines.size(); i++) {
+		version->custom_defines.push_back(p_custom_defines[i].utf8());
+	}
 
-				case ShaderLanguage::TYPE_VEC2: {
-					glUniform2f(location, 0, 0);
-				} break;
+	if (p_initialize) {
+		_initialize_version(version);
+	}
+}
 
-				case ShaderLanguage::TYPE_VEC3: {
-					glUniform3f(location, 0, 0, 0);
-				} break;
+bool ShaderGLES3::version_is_valid(RID p_version) {
+	Version *version = version_owner.get_or_null(p_version);
+	return version != nullptr;
+}
 
-				case ShaderLanguage::TYPE_VEC4: {
-					glUniform4f(location, 0, 0, 0, 0);
-				} break;
+bool ShaderGLES3::version_free(RID p_version) {
+	if (version_owner.owns(p_version)) {
+		Version *version = version_owner.get_or_null(p_version);
+		_clear_version(version);
+		version_owner.free(p_version);
+	} else {
+		return false;
+	}
 
-				case ShaderLanguage::TYPE_MAT2: {
-					GLfloat mat[4] = { 0, 0, 0, 0 };
+	return true;
+}
 
-					glUniformMatrix2fv(location, 1, GL_FALSE, mat);
-				} break;
+bool ShaderGLES3::shader_cache_cleanup_on_start = false;
 
-				case ShaderLanguage::TYPE_MAT3: {
-					GLfloat mat[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ShaderGLES3::ShaderGLES3() {
+}
 
-					glUniformMatrix3fv(location, 1, GL_FALSE, mat);
+void ShaderGLES3::initialize(const String &p_general_defines, int p_base_texture_index) {
+	general_defines = p_general_defines.utf8();
+	base_texture_index = p_base_texture_index;
 
-				} break;
+	_init();
 
-				case ShaderLanguage::TYPE_MAT4: {
-					GLfloat mat[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	if (shader_cache_dir != String()) {
+		StringBuilder hash_build;
 
-					glUniformMatrix4fv(location, 1, GL_FALSE, mat);
+		hash_build.append("[base_hash]");
+		hash_build.append(base_sha256);
+		hash_build.append("[general_defines]");
+		hash_build.append(general_defines.get_data());
+		for (int i = 0; i < variant_count; i++) {
+			hash_build.append("[variant_defines:" + itos(i) + "]");
+			hash_build.append(variant_defines[i]);
+		}
 
-				} break;
+		base_sha256 = hash_build.as_string().sha256_text();
 
-				case ShaderLanguage::TYPE_SAMPLER2D: {
-				} break;
+		DirAccessRef d = DirAccess::open(shader_cache_dir);
+		ERR_FAIL_COND(!d);
+		if (d->change_dir(name) != OK) {
+			Error err = d->make_dir(name);
+			ERR_FAIL_COND(err != OK);
+			d->change_dir(name);
+		}
 
-					/*
-				case ShaderLanguage::TYPE_SAMPLEREXT: {
-				} break;
-*/
+		//erase other versions?
+		if (shader_cache_cleanup_on_start) {
+		}
+		//
+		if (d->change_dir(base_sha256) != OK) {
+			Error err = d->make_dir(base_sha256);
+			ERR_FAIL_COND(err != OK);
+		}
+		shader_cache_dir_valid = true;
 
-				case ShaderLanguage::TYPE_ISAMPLER2D: {
-				} break;
+		print_verbose("Shader '" + name + "' SHA256: " + base_sha256);
+	}
 
-				case ShaderLanguage::TYPE_USAMPLER2D: {
-				} break;
+	glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units);
+}
 
-				case ShaderLanguage::TYPE_SAMPLERCUBE: {
-				} break;
+void ShaderGLES3::set_shader_cache_dir(const String &p_dir) {
+	shader_cache_dir = p_dir;
+}
 
-				case ShaderLanguage::TYPE_SAMPLER2DARRAY:
-				case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
-				case ShaderLanguage::TYPE_USAMPLER2DARRAY:
-				case ShaderLanguage::TYPE_SAMPLER3D:
-				case ShaderLanguage::TYPE_ISAMPLER3D:
-				case ShaderLanguage::TYPE_USAMPLER3D: {
-					// Not implemented in OpenGL
-				} break;
+void ShaderGLES3::set_shader_cache_save_compressed(bool p_enable) {
+	shader_cache_save_compressed = p_enable;
+}
 
-				case ShaderLanguage::TYPE_VOID: {
-					// Nothing to do?
-				} break;
-				default: {
-					ERR_PRINT("ShaderNode type missing, bug?");
-				} break;
-			}
-		}
-	}
+void ShaderGLES3::set_shader_cache_save_compressed_zstd(bool p_enable) {
+	shader_cache_save_compressed_zstd = p_enable;
 }
 
-ShaderGLES3::ShaderGLES3() {
-	version = NULL;
-	last_custom_code = 1;
-	uniforms_dirty = true;
+void ShaderGLES3::set_shader_cache_save_debug(bool p_enable) {
+	shader_cache_save_debug = p_enable;
 }
 
+String ShaderGLES3::shader_cache_dir;
+bool ShaderGLES3::shader_cache_save_compressed = true;
+bool ShaderGLES3::shader_cache_save_compressed_zstd = true;
+bool ShaderGLES3::shader_cache_save_debug = true;
+
 ShaderGLES3::~ShaderGLES3() {
-	finish();
+	List<RID> remaining;
+	version_owner.get_owned_list(&remaining);
+	if (remaining.size()) {
+		ERR_PRINT(itos(remaining.size()) + " shaders of type " + name + " were never freed");
+		while (remaining.size()) {
+			version_free(remaining.front()->get());
+			remaining.pop_front();
+		}
+	}
 }
-
-#endif // GLES3_BACKEND_ENABLED
+#endif

+ 138 - 178
drivers/gles3/shader_gles3.h

@@ -31,6 +31,15 @@
 #ifndef SHADER_OPENGL_H
 #define SHADER_OPENGL_H
 
+#include "core/os/mutex.h"
+#include "core/string/string_builder.h"
+#include "core/templates/hash_map.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/map.h"
+#include "core/templates/rid_owner.h"
+#include "core/variant/variant.h"
+#include "servers/rendering_server.h"
+
 #include "drivers/gles3/rasterizer_platforms.h"
 #ifdef GLES3_BACKEND_ENABLED
 
@@ -42,236 +51,187 @@
 #include OPENGL_INCLUDE_H
 #endif
 
-#include "core/math/camera_matrix.h"
-#include "core/templates/hash_map.h"
-#include "core/templates/map.h"
-#include "core/templates/pair.h"
-#include "core/variant/variant.h"
-#include "servers/rendering/shader_language.h"
-
 #include <stdio.h>
-
-class RasterizerStorageGLES3;
+/**
+	@author Juan Linietsky <[email protected]>
+*/
 
 class ShaderGLES3 {
 protected:
-	struct Enum {
-		uint64_t mask;
-		uint64_t shift;
-		const char *defines[16];
-	};
-
-	struct EnumValue {
-		uint64_t set_mask;
-		uint64_t clear_mask;
-	};
-
-	struct AttributePair {
+	struct TexUnitPair {
 		const char *name;
 		int index;
 	};
 
-	struct UniformPair {
+	struct UBOPair {
 		const char *name;
-		Variant::Type type_hint;
+		int index;
 	};
 
-	struct TexUnitPair {
+	struct Specialization {
 		const char *name;
-		int index;
+		bool defalut_value = false;
 	};
 
-	bool uniforms_dirty;
-
 private:
-	bool valid = false;
-
-	//@TODO Optimize to a fixed set of shader pools and use a LRU
-	int uniform_count;
-	int texunit_pair_count;
-	int conditional_count;
-	int vertex_code_start;
-	int fragment_code_start;
-	int attribute_pair_count;
-
-	struct CustomCode {
-		String vertex;
-		String vertex_globals;
-		String fragment;
-		String fragment_globals;
-		String light;
-		uint32_t version;
-		Vector<StringName> texture_uniforms;
-		Vector<StringName> custom_uniforms;
-		Vector<CharString> custom_defines;
-		Set<uint32_t> versions;
-	};
+	//versions
+	CharString general_defines;
 
 	struct Version {
-		GLuint id;
-		GLuint vert_id;
-		GLuint frag_id;
-		GLint *uniform_location;
-		Vector<GLint> texture_uniform_locations;
-		Map<StringName, GLint> custom_uniform_locations;
-		uint32_t code_version;
-		bool ok;
-		Version() {
-			id = 0;
-			vert_id = 0;
-			frag_id = 0;
-			uniform_location = NULL;
-			code_version = 0;
-			ok = false;
-		}
-	};
-
-	Version *version;
+		Vector<StringName> texture_uniforms;
+		CharString uniforms;
+		CharString vertex_globals;
+		CharString fragment_globals;
+		Map<StringName, CharString> code_sections;
+		Vector<CharString> custom_defines;
 
-	union VersionKey {
-		struct {
-			uint32_t version;
-			uint32_t code_version;
+		struct Specialization {
+			GLuint id;
+			GLuint vert_id;
+			GLuint frag_id;
+			LocalVector<GLint> uniform_location;
+			LocalVector<GLint> texture_uniform_locations;
+			Map<StringName, GLint> custom_uniform_locations;
+			bool build_queued = false;
+			bool ok = false;
+			Specialization() {
+				id = 0;
+				vert_id = 0;
+				frag_id = 0;
+			}
 		};
-		uint64_t key;
-		bool operator==(const VersionKey &p_key) const { return key == p_key.key; }
-		bool operator<(const VersionKey &p_key) const { return key < p_key.key; }
-	};
 
-	struct VersionKeyHash {
-		static _FORCE_INLINE_ uint32_t hash(const VersionKey &p_key) { return HashMapHasherDefault::hash(p_key.key); }
+		LocalVector<OAHashMap<uint64_t, Specialization>> variants;
 	};
 
-	//this should use a way more cachefriendly version..
-	HashMap<VersionKey, Version, VersionKeyHash> version_map;
-
-	HashMap<uint32_t, CustomCode> custom_code_map;
-	uint32_t last_custom_code;
+	Mutex variant_set_mutex;
 
-	VersionKey conditional_version;
-	VersionKey new_conditional_version;
+	void _compile_specialization(Version::Specialization &spec, uint32_t p_variant, Version *p_version, uint64_t p_specialization);
 
-	virtual String get_shader_name() const = 0;
+	void _clear_version(Version *p_version);
+	void _initialize_version(Version *p_version);
 
-	const char **conditional_defines;
-	const char **uniform_names;
-	const AttributePair *attribute_pairs;
-	const TexUnitPair *texunit_pairs;
-	const char *vertex_code;
-	const char *fragment_code;
-	CharString fragment_code0;
-	CharString fragment_code1;
-	CharString fragment_code2;
-	CharString fragment_code3;
+	RID_Owner<Version> version_owner;
 
-	CharString vertex_code0;
-	CharString vertex_code1;
-	CharString vertex_code2;
+	struct StageTemplate {
+		struct Chunk {
+			enum Type {
+				TYPE_MATERIAL_UNIFORMS,
+				TYPE_VERTEX_GLOBALS,
+				TYPE_FRAGMENT_GLOBALS,
+				TYPE_CODE,
+				TYPE_TEXT
+			};
 
-	Vector<CharString> custom_defines;
+			Type type;
+			StringName code;
+			CharString text;
+		};
+		LocalVector<Chunk> chunks;
+	};
 
-	Version *get_current_version();
+	String name;
 
-	static ShaderGLES3 *active;
+	String base_sha256;
 
-	int max_image_units;
+	static String shader_cache_dir;
+	static bool shader_cache_cleanup_on_start;
+	static bool shader_cache_save_compressed;
+	static bool shader_cache_save_compressed_zstd;
+	static bool shader_cache_save_debug;
+	bool shader_cache_dir_valid = false;
 
-	Map<StringName, Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value>>> uniform_values;
+	GLint max_image_units;
 
-protected:
-	_FORCE_INLINE_ int _get_uniform(int p_which) const;
-	_FORCE_INLINE_ void _set_conditional(int p_which, bool p_value);
-
-	void setup(const char **p_conditional_defines,
-			int p_conditional_count,
-			const char **p_uniform_names,
-			int p_uniform_count,
-			const AttributePair *p_attribute_pairs,
-			int p_attribute_count,
-			const TexUnitPair *p_texunit_pairs,
-			int p_texunit_pair_count,
-			const char *p_vertex_code,
-			const char *p_fragment_code,
-			int p_vertex_code_start,
-			int p_fragment_code_start);
+	enum StageType {
+		STAGE_TYPE_VERTEX,
+		STAGE_TYPE_FRAGMENT,
+		STAGE_TYPE_MAX,
+	};
 
-	ShaderGLES3();
+	StageTemplate stage_templates[STAGE_TYPE_MAX];
 
-public:
-	enum {
-		CUSTOM_SHADER_DISABLED = 0
-	};
+	void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization);
 
-	GLint get_uniform_location(const String &p_name) const;
-	GLint get_uniform_location(int p_index) const;
+	void _add_stage(const char *p_code, StageType p_stage_type);
 
-	static _FORCE_INLINE_ ShaderGLES3 *get_active() { return active; }
-	bool bind();
-	void unbind();
+	String _version_get_sha1(Version *p_version) const;
+	bool _load_from_cache(Version *p_version);
+	void _save_to_cache(Version *p_version);
 
-	inline GLuint get_program() const { return version ? version->id : 0; }
+	const char **uniform_names = nullptr;
+	int uniform_count = 0;
+	const UBOPair *ubo_pairs = nullptr;
+	int ubo_count = 0;
+	const TexUnitPair *texunit_pairs = nullptr;
+	int texunit_pair_count = 0;
+	int specialization_count = 0;
+	const Specialization *specializations = nullptr;
+	uint64_t specialization_default_mask = 0;
+	const char **variant_defines = nullptr;
+	int variant_count = 0;
 
-	void clear_caches();
+	int base_texture_index = 0;
 
-	uint32_t create_custom_shader();
-	void set_custom_shader_code(uint32_t p_code_id,
-			const String &p_vertex,
-			const String &p_vertex_globals,
-			const String &p_fragment,
-			const String &p_light,
-			const String &p_fragment_globals,
-			const Vector<StringName> &p_uniforms,
-			const Vector<StringName> &p_texture_uniforms,
-			const Vector<CharString> &p_custom_defines);
+protected:
+	ShaderGLES3();
+	void _setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name, int p_uniform_count, const char **p_uniform_names, int p_ubo_count, const UBOPair *p_ubos, int p_texture_count, const TexUnitPair *p_tex_units, int p_specialization_count, const Specialization *p_specializations, int p_variant_count, const char **p_variants);
 
-	void set_custom_shader(uint32_t p_code_id);
-	void free_custom_shader(uint32_t p_code_id);
+	_FORCE_INLINE_ void _version_bind_shader(RID p_version, int p_variant, uint64_t p_specialization) {
+		ERR_FAIL_INDEX(p_variant, variant_count);
 
-	uint32_t get_version_key() const { return conditional_version.version; }
+		Version *version = version_owner.get_or_null(p_version);
+		ERR_FAIL_COND(!version);
 
-	// this void* is actually a RasterizerStorageGLES3::Material, but C++ doesn't
-	// like forward declared nested classes.
-	void use_material(void *p_material);
+		if (version->variants.size() == 0) {
+			_initialize_version(version); //may lack initialization
+		}
 
-	_FORCE_INLINE_ uint32_t get_version() const { return new_conditional_version.version; }
-	_FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; }
+		Version::Specialization *spec = version->variants[p_variant].lookup_ptr(p_specialization);
+		if (!spec) {
+			if (false) {
+				// Queue load this specialization and use defaults in the meantime (TODO)
+
+				spec = version->variants[p_variant].lookup_ptr(specialization_default_mask);
+			} else {
+				// Compile on the spot
+				Version::Specialization s;
+				_compile_specialization(s, p_variant, version, p_specialization);
+				version->variants[p_variant].insert(p_specialization, s);
+				spec = version->variants[p_variant].lookup_ptr(p_specialization);
+			}
+		} else if (spec->build_queued) {
+			// Still queued, wait
+			spec = version->variants[p_variant].lookup_ptr(specialization_default_mask);
+		}
 
-	virtual void init() = 0;
-	void finish();
+		ERR_FAIL_COND(!spec); // Should never happen
+		ERR_FAIL_COND(!spec->ok); // Should never happen
 
-	void add_custom_define(const String &p_define) {
-		custom_defines.push_back(p_define.utf8());
+		glUseProgram(spec->id);
 	}
 
-	void get_custom_defines(Vector<String> *p_defines) {
-		for (int i = 0; i < custom_defines.size(); i++) {
-			p_defines->push_back(custom_defines[i].get_data());
-		}
-	}
+	virtual void _init() = 0;
 
-	void remove_custom_define(const String &p_define) {
-		custom_defines.erase(p_define.utf8());
-	}
+public:
+	RID version_create();
 
-	virtual ~ShaderGLES3();
-};
+	void version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const Vector<StringName> &p_texture_uniforms, bool p_initialize = false);
+
+	bool version_is_valid(RID p_version);
 
-// called a lot, made inline
+	bool version_free(RID p_version);
 
-int ShaderGLES3::_get_uniform(int p_which) const {
-	ERR_FAIL_INDEX_V(p_which, uniform_count, -1);
-	ERR_FAIL_COND_V(!version, -1);
-	return version->uniform_location[p_which];
-}
+	static void set_shader_cache_dir(const String &p_dir);
+	static void set_shader_cache_save_compressed(bool p_enable);
+	static void set_shader_cache_save_compressed_zstd(bool p_enable);
+	static void set_shader_cache_save_debug(bool p_enable);
 
-void ShaderGLES3::_set_conditional(int p_which, bool p_value) {
-	ERR_FAIL_INDEX(p_which, conditional_count);
-	if (p_value)
-		new_conditional_version.version |= (1 << p_which);
-	else
-		new_conditional_version.version &= ~(1 << p_which);
-}
+	RS::ShaderNativeSourceCode version_get_native_source_code(RID p_version);
 
-#endif // GLES3_BACKEND_ENABLED
+	void initialize(const String &p_general_defines = "", int p_base_texture_index = 0);
+	virtual ~ShaderGLES3();
+};
 
 #endif // SHADER_OPENGL_H
+#endif

+ 1116 - 0
drivers/gles3/shader_old_gles3.cpp

@@ -0,0 +1,1116 @@
+/*************************************************************************/
+/*  shader_gles3.cpp                                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 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 "shader_old_gles3.h"
+#include "drivers/gles3/rasterizer_platforms.h"
+#ifdef GLES3_BACKEND_ENABLED
+
+#include "rasterizer_gles3.h"
+#include "rasterizer_storage_gles3.h"
+
+#include "core/config/project_settings.h"
+#include "core/os/memory.h"
+#include "core/string/print_string.h"
+#include "core/string/string_builder.h"
+
+// #define DEBUG_OPENGL
+
+// #include "shaders/copy.glsl.gen.h"
+
+#ifdef DEBUG_OPENGL
+
+#define DEBUG_TEST_ERROR(m_section)                                         \
+	{                                                                       \
+		uint32_t err = glGetError();                                        \
+		if (err) {                                                          \
+			print_line("OpenGL Error #" + itos(err) + " at: " + m_section); \
+		}                                                                   \
+	}
+#else
+
+#define DEBUG_TEST_ERROR(m_section)
+
+#endif
+
+ShaderOLDGLES3 *ShaderOLDGLES3::active = NULL;
+
+//#define DEBUG_SHADER
+
+#ifdef DEBUG_SHADER
+
+#define DEBUG_PRINT(m_text) print_line(m_text);
+
+#else
+
+#define DEBUG_PRINT(m_text)
+
+#endif
+
+GLint ShaderOLDGLES3::get_uniform_location(int p_index) const {
+	ERR_FAIL_COND_V(!version, -1);
+
+	return version->uniform_location[p_index];
+}
+
+bool ShaderOLDGLES3::bind() {
+	if (active != this || !version || new_conditional_version.key != conditional_version.key) {
+		conditional_version = new_conditional_version;
+		version = get_current_version();
+	} else {
+		return false;
+	}
+
+	ERR_FAIL_COND_V(!version, false);
+
+	if (!version->ok) { //broken, unable to bind (do not throw error, you saw it before already when it failed compilation).
+		glUseProgram(0);
+		return false;
+	}
+
+	glUseProgram(version->id);
+
+	DEBUG_TEST_ERROR("use program");
+
+	active = this;
+	uniforms_dirty = true;
+
+	return true;
+}
+
+void ShaderOLDGLES3::unbind() {
+	version = NULL;
+	glUseProgram(0);
+	uniforms_dirty = true;
+	active = NULL;
+}
+
+static void _display_error_with_code(const String &p_error, const Vector<const char *> &p_code) {
+	int line = 1;
+	String total_code;
+
+	for (int i = 0; i < p_code.size(); i++) {
+		total_code += String(p_code[i]);
+	}
+
+	Vector<String> lines = String(total_code).split("\n");
+
+	for (int j = 0; j < lines.size(); j++) {
+		print_line(itos(line) + ": " + lines[j]);
+		line++;
+	}
+
+	ERR_PRINT(p_error);
+}
+
+static String _mkid(const String &p_id) {
+	String id = "m_" + p_id;
+	return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl
+}
+
+ShaderOLDGLES3::Version *ShaderOLDGLES3::get_current_version() {
+	if (!valid)
+		return nullptr;
+
+	Version *_v = version_map.getptr(conditional_version);
+
+	if (_v) {
+		if (conditional_version.code_version != 0) {
+			CustomCode *cc = custom_code_map.getptr(conditional_version.code_version);
+			ERR_FAIL_COND_V(!cc, _v);
+			if (cc->version == _v->code_version)
+				return _v;
+		} else {
+			return _v;
+		}
+	}
+
+	if (!_v)
+		version_map[conditional_version] = Version();
+
+	Version &v = version_map[conditional_version];
+
+	if (!_v) {
+		v.uniform_location = memnew_arr(GLint, uniform_count);
+	} else {
+		if (v.ok) {
+			glDeleteShader(v.vert_id);
+			glDeleteShader(v.frag_id);
+			glDeleteProgram(v.id);
+			v.id = 0;
+		}
+	}
+
+	v.ok = false;
+
+	Vector<const char *> strings;
+
+#ifdef GLES_OVER_GL
+	strings.push_back("#version 330\n");
+	strings.push_back("#define USE_GLES_OVER_GL\n");
+#else
+	strings.push_back("#version 300 es\n");
+//angle does not like
+#ifdef JAVASCRIPT_ENABLED
+	strings.push_back("#define USE_HIGHP_PRECISION\n");
+#endif
+
+	//if (GLOBAL_GET("rendering/opengl/compatibility/enable_high_float.Android")) {
+	// enable USE_HIGHP_PRECISION but safeguarded by an availability check as highp support is optional in OpenGL
+	// see Section 4.5.4 of the GLSL_ES_Specification_1.00
+	//strings.push_back("#ifdef GL_FRAGMENT_PRECISION_HIGH\n  #define USE_HIGHP_PRECISION\n#endif\n");
+	//}
+
+#endif
+
+#ifdef ANDROID_ENABLED
+	strings.push_back("#define ANDROID_ENABLED\n");
+#endif
+
+	for (int i = 0; i < custom_defines.size(); i++) {
+		strings.push_back(custom_defines[i].get_data());
+		strings.push_back("\n");
+	}
+
+	for (int j = 0; j < conditional_count; j++) {
+		bool enable = (conditional_version.version & (1 << j)) > 0;
+
+		if (enable) {
+			strings.push_back(conditional_defines[j]);
+			DEBUG_PRINT(conditional_defines[j]);
+		}
+	}
+
+	// keep them around during the function
+	CharString code_string;
+	CharString code_string2;
+	CharString code_globals;
+
+	CustomCode *cc = NULL;
+
+	if (conditional_version.code_version > 0) {
+		cc = custom_code_map.getptr(conditional_version.code_version);
+
+		ERR_FAIL_COND_V(!cc, NULL);
+		v.code_version = cc->version;
+	}
+
+	// program
+
+	v.id = glCreateProgram();
+	ERR_FAIL_COND_V(v.id == 0, NULL);
+
+	if (cc) {
+		for (int i = 0; i < cc->custom_defines.size(); i++) {
+			strings.push_back(cc->custom_defines.write[i]);
+			DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i].get_data()));
+		}
+	}
+
+	// vertex shader
+
+	int string_base_size = strings.size();
+
+	strings.push_back(vertex_code0.get_data());
+
+	if (cc) {
+		code_globals = cc->vertex_globals.ascii();
+		strings.push_back(code_globals.get_data());
+	}
+
+	strings.push_back(vertex_code1.get_data());
+
+	if (cc) {
+		code_string = cc->vertex.ascii();
+		strings.push_back(code_string.get_data());
+	}
+
+	strings.push_back(vertex_code2.get_data());
+
+#ifdef DEBUG_SHADER
+
+	DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data()));
+
+#endif
+
+	v.vert_id = glCreateShader(GL_VERTEX_SHADER);
+	glShaderSource(v.vert_id, strings.size(), &strings[0], NULL);
+	glCompileShader(v.vert_id);
+
+	GLint status;
+
+	glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status);
+	if (status == GL_FALSE) {
+		GLsizei iloglen;
+		glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen);
+
+		if (iloglen < 0) {
+			glDeleteShader(v.vert_id);
+			glDeleteProgram(v.id);
+			v.id = 0;
+
+			ERR_PRINT("No OpenGL vertex shader compiler log. What the frick?");
+		} else {
+			if (iloglen == 0) {
+				iloglen = 4096; // buggy driver (Adreno 220+)
+			}
+
+			char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
+			ilogmem[iloglen] = '\0';
+			glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem);
+
+			String err_string = get_shader_name() + ": Vertex shader compilation failed:\n";
+
+			err_string += ilogmem;
+
+			_display_error_with_code(err_string, strings);
+
+			Memory::free_static(ilogmem);
+			glDeleteShader(v.vert_id);
+			glDeleteProgram(v.id);
+			v.id = 0;
+		}
+
+		ERR_FAIL_V(NULL);
+	}
+
+	strings.resize(string_base_size);
+
+	// fragment shader
+
+	strings.push_back(fragment_code0.get_data());
+
+	if (cc) {
+		code_globals = cc->fragment_globals.ascii();
+		strings.push_back(code_globals.get_data());
+	}
+
+	strings.push_back(fragment_code1.get_data());
+
+	if (cc) {
+		code_string = cc->light.ascii();
+		strings.push_back(code_string.get_data());
+	}
+
+	strings.push_back(fragment_code2.get_data());
+
+	if (cc) {
+		code_string2 = cc->fragment.ascii();
+		strings.push_back(code_string2.get_data());
+	}
+
+	strings.push_back(fragment_code3.get_data());
+
+#ifdef DEBUG_SHADER
+
+	if (cc) {
+		DEBUG_PRINT("\nFragment Code:\n\n" + String(cc->fragment_globals));
+	}
+	DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string.get_data()));
+#endif
+
+	v.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
+	glShaderSource(v.frag_id, strings.size(), &strings[0], NULL);
+	glCompileShader(v.frag_id);
+
+	glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status);
+	if (status == GL_FALSE) {
+		GLsizei iloglen;
+		glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen);
+
+		if (iloglen < 0) {
+			glDeleteShader(v.frag_id);
+			glDeleteShader(v.vert_id);
+			glDeleteProgram(v.id);
+			v.id = 0;
+
+			ERR_PRINT("No OpenGL fragment shader compiler log. What the frick?");
+		} else {
+			if (iloglen == 0) {
+				iloglen = 4096; // buggy driver (Adreno 220+)
+			}
+
+			char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
+			ilogmem[iloglen] = '\0';
+			glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem);
+
+			String err_string = get_shader_name() + ": Fragment shader compilation failed:\n";
+
+			err_string += ilogmem;
+
+			_display_error_with_code(err_string, strings);
+
+			Memory::free_static(ilogmem);
+			glDeleteShader(v.frag_id);
+			glDeleteShader(v.vert_id);
+			glDeleteProgram(v.id);
+			v.id = 0;
+		}
+
+		ERR_FAIL_V(NULL);
+	}
+
+	glAttachShader(v.id, v.frag_id);
+	glAttachShader(v.id, v.vert_id);
+
+	// bind the attribute locations. This has to be done before linking so that the
+	// linker doesn't assign some random indices
+
+	for (int i = 0; i < attribute_pair_count; i++) {
+		glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name);
+	}
+
+	glLinkProgram(v.id);
+
+	glGetProgramiv(v.id, GL_LINK_STATUS, &status);
+	if (status == GL_FALSE) {
+		GLsizei iloglen;
+		glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen);
+
+		if (iloglen < 0) {
+			glDeleteShader(v.frag_id);
+			glDeleteShader(v.vert_id);
+			glDeleteProgram(v.id);
+			v.id = 0;
+
+			ERR_PRINT("No OpenGL program link log. What the frick?");
+			ERR_FAIL_V(NULL);
+		}
+
+		if (iloglen == 0) {
+			iloglen = 4096; // buggy driver (Adreno 220+)
+		}
+
+		char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
+		ilogmem[iloglen] = '\0';
+		glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem);
+
+		String err_string = get_shader_name() + ": Program linking failed:\n";
+
+		err_string += ilogmem;
+
+		_display_error_with_code(err_string, strings);
+
+		Memory::free_static(ilogmem);
+		glDeleteShader(v.frag_id);
+		glDeleteShader(v.vert_id);
+		glDeleteProgram(v.id);
+		v.id = 0;
+
+		ERR_FAIL_V(NULL);
+	}
+
+	// get uniform locations
+
+	glUseProgram(v.id);
+
+	for (int i = 0; i < uniform_count; i++) {
+		v.uniform_location[i] = glGetUniformLocation(v.id, uniform_names[i]);
+	}
+
+	for (int i = 0; i < texunit_pair_count; i++) {
+		GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name);
+		if (loc >= 0) {
+			if (texunit_pairs[i].index < 0) {
+				glUniform1i(loc, max_image_units + texunit_pairs[i].index);
+			} else {
+				glUniform1i(loc, texunit_pairs[i].index);
+			}
+		}
+	}
+
+	if (cc) {
+		// uniforms
+		for (int i = 0; i < cc->custom_uniforms.size(); i++) {
+			String native_uniform_name = _mkid(cc->custom_uniforms[i]);
+			GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data());
+			v.custom_uniform_locations[cc->custom_uniforms[i]] = location;
+		}
+
+		// textures
+		for (int i = 0; i < cc->texture_uniforms.size(); i++) {
+			String native_uniform_name = _mkid(cc->texture_uniforms[i]);
+			GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data());
+			v.custom_uniform_locations[cc->texture_uniforms[i]] = location;
+			glUniform1i(location, i);
+		}
+	}
+
+	glUseProgram(0);
+	v.ok = true;
+
+	if (cc) {
+		cc->versions.insert(conditional_version.version);
+	}
+
+	return &v;
+}
+
+GLint ShaderOLDGLES3::get_uniform_location(const String &p_name) const {
+	ERR_FAIL_COND_V(!version, -1);
+	return glGetUniformLocation(version->id, p_name.ascii().get_data());
+}
+
+void ShaderOLDGLES3::setup(
+		const char **p_conditional_defines,
+		int p_conditional_count,
+		const char **p_uniform_names,
+		int p_uniform_count,
+		const AttributePair *p_attribute_pairs,
+		int p_attribute_count,
+		const TexUnitPair *p_texunit_pairs,
+		int p_texunit_pair_count,
+		const char *p_vertex_code,
+		const char *p_fragment_code,
+		int p_vertex_code_start,
+		int p_fragment_code_start) {
+	ERR_FAIL_COND(version);
+
+	conditional_version.key = 0;
+	new_conditional_version.key = 0;
+	uniform_count = p_uniform_count;
+	conditional_count = p_conditional_count;
+	conditional_defines = p_conditional_defines;
+	uniform_names = p_uniform_names;
+	vertex_code = p_vertex_code;
+	fragment_code = p_fragment_code;
+	texunit_pairs = p_texunit_pairs;
+	texunit_pair_count = p_texunit_pair_count;
+	vertex_code_start = p_vertex_code_start;
+	fragment_code_start = p_fragment_code_start;
+	attribute_pairs = p_attribute_pairs;
+	attribute_pair_count = p_attribute_count;
+
+	{
+		String globals_tag = "\nVERTEX_SHADER_GLOBALS";
+		String code_tag = "\nVERTEX_SHADER_CODE";
+		String code = vertex_code;
+		int cpos = code.find(globals_tag);
+		if (cpos == -1) {
+			vertex_code0 = code.ascii();
+		} else {
+			vertex_code0 = code.substr(0, cpos).ascii();
+			code = code.substr(cpos + globals_tag.length(), code.length());
+
+			cpos = code.find(code_tag);
+
+			if (cpos == -1) {
+				vertex_code1 = code.ascii();
+			} else {
+				vertex_code1 = code.substr(0, cpos).ascii();
+				vertex_code2 = code.substr(cpos + code_tag.length(), code.length()).ascii();
+			}
+		}
+	}
+
+	{
+		String globals_tag = "\nFRAGMENT_SHADER_GLOBALS";
+		String code_tag = "\nFRAGMENT_SHADER_CODE";
+		String light_code_tag = "\nLIGHT_SHADER_CODE";
+		String code = fragment_code;
+		int cpos = code.find(globals_tag);
+		if (cpos == -1) {
+			fragment_code0 = code.ascii();
+		} else {
+			fragment_code0 = code.substr(0, cpos).ascii();
+			code = code.substr(cpos + globals_tag.length(), code.length());
+
+			cpos = code.find(light_code_tag);
+
+			String code2;
+
+			if (cpos != -1) {
+				fragment_code1 = code.substr(0, cpos).ascii();
+				code2 = code.substr(cpos + light_code_tag.length(), code.length());
+			} else {
+				code2 = code;
+			}
+
+			cpos = code2.find(code_tag);
+			if (cpos == -1) {
+				fragment_code2 = code2.ascii();
+			} else {
+				fragment_code2 = code2.substr(0, cpos).ascii();
+				fragment_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii();
+			}
+		}
+	}
+
+	glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units);
+
+	valid = true;
+}
+
+void ShaderOLDGLES3::finish() {
+	const VersionKey *V = NULL;
+
+	while ((V = version_map.next(V))) {
+		Version &v = version_map[*V];
+		glDeleteShader(v.vert_id);
+		glDeleteShader(v.frag_id);
+		glDeleteProgram(v.id);
+
+		if (v.uniform_location)
+			memdelete_arr(v.uniform_location);
+	}
+}
+
+void ShaderOLDGLES3::clear_caches() {
+	const VersionKey *V = NULL;
+
+	while ((V = version_map.next(V))) {
+		Version &v = version_map[*V];
+		glDeleteShader(v.vert_id);
+		glDeleteShader(v.frag_id);
+		glDeleteProgram(v.id);
+		memdelete_arr(v.uniform_location);
+	}
+
+	version_map.clear();
+
+	custom_code_map.clear();
+	version = NULL;
+	last_custom_code = 1;
+	uniforms_dirty = true;
+}
+
+uint32_t ShaderOLDGLES3::create_custom_shader() {
+	custom_code_map[last_custom_code] = CustomCode();
+	custom_code_map[last_custom_code].version = 1;
+	return last_custom_code++;
+}
+
+void ShaderOLDGLES3::set_custom_shader_code(uint32_t p_code_id,
+		const String &p_vertex,
+		const String &p_vertex_globals,
+		const String &p_fragment,
+		const String &p_light,
+		const String &p_fragment_globals,
+		const Vector<StringName> &p_uniforms,
+		const Vector<StringName> &p_texture_uniforms,
+		const Vector<CharString> &p_custom_defines) {
+	CustomCode *cc = custom_code_map.getptr(p_code_id);
+	ERR_FAIL_COND(!cc);
+
+	cc->vertex = p_vertex;
+	cc->vertex_globals = p_vertex_globals;
+	cc->fragment = p_fragment;
+	cc->fragment_globals = p_fragment_globals;
+	cc->light = p_light;
+	cc->custom_uniforms = p_uniforms;
+	cc->custom_defines = p_custom_defines;
+	cc->texture_uniforms = p_texture_uniforms;
+	cc->version++;
+}
+
+void ShaderOLDGLES3::set_custom_shader(uint32_t p_code_id) {
+	new_conditional_version.code_version = p_code_id;
+}
+
+void ShaderOLDGLES3::free_custom_shader(uint32_t p_code_id) {
+	ERR_FAIL_COND(!custom_code_map.has(p_code_id));
+	if (conditional_version.code_version == p_code_id) {
+		conditional_version.code_version = 0; //do not keep using a version that is going away
+		unbind();
+	}
+
+	VersionKey key;
+	key.code_version = p_code_id;
+	for (Set<uint32_t>::Element *E = custom_code_map[p_code_id].versions.front(); E; E = E->next()) {
+		key.version = E->get();
+		ERR_CONTINUE(!version_map.has(key));
+		Version &v = version_map[key];
+
+		glDeleteShader(v.vert_id);
+		glDeleteShader(v.frag_id);
+		glDeleteProgram(v.id);
+		memdelete_arr(v.uniform_location);
+		v.id = 0;
+
+		version_map.erase(key);
+	}
+
+	custom_code_map.erase(p_code_id);
+}
+
+void ShaderOLDGLES3::use_material(void *p_material) {
+	RasterizerStorageGLES3::Material *material = (RasterizerStorageGLES3::Material *)p_material;
+
+	if (!material) {
+		return;
+	}
+
+	if (!material->shader) {
+		return;
+	}
+
+	Version *v = version_map.getptr(conditional_version);
+
+	// bind uniforms
+	for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) {
+		if (E->get().texture_order >= 0)
+			continue; // this is a texture, doesn't go here
+
+		Map<StringName, GLint>::Element *L = v->custom_uniform_locations.find(E->key());
+		if (!L || L->get() < 0)
+			continue; //uniform not valid
+
+		GLuint location = L->get();
+
+		Map<StringName, Variant>::Element *V = material->params.find(E->key());
+
+		if (V) {
+			switch (E->get().type) {
+				case ShaderLanguage::TYPE_BOOL: {
+					bool boolean = V->get();
+					glUniform1i(location, boolean ? 1 : 0);
+				} break;
+
+				case ShaderLanguage::TYPE_BVEC2: {
+					int flags = V->get();
+					glUniform2i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0);
+				} break;
+
+				case ShaderLanguage::TYPE_BVEC3: {
+					int flags = V->get();
+					glUniform3i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0);
+
+				} break;
+
+				case ShaderLanguage::TYPE_BVEC4: {
+					int flags = V->get();
+					glUniform4i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0, (flags & 8) ? 1 : 0);
+
+				} break;
+
+				case ShaderLanguage::TYPE_INT:
+				case ShaderLanguage::TYPE_UINT: {
+					int value = V->get();
+					glUniform1i(location, value);
+				} break;
+
+				case ShaderLanguage::TYPE_IVEC2:
+				case ShaderLanguage::TYPE_UVEC2: {
+					Array r = V->get();
+					const int count = 2;
+					if (r.size() == count) {
+						int values[count];
+						for (int i = 0; i < count; i++) {
+							values[i] = r[i];
+						}
+						glUniform2i(location, values[0], values[1]);
+					}
+
+				} break;
+
+				case ShaderLanguage::TYPE_IVEC3:
+				case ShaderLanguage::TYPE_UVEC3: {
+					Array r = V->get();
+					const int count = 3;
+					if (r.size() == count) {
+						int values[count];
+						for (int i = 0; i < count; i++) {
+							values[i] = r[i];
+						}
+						glUniform3i(location, values[0], values[1], values[2]);
+					}
+
+				} break;
+
+				case ShaderLanguage::TYPE_IVEC4:
+				case ShaderLanguage::TYPE_UVEC4: {
+					Array r = V->get();
+					const int count = 4;
+					if (r.size() == count) {
+						int values[count];
+						for (int i = 0; i < count; i++) {
+							values[i] = r[i];
+						}
+						glUniform4i(location, values[0], values[1], values[2], values[3]);
+					}
+
+				} break;
+
+				case ShaderLanguage::TYPE_FLOAT: {
+					float value = V->get();
+					glUniform1f(location, value);
+
+				} break;
+
+				case ShaderLanguage::TYPE_VEC2: {
+					Vector2 value = V->get();
+					glUniform2f(location, value.x, value.y);
+				} break;
+
+				case ShaderLanguage::TYPE_VEC3: {
+					Vector3 value = V->get();
+					glUniform3f(location, value.x, value.y, value.z);
+				} break;
+
+				case ShaderLanguage::TYPE_VEC4: {
+					if (V->get().get_type() == Variant::COLOR) {
+						Color value = V->get();
+						glUniform4f(location, value.r, value.g, value.b, value.a);
+					} else if (V->get().get_type() == Variant::QUATERNION) {
+						Quaternion value = V->get();
+						glUniform4f(location, value.x, value.y, value.z, value.w);
+					} else {
+						Plane value = V->get();
+						glUniform4f(location, value.normal.x, value.normal.y, value.normal.z, value.d);
+					}
+
+				} break;
+
+				case ShaderLanguage::TYPE_MAT2: {
+					Transform2D tr = V->get();
+					GLfloat matrix[4] = {
+						/* build a 16x16 matrix */
+						tr.elements[0][0],
+						tr.elements[0][1],
+						tr.elements[1][0],
+						tr.elements[1][1],
+					};
+					glUniformMatrix2fv(location, 1, GL_FALSE, matrix);
+
+				} break;
+
+				case ShaderLanguage::TYPE_MAT3: {
+					Basis val = V->get();
+
+					GLfloat mat[9] = {
+						val.elements[0][0],
+						val.elements[1][0],
+						val.elements[2][0],
+						val.elements[0][1],
+						val.elements[1][1],
+						val.elements[2][1],
+						val.elements[0][2],
+						val.elements[1][2],
+						val.elements[2][2],
+					};
+
+					glUniformMatrix3fv(location, 1, GL_FALSE, mat);
+
+				} break;
+
+				case ShaderLanguage::TYPE_MAT4: {
+					Transform2D tr = V->get();
+					GLfloat matrix[16] = { /* build a 16x16 matrix */
+						tr.elements[0][0],
+						tr.elements[0][1],
+						0,
+						0,
+						tr.elements[1][0],
+						tr.elements[1][1],
+						0,
+						0,
+						0,
+						0,
+						1,
+						0,
+						tr.elements[2][0],
+						tr.elements[2][1],
+						0,
+						1
+					};
+
+					glUniformMatrix4fv(location, 1, GL_FALSE, matrix);
+
+				} break;
+
+				default: {
+					ERR_PRINT("ShaderNode type missing, bug?");
+				} break;
+			}
+		} else if (E->get().default_value.size()) {
+			const Vector<ShaderLanguage::ConstantNode::Value> &values = E->get().default_value;
+			switch (E->get().type) {
+				case ShaderLanguage::TYPE_BOOL: {
+					glUniform1i(location, values[0].boolean);
+				} break;
+
+				case ShaderLanguage::TYPE_BVEC2: {
+					glUniform2i(location, values[0].boolean, values[1].boolean);
+				} break;
+
+				case ShaderLanguage::TYPE_BVEC3: {
+					glUniform3i(location, values[0].boolean, values[1].boolean, values[2].boolean);
+				} break;
+
+				case ShaderLanguage::TYPE_BVEC4: {
+					glUniform4i(location, values[0].boolean, values[1].boolean, values[2].boolean, values[3].boolean);
+				} break;
+
+				case ShaderLanguage::TYPE_INT: {
+					glUniform1i(location, values[0].sint);
+				} break;
+
+				case ShaderLanguage::TYPE_IVEC2: {
+					glUniform2i(location, values[0].sint, values[1].sint);
+				} break;
+
+				case ShaderLanguage::TYPE_IVEC3: {
+					glUniform3i(location, values[0].sint, values[1].sint, values[2].sint);
+				} break;
+
+				case ShaderLanguage::TYPE_IVEC4: {
+					glUniform4i(location, values[0].sint, values[1].sint, values[2].sint, values[3].sint);
+				} break;
+
+				case ShaderLanguage::TYPE_UINT: {
+					glUniform1i(location, values[0].uint);
+				} break;
+
+				case ShaderLanguage::TYPE_UVEC2: {
+					glUniform2i(location, values[0].uint, values[1].uint);
+				} break;
+
+				case ShaderLanguage::TYPE_UVEC3: {
+					glUniform3i(location, values[0].uint, values[1].uint, values[2].uint);
+				} break;
+
+				case ShaderLanguage::TYPE_UVEC4: {
+					glUniform4i(location, values[0].uint, values[1].uint, values[2].uint, values[3].uint);
+				} break;
+
+				case ShaderLanguage::TYPE_FLOAT: {
+					glUniform1f(location, values[0].real);
+				} break;
+
+				case ShaderLanguage::TYPE_VEC2: {
+					glUniform2f(location, values[0].real, values[1].real);
+				} break;
+
+				case ShaderLanguage::TYPE_VEC3: {
+					glUniform3f(location, values[0].real, values[1].real, values[2].real);
+				} break;
+
+				case ShaderLanguage::TYPE_VEC4: {
+					glUniform4f(location, values[0].real, values[1].real, values[2].real, values[3].real);
+				} break;
+
+				case ShaderLanguage::TYPE_MAT2: {
+					GLfloat mat[4];
+
+					for (int i = 0; i < 4; i++) {
+						mat[i] = values[i].real;
+					}
+
+					glUniformMatrix2fv(location, 1, GL_FALSE, mat);
+				} break;
+
+				case ShaderLanguage::TYPE_MAT3: {
+					GLfloat mat[9];
+
+					for (int i = 0; i < 9; i++) {
+						mat[i] = values[i].real;
+					}
+
+					glUniformMatrix3fv(location, 1, GL_FALSE, mat);
+
+				} break;
+
+				case ShaderLanguage::TYPE_MAT4: {
+					GLfloat mat[16];
+
+					for (int i = 0; i < 16; i++) {
+						mat[i] = values[i].real;
+					}
+
+					glUniformMatrix4fv(location, 1, GL_FALSE, mat);
+
+				} break;
+
+				case ShaderLanguage::TYPE_SAMPLER2D: {
+				} break;
+
+					/*
+				case ShaderLanguage::TYPE_SAMPLEREXT: {
+				} break;
+*/
+				case ShaderLanguage::TYPE_ISAMPLER2D: {
+				} break;
+
+				case ShaderLanguage::TYPE_USAMPLER2D: {
+				} break;
+
+				case ShaderLanguage::TYPE_SAMPLERCUBE: {
+				} break;
+
+				case ShaderLanguage::TYPE_SAMPLER2DARRAY:
+				case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
+				case ShaderLanguage::TYPE_USAMPLER2DARRAY:
+				case ShaderLanguage::TYPE_SAMPLER3D:
+				case ShaderLanguage::TYPE_ISAMPLER3D:
+				case ShaderLanguage::TYPE_USAMPLER3D: {
+					// Not implemented in OpenGL
+				} break;
+
+				case ShaderLanguage::TYPE_VOID: {
+					// Nothing to do?
+				} break;
+				default: {
+					ERR_PRINT("ShaderNode type missing, bug?");
+				} break;
+			}
+		} else { //zero
+
+			switch (E->get().type) {
+				case ShaderLanguage::TYPE_BOOL: {
+					glUniform1i(location, GL_FALSE);
+				} break;
+
+				case ShaderLanguage::TYPE_BVEC2: {
+					glUniform2i(location, GL_FALSE, GL_FALSE);
+				} break;
+
+				case ShaderLanguage::TYPE_BVEC3: {
+					glUniform3i(location, GL_FALSE, GL_FALSE, GL_FALSE);
+				} break;
+
+				case ShaderLanguage::TYPE_BVEC4: {
+					glUniform4i(location, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+				} break;
+
+				case ShaderLanguage::TYPE_INT: {
+					glUniform1i(location, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_IVEC2: {
+					glUniform2i(location, 0, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_IVEC3: {
+					glUniform3i(location, 0, 0, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_IVEC4: {
+					glUniform4i(location, 0, 0, 0, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_UINT: {
+					glUniform1i(location, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_UVEC2: {
+					glUniform2i(location, 0, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_UVEC3: {
+					glUniform3i(location, 0, 0, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_UVEC4: {
+					glUniform4i(location, 0, 0, 0, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_FLOAT: {
+					glUniform1f(location, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_VEC2: {
+					glUniform2f(location, 0, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_VEC3: {
+					glUniform3f(location, 0, 0, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_VEC4: {
+					glUniform4f(location, 0, 0, 0, 0);
+				} break;
+
+				case ShaderLanguage::TYPE_MAT2: {
+					GLfloat mat[4] = { 0, 0, 0, 0 };
+
+					glUniformMatrix2fv(location, 1, GL_FALSE, mat);
+				} break;
+
+				case ShaderLanguage::TYPE_MAT3: {
+					GLfloat mat[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+					glUniformMatrix3fv(location, 1, GL_FALSE, mat);
+
+				} break;
+
+				case ShaderLanguage::TYPE_MAT4: {
+					GLfloat mat[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+					glUniformMatrix4fv(location, 1, GL_FALSE, mat);
+
+				} break;
+
+				case ShaderLanguage::TYPE_SAMPLER2D: {
+				} break;
+
+					/*
+				case ShaderLanguage::TYPE_SAMPLEREXT: {
+				} break;
+*/
+
+				case ShaderLanguage::TYPE_ISAMPLER2D: {
+				} break;
+
+				case ShaderLanguage::TYPE_USAMPLER2D: {
+				} break;
+
+				case ShaderLanguage::TYPE_SAMPLERCUBE: {
+				} break;
+
+				case ShaderLanguage::TYPE_SAMPLER2DARRAY:
+				case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
+				case ShaderLanguage::TYPE_USAMPLER2DARRAY:
+				case ShaderLanguage::TYPE_SAMPLER3D:
+				case ShaderLanguage::TYPE_ISAMPLER3D:
+				case ShaderLanguage::TYPE_USAMPLER3D: {
+					// Not implemented in OpenGL
+				} break;
+
+				case ShaderLanguage::TYPE_VOID: {
+					// Nothing to do?
+				} break;
+				default: {
+					ERR_PRINT("ShaderNode type missing, bug?");
+				} break;
+			}
+		}
+	}
+}
+
+ShaderOLDGLES3::ShaderOLDGLES3() {
+	version = NULL;
+	last_custom_code = 1;
+	uniforms_dirty = true;
+}
+
+ShaderOLDGLES3::~ShaderOLDGLES3() {
+	finish();
+}
+
+#endif // GLES3_BACKEND_ENABLED

+ 277 - 0
drivers/gles3/shader_old_gles3.h

@@ -0,0 +1,277 @@
+/*************************************************************************/
+/*  shader_gles3.h                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 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.                */
+/*************************************************************************/
+
+#ifndef SHADER_OLD_OPENGL_H
+#define SHADER_OLD_OPENGL_H
+
+#include "drivers/gles3/rasterizer_platforms.h"
+#ifdef GLES3_BACKEND_ENABLED
+
+// This must come first to avoid windows.h mess
+#include "platform_config.h"
+#ifndef OPENGL_INCLUDE_H
+#include <GLES3/gl3.h>
+#else
+#include OPENGL_INCLUDE_H
+#endif
+
+#include "core/math/camera_matrix.h"
+#include "core/templates/hash_map.h"
+#include "core/templates/map.h"
+#include "core/templates/pair.h"
+#include "core/variant/variant.h"
+#include "servers/rendering/shader_language.h"
+
+#include <stdio.h>
+
+class RasterizerStorageGLES3;
+
+class ShaderOLDGLES3 {
+protected:
+	struct Enum {
+		uint64_t mask;
+		uint64_t shift;
+		const char *defines[16];
+	};
+
+	struct EnumValue {
+		uint64_t set_mask;
+		uint64_t clear_mask;
+	};
+
+	struct AttributePair {
+		const char *name;
+		int index;
+	};
+
+	struct UniformPair {
+		const char *name;
+		Variant::Type type_hint;
+	};
+
+	struct TexUnitPair {
+		const char *name;
+		int index;
+	};
+
+	bool uniforms_dirty;
+
+private:
+	bool valid = false;
+
+	//@TODO Optimize to a fixed set of shader pools and use a LRU
+	int uniform_count;
+	int texunit_pair_count;
+	int conditional_count;
+	int vertex_code_start;
+	int fragment_code_start;
+	int attribute_pair_count;
+
+	struct CustomCode {
+		String vertex;
+		String vertex_globals;
+		String fragment;
+		String fragment_globals;
+		String light;
+		uint32_t version;
+		Vector<StringName> texture_uniforms;
+		Vector<StringName> custom_uniforms;
+		Vector<CharString> custom_defines;
+		Set<uint32_t> versions;
+	};
+
+	struct Version {
+		GLuint id;
+		GLuint vert_id;
+		GLuint frag_id;
+		GLint *uniform_location;
+		Vector<GLint> texture_uniform_locations;
+		Map<StringName, GLint> custom_uniform_locations;
+		uint32_t code_version;
+		bool ok;
+		Version() {
+			id = 0;
+			vert_id = 0;
+			frag_id = 0;
+			uniform_location = NULL;
+			code_version = 0;
+			ok = false;
+		}
+	};
+
+	Version *version;
+
+	union VersionKey {
+		struct {
+			uint32_t version;
+			uint32_t code_version;
+		};
+		uint64_t key;
+		bool operator==(const VersionKey &p_key) const { return key == p_key.key; }
+		bool operator<(const VersionKey &p_key) const { return key < p_key.key; }
+	};
+
+	struct VersionKeyHash {
+		static _FORCE_INLINE_ uint32_t hash(const VersionKey &p_key) { return HashMapHasherDefault::hash(p_key.key); }
+	};
+
+	//this should use a way more cachefriendly version..
+	HashMap<VersionKey, Version, VersionKeyHash> version_map;
+
+	HashMap<uint32_t, CustomCode> custom_code_map;
+	uint32_t last_custom_code;
+
+	VersionKey conditional_version;
+	VersionKey new_conditional_version;
+
+	virtual String get_shader_name() const = 0;
+
+	const char **conditional_defines;
+	const char **uniform_names;
+	const AttributePair *attribute_pairs;
+	const TexUnitPair *texunit_pairs;
+	const char *vertex_code;
+	const char *fragment_code;
+	CharString fragment_code0;
+	CharString fragment_code1;
+	CharString fragment_code2;
+	CharString fragment_code3;
+
+	CharString vertex_code0;
+	CharString vertex_code1;
+	CharString vertex_code2;
+
+	Vector<CharString> custom_defines;
+
+	Version *get_current_version();
+
+	static ShaderOLDGLES3 *active;
+
+	int max_image_units;
+
+	Map<StringName, Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value>>> uniform_values;
+
+protected:
+	_FORCE_INLINE_ int _get_uniform(int p_which) const;
+	_FORCE_INLINE_ void _set_conditional(int p_which, bool p_value);
+
+	void setup(const char **p_conditional_defines,
+			int p_conditional_count,
+			const char **p_uniform_names,
+			int p_uniform_count,
+			const AttributePair *p_attribute_pairs,
+			int p_attribute_count,
+			const TexUnitPair *p_texunit_pairs,
+			int p_texunit_pair_count,
+			const char *p_vertex_code,
+			const char *p_fragment_code,
+			int p_vertex_code_start,
+			int p_fragment_code_start);
+
+	ShaderOLDGLES3();
+
+public:
+	enum {
+		CUSTOM_SHADER_DISABLED = 0
+	};
+
+	GLint get_uniform_location(const String &p_name) const;
+	GLint get_uniform_location(int p_index) const;
+
+	static _FORCE_INLINE_ ShaderOLDGLES3 *get_active() { return active; }
+	bool bind();
+	void unbind();
+
+	inline GLuint get_program() const { return version ? version->id : 0; }
+
+	void clear_caches();
+
+	uint32_t create_custom_shader();
+	void set_custom_shader_code(uint32_t p_code_id,
+			const String &p_vertex,
+			const String &p_vertex_globals,
+			const String &p_fragment,
+			const String &p_light,
+			const String &p_fragment_globals,
+			const Vector<StringName> &p_uniforms,
+			const Vector<StringName> &p_texture_uniforms,
+			const Vector<CharString> &p_custom_defines);
+
+	void set_custom_shader(uint32_t p_code_id);
+	void free_custom_shader(uint32_t p_code_id);
+
+	uint32_t get_version_key() const { return conditional_version.version; }
+
+	// this void* is actually a RasterizerStorageGLES3::Material, but C++ doesn't
+	// like forward declared nested classes.
+	void use_material(void *p_material);
+
+	_FORCE_INLINE_ uint32_t get_version() const { return new_conditional_version.version; }
+	_FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; }
+
+	virtual void init() = 0;
+	void finish();
+
+	void add_custom_define(const String &p_define) {
+		custom_defines.push_back(p_define.utf8());
+	}
+
+	void get_custom_defines(Vector<String> *p_defines) {
+		for (int i = 0; i < custom_defines.size(); i++) {
+			p_defines->push_back(custom_defines[i].get_data());
+		}
+	}
+
+	void remove_custom_define(const String &p_define) {
+		custom_defines.erase(p_define.utf8());
+	}
+
+	virtual ~ShaderOLDGLES3();
+};
+
+// called a lot, made inline
+
+int ShaderOLDGLES3::_get_uniform(int p_which) const {
+	ERR_FAIL_INDEX_V(p_which, uniform_count, -1);
+	ERR_FAIL_COND_V(!version, -1);
+	return version->uniform_location[p_which];
+}
+
+void ShaderOLDGLES3::_set_conditional(int p_which, bool p_value) {
+	ERR_FAIL_INDEX(p_which, conditional_count);
+	if (p_value)
+		new_conditional_version.version |= (1 << p_which);
+	else
+		new_conditional_version.version &= ~(1 << p_which);
+}
+
+#endif // GLES3_BACKEND_ENABLED
+
+#endif // SHADER_OPENGL_H

+ 11 - 8
drivers/gles3/shaders/SCsub

@@ -3,12 +3,15 @@
 Import("env")
 
 if "GLES3_GLSL" in env["BUILDERS"]:
-    env.GLES3_GLSL("copy.glsl")
     env.GLES3_GLSL("canvas.glsl")
-    env.GLES3_GLSL("canvas_shadow.glsl")
-    env.GLES3_GLSL("scene.glsl")
-    env.GLES3_GLSL("cubemap_filter.glsl")
-    env.GLES3_GLSL("cube_to_dp.glsl")
-    env.GLES3_GLSL("effect_blur.glsl")
-    env.GLES3_GLSL("tonemap.glsl")
-    env.GLES3_GLSL("lens_distorted.glsl")
+
+if "GLES3_OLD_GLSL" in env["BUILDERS"]:
+    env.GLES3_OLD_GLSL("copy.glsl")
+    env.GLES3_OLD_GLSL("canvas_old.glsl")
+    env.GLES3_OLD_GLSL("canvas_shadow.glsl")
+    env.GLES3_OLD_GLSL("scene.glsl")
+    env.GLES3_OLD_GLSL("cubemap_filter.glsl")
+    env.GLES3_OLD_GLSL("cube_to_dp.glsl")
+    env.GLES3_OLD_GLSL("effect_blur.glsl")
+    env.GLES3_OLD_GLSL("tonemap.glsl")
+    env.GLES3_OLD_GLSL("lens_distorted.glsl")

+ 573 - 482
drivers/gles3/shaders/canvas.glsl

@@ -1,665 +1,756 @@
-/* clang-format off */
-[vertex]
+#[modes]
 
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-precision highp float;
-precision highp int;
-#endif
+mode_quad =
+		mode_ninepatch = #define USE_NINEPATCH
+				mode_primitive = #define USE_PRIMITIVE
+						mode_attributes = #define USE_ATTRIBUTES
 
-uniform highp mat4 projection_matrix;
-/* clang-format on */
+#[specializations]
 
-uniform highp mat4 modelview_matrix;
-uniform highp mat4 extra_matrix;
-layout(location = 0) in highp vec2 vertex;
+								DISABLE_LIGHTING = false
 
-#ifdef USE_ATTRIB_LIGHT_ANGLE
-// shared with tangent, not used in canvas shader
-layout(location = 2) in highp float light_angle;
-#endif
+#[vertex]
 
+#version 450
+
+#VERSION_DEFINES
+
+#ifdef USE_ATTRIBUTES
+		layout(location = 0) in vec2 vertex_attrib;
 layout(location = 3) in vec4 color_attrib;
 layout(location = 4) in vec2 uv_attrib;
 
-#ifdef USE_ATTRIB_MODULATE
-layout(location = 5) in highp vec4 modulate_attrib;
-#endif
+layout(location = 10) in uvec4 bone_attrib;
+layout(location = 11) in vec4 weight_attrib;
 
-#ifdef USE_ATTRIB_LARGE_VERTEX
-// shared with skeleton attributes, not used in batched shader
-layout(location = 6) in highp vec2 translate_attrib;
-layout(location = 7) in highp vec4 basis_attrib;
 #endif
 
-#ifdef USE_SKELETON
-layout(location = 6) in highp vec4 bone_indices;
-layout(location = 7) in highp vec4 bone_weights;
-#endif
+#include "canvas_uniforms_inc.glsl"
 
-#ifdef USE_INSTANCING
+uniform sampler2D transforms_texture; //texunit:-1
 
-layout(location = 8) in highp vec4 instance_xform0;
-layout(location = 9) in highp vec4 instance_xform1;
-layout(location = 10) in highp vec4 instance_xform2;
-layout(location = 11) in highp vec4 instance_color;
+out vec2 uv_interp;
+out vec4 color_interp;
+out vec2 vertex_interp;
 
-#ifdef USE_INSTANCE_CUSTOM
-layout(location = 12) in highp vec4 instance_custom_data;
-#endif
+#ifdef USE_NINEPATCH
 
-#endif
+out vec2 pixel_size_interp;
 
-#ifdef USE_SKELETON
-uniform highp sampler2D skeleton_texture; // texunit:-3
-uniform highp ivec2 skeleton_texture_size;
-uniform highp mat4 skeleton_transform;
-uniform highp mat4 skeleton_transform_inverse;
 #endif
 
-out vec2 uv_interp;
-out vec4 color_interp;
+#ifdef MATERIAL_UNIFORMS_USED
+layout(std140) uniform MaterialUniforms{
+//ubo:4
 
-#ifdef USE_ATTRIB_MODULATE
-// modulate doesn't need interpolating but we need to send it to the fragment shader
-flat out vec4 modulate_interp;
-#endif
+#MATERIAL_UNIFORMS
 
-#ifdef MODULATE_USED
-uniform vec4 final_modulate;
+};
 #endif
 
-uniform highp vec2 color_texpixel_size;
+#GLOBALS
 
-#ifdef USE_TEXTURE_RECT
+void main() {
+	vec4 instance_custom = vec4(0.0);
+#ifdef USE_PRIMITIVE
 
-uniform vec4 dst_rect;
-uniform vec4 src_rect;
+	//weird bug,
+	//this works
+	vec2 vertex;
+	vec2 uv;
+	vec4 color;
+
+	if (gl_VertexIndex == 0) {
+		vertex = draw_data.points[0];
+		uv = draw_data.uvs[0];
+		color = vec4(unpackHalf2x16(draw_data.colors[0]), unpackHalf2x16(draw_data.colors[1]));
+	} else if (gl_VertexIndex == 1) {
+		vertex = draw_data.points[1];
+		uv = draw_data.uvs[1];
+		color = vec4(unpackHalf2x16(draw_data.colors[2]), unpackHalf2x16(draw_data.colors[3]));
+	} else {
+		vertex = draw_data.points[2];
+		uv = draw_data.uvs[2];
+		color = vec4(unpackHalf2x16(draw_data.colors[4]), unpackHalf2x16(draw_data.colors[5]));
+	}
+	uvec4 bones = uvec4(0, 0, 0, 0);
+	vec4 bone_weights = vec4(0.0);
 
-#endif
+#elif defined(USE_ATTRIBUTES)
 
-uniform highp float time;
-
-#ifdef USE_LIGHTING
-
-// light matrices
-uniform highp mat4 light_matrix;
-uniform highp mat4 light_matrix_inverse;
-uniform highp mat4 light_local_matrix;
-uniform highp mat4 shadow_matrix;
-uniform highp vec4 light_color;
-uniform highp vec4 light_shadow_color;
-uniform highp vec2 light_pos;
-uniform highp float shadowpixel_size;
-uniform highp float shadow_gradient;
-uniform highp float light_height;
-uniform highp float light_outside_alpha;
-uniform highp float shadow_distance_mult;
-
-out vec4 light_uv_interp;
-out vec2 transformed_light_uv;
-out vec4 local_rot;
-
-#ifdef USE_SHADOWS
-out highp vec2 pos;
-#endif
+	vec2 vertex = vertex_attrib;
+	vec4 color = color_attrib * draw_data.modulation;
+	vec2 uv = uv_attrib;
 
-const bool at_light_pass = true;
+	uvec4 bones = bone_attrib;
+	vec4 bone_weights = weight_attrib;
 #else
-const bool at_light_pass = false;
-#endif
-
-/* clang-format off */
-
-VERTEX_SHADER_GLOBALS
 
-/* clang-format on */
+	vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+	vec2 vertex_base = vertex_base_arr[gl_VertexIndex];
 
-vec2 select(vec2 a, vec2 b, bvec2 c) {
-	vec2 ret;
+	vec2 uv = draw_data.src_rect.xy + abs(draw_data.src_rect.zw) * ((draw_data.flags & FLAGS_TRANSPOSE_RECT) != 0 ? vertex_base.yx : vertex_base.xy);
+	vec4 color = draw_data.modulation;
+	vec2 vertex = draw_data.dst_rect.xy + abs(draw_data.dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data.src_rect.zw, vec2(0.0, 0.0)));
+	uvec4 bones = uvec4(0, 0, 0, 0);
 
-	ret.x = c.x ? b.x : a.x;
-	ret.y = c.y ? b.y : a.y;
-
-	return ret;
-}
+#endif
 
-void main() {
-	vec4 color = color_attrib;
-	vec2 uv;
+	mat4 world_matrix = mat4(vec4(draw_data.world_x, 0.0, 0.0), vec4(draw_data.world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data.world_ofs, 0.0, 1.0));
 
-#ifdef USE_INSTANCING
-	mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
-	color *= instance_color;
+#define FLAGS_INSTANCING_MASK 0x7F
+#define FLAGS_INSTANCING_HAS_COLORS (1 << 7)
+#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 8)
 
-#ifdef USE_INSTANCE_CUSTOM
-	vec4 instance_custom = instance_custom_data;
-#else
-	vec4 instance_custom = vec4(0.0);
-#endif
+	uint instancing = draw_data.flags & FLAGS_INSTANCING_MASK;
 
-#else
-	mat4 extra_matrix_instance = extra_matrix;
-	vec4 instance_custom = vec4(0.0);
-#endif
+#ifdef USE_ATTRIBUTES
+	if (instancing > 1) {
+		// trails
 
-#ifdef USE_TEXTURE_RECT
+		uint stride = 2 + 1 + 1; //particles always uses this format
 
-	if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z
-		uv = src_rect.xy + abs(src_rect.zw) * vertex.yx;
-	} else {
-		uv = src_rect.xy + abs(src_rect.zw) * vertex;
-	}
+		uint trail_size = instancing;
 
-	vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0);
+		uint offset = trail_size * stride * gl_InstanceIndex;
 
-	// This is what is done in the GLES 3 bindings and should
-	// take care of flipped rects.
-	//
-	// But it doesn't.
-	// I don't know why, will need to investigate further.
+		vec4 pcolor;
+		vec2 new_vertex;
+		{
+			uint boffset = offset + bone_attrib.x * stride;
+			new_vertex = (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.x;
+			pcolor = transforms.data[boffset + 2] * weight_attrib.x;
+		}
+		if (weight_attrib.y > 0.001) {
+			uint boffset = offset + bone_attrib.y * stride;
+			new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.y;
+			pcolor += transforms.data[boffset + 2] * weight_attrib.y;
+		}
+		if (weight_attrib.z > 0.001) {
+			uint boffset = offset + bone_attrib.z * stride;
+			new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.z;
+			pcolor += transforms.data[boffset + 2] * weight_attrib.z;
+		}
+		if (weight_attrib.w > 0.001) {
+			uint boffset = offset + bone_attrib.w * stride;
+			new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.w;
+			pcolor += transforms.data[boffset + 2] * weight_attrib.w;
+		}
 
-	outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0)));
+		instance_custom = transforms.data[offset + 3];
 
-	// outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex;
-#else
-	vec4 outvec = vec4(vertex.xy, 0.0, 1.0);
+		vertex = new_vertex;
+		color *= pcolor;
+	} else
+#endif // USE_ATTRIBUTES
+	{
+		if (instancing == 1) {
+			uint stride = 2;
+			{
+				if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
+					stride += 1;
+				}
+				if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+					stride += 1;
+				}
+			}
+
+			uint offset = stride * gl_InstanceIndex;
+
+			mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
+			offset += 2;
+
+			if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
+				color *= transforms.data[offset];
+				offset += 1;
+			}
+
+			if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+				instance_custom = transforms.data[offset];
+			}
+
+			matrix = transpose(matrix);
+			world_matrix = world_matrix * matrix;
+		}
+	}
 
-	uv = uv_attrib;
+#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
+	if (bool(draw_data.flags & FLAGS_USING_PARTICLES)) {
+		//scale by texture size
+		vertex /= draw_data.color_texture_pixel_size;
+	}
 #endif
 
+#ifdef USE_POINT_SIZE
 	float point_size = 1.0;
-
+#endif
 	{
-		vec2 src_vtx = outvec.xy;
-		/* clang-format off */
-
-VERTEX_SHADER_CODE
-
-		/* clang-format on */
+#CODE : VERTEX
 	}
 
-	gl_PointSize = point_size;
+#ifdef USE_NINEPATCH
+	pixel_size_interp = abs(draw_data.dst_rect.zw) * vertex_base;
+#endif
 
-#ifdef USE_ATTRIB_MODULATE
-	// modulate doesn't need interpolating but we need to send it to the fragment shader
-	modulate_interp = modulate_attrib;
+#if !defined(SKIP_TRANSFORM_USED)
+	vertex = (world_matrix * vec4(vertex, 0.0, 1.0)).xy;
 #endif
 
-#ifdef USE_ATTRIB_LARGE_VERTEX
-	// transform is in attributes
-	vec2 temp;
+	color_interp = color;
 
-	temp = outvec.xy;
-	temp.x = (outvec.x * basis_attrib.x) + (outvec.y * basis_attrib.z);
-	temp.y = (outvec.x * basis_attrib.y) + (outvec.y * basis_attrib.w);
+	if (canvas_data.use_pixel_snap) {
+		vertex = floor(vertex + 0.5);
+		// precision issue on some hardware creates artifacts within texture
+		// offset uv by a small amount to avoid
+		uv += 1e-5;
+	}
 
-	temp += translate_attrib;
-	outvec.xy = temp;
+#ifdef USE_ATTRIBUTES
+#if 0
+	if (bool(draw_data.flags & FLAGS_USE_SKELETON) && bone_weights != vec4(0.0)) { //must be a valid bone
+		//skeleton transform
+		ivec4 bone_indicesi = ivec4(bone_indices);
 
-#else
+		uvec2 tex_ofs = bone_indicesi.x * 2;
 
-	// transform is in uniforms
-#if !defined(SKIP_TRANSFORM_USED)
-	outvec = extra_matrix_instance * outvec;
-	outvec = modelview_matrix * outvec;
-#endif
+		mat2x4 m;
+		m = mat2x4(
+					texelFetch(skeleton_buffer, tex_ofs + 0),
+					texelFetch(skeleton_buffer, tex_ofs + 1)) *
+			bone_weights.x;
 
-#endif // not large integer
+		tex_ofs = bone_indicesi.y * 2;
 
-	color_interp = color;
+		m += mat2x4(
+					 texelFetch(skeleton_buffer, tex_ofs + 0),
+					 texelFetch(skeleton_buffer, tex_ofs + 1)) *
+			 bone_weights.y;
 
-#ifdef USE_PIXEL_SNAP
-	outvec.xy = floor(outvec + 0.5).xy;
-	// precision issue on some hardware creates artifacts within texture
-	// offset uv by a small amount to avoid
-	uv += 1e-5;
-#endif
+		tex_ofs = bone_indicesi.z * 2;
 
-#ifdef USE_SKELETON
+		m += mat2x4(
+					 texelFetch(skeleton_buffer, tex_ofs + 0),
+					 texelFetch(skeleton_buffer, tex_ofs + 1)) *
+			 bone_weights.z;
 
-	// look up transform from the "pose texture"
-	if (bone_weights != vec4(0.0)) {
-		highp mat4 bone_transform = mat4(0.0);
+		tex_ofs = bone_indicesi.w * 2;
 
-		for (int i = 0; i < 4; i++) {
-			ivec2 tex_ofs = ivec2(int(bone_indices[i]) * 2, 0);
+		m += mat2x4(
+					 texelFetch(skeleton_buffer, tex_ofs + 0),
+					 texelFetch(skeleton_buffer, tex_ofs + 1)) *
+			 bone_weights.w;
 
-			highp mat4 b = mat4(
-					texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(0, 0)),
-					texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(1, 0)),
-					vec4(0.0, 0.0, 1.0, 0.0),
-					vec4(0.0, 0.0, 0.0, 1.0));
+		mat4 bone_matrix = skeleton_data.skeleton_transform * transpose(mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))) * skeleton_data.skeleton_transform_inverse;
 
-			bone_transform += b * bone_weights[i];
-		}
+		//outvec = bone_matrix * outvec;
+	}
+#endif
+#endif
 
-		mat4 bone_matrix = skeleton_transform * transpose(bone_transform) * skeleton_transform_inverse;
+	vertex = (canvas_data.canvas_transform * vec4(vertex, 0.0, 1.0)).xy;
 
-		outvec = bone_matrix * outvec;
-	}
+	vertex_interp = vertex;
+	uv_interp = uv;
 
+	gl_Position = canvas_data.screen_transform * vec4(vertex, 0.0, 1.0);
+
+#ifdef USE_POINT_SIZE
+	gl_PointSize = point_size;
 #endif
+}
 
-	uv_interp = uv;
-	gl_Position = projection_matrix * outvec;
+#[fragment]
 
-#ifdef USE_LIGHTING
+#version 450
 
-	light_uv_interp.xy = (light_matrix * outvec).xy;
-	light_uv_interp.zw = (light_local_matrix * outvec).xy;
+#VERSION_DEFINES
 
-	transformed_light_uv = (mat3(light_matrix_inverse) * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping
+#include "canvas_uniforms_inc.glsl"
 
-#ifdef USE_SHADOWS
-	pos = outvec.xy;
-#endif
+uniform sampler2D atlas_texture; //texunit:-2
+uniform sampler2D shadow_atlas_texture; //texunit:-3
+uniform sampler2D screen_texture; //texunit:-4
+uniform sampler2D sdf_texture; //texunit:-5
+uniform sampler2D normal_texture; //texunit:-6
+uniform sampler2D specular_texture; //texunit:-7
 
-#ifdef USE_ATTRIB_LIGHT_ANGLE
-	// we add a fixed offset because we are using the sign later,
-	// and don't want floating point error around 0.0
-	float la = abs(light_angle) - 1.0;
-
-	// vector light angle
-	vec4 vla;
-	vla.xy = vec2(cos(la), sin(la));
-	vla.zw = vec2(-vla.y, vla.x);
-
-	// vertical flip encoded in the sign
-	vla.zw *= sign(light_angle);
-
-	// apply the transform matrix.
-	// The rotate will be encoded in the transform matrix for single rects,
-	// and just the flips in the light angle.
-	// For batching we will encode the rotation and the flips
-	// in the light angle, and can use the same shader.
-	local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.xy, 0.0, 0.0))).xy);
-	local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.zw, 0.0, 0.0))).xy);
-#else
-	local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy);
-	local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy);
-#ifdef USE_TEXTURE_RECT
-	local_rot.xy *= sign(src_rect.z);
-	local_rot.zw *= sign(src_rect.w);
-#endif
-#endif // not using light angle
+uniform sampler2D color_texture; //texunit:0
 
-#endif
-}
+in vec2 uv_interp;
+in vec4 color_interp;
+in vec2 vertex_interp;
 
-/* clang-format off */
-[fragment]
+#ifdef USE_NINEPATCH
+
+in vec2 pixel_size_interp;
 
-#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
 
-uniform sampler2D color_texture; // texunit:-1
-/* clang-format on */
-uniform highp vec2 color_texpixel_size;
-uniform mediump sampler2D normal_texture; // texunit:-2
+layout(location = 0) out vec4 frag_color;
+
+#ifdef MATERIAL_UNIFORMS_USED
+uniform MaterialUniforms{
+//ubo:4
 
-in mediump vec2 uv_interp;
-in mediump vec4 color_interp;
+#MATERIAL_UNIFORMS
 
-#ifdef USE_ATTRIB_MODULATE
-in mediump vec4 modulate_interp;
+};
 #endif
 
-uniform highp float time;
+vec2 screen_uv_to_sdf(vec2 p_uv) {
+	return canvas_data.screen_to_sdf * p_uv;
+}
 
-uniform vec4 final_modulate;
+float texture_sdf(vec2 p_sdf) {
+	vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
+	float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r;
+	d *= SDF_MAX_LENGTH;
+	return d * canvas_data.tex_to_sdf;
+}
 
-#ifdef SCREEN_TEXTURE_USED
+vec2 texture_sdf_normal(vec2 p_sdf) {
+	vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
 
-uniform sampler2D screen_texture; // texunit:-4
+	const float EPSILON = 0.001;
+	return normalize(vec2(
+			texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(EPSILON, 0.0)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(EPSILON, 0.0)).r,
+			texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(0.0, EPSILON)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(0.0, EPSILON)).r));
+}
 
-#endif
+vec2 sdf_to_screen_uv(vec2 p_sdf) {
+	return p_sdf * canvas_data.sdf_to_screen;
+}
 
-#ifdef SCREEN_UV_USED
+#GLOBALS
 
-uniform vec2 screen_pixel_size;
+#ifdef LIGHT_CODE_USED
 
-#endif
+vec4 light_compute(
+		vec3 light_vertex,
+		vec3 light_position,
+		vec3 normal,
+		vec4 light_color,
+		float light_energy,
+		vec4 specular_shininess,
+		inout vec4 shadow_modulate,
+		vec2 screen_uv,
+		vec2 uv,
+		vec4 color, bool is_directional) {
+	vec4 light = vec4(0.0);
 
-#ifdef USE_LIGHTING
+#CODE : LIGHT
 
-uniform highp mat4 light_matrix;
-uniform highp mat4 light_local_matrix;
-uniform highp mat4 shadow_matrix;
-uniform highp vec4 light_color;
-uniform highp vec4 light_shadow_color;
-uniform highp vec2 light_pos;
-uniform highp float shadowpixel_size;
-uniform highp float shadow_gradient;
-uniform highp float light_height;
-uniform highp float light_outside_alpha;
-uniform highp float shadow_distance_mult;
+	return light;
+}
 
-uniform lowp sampler2D light_texture; // texunit:-6
-in vec4 light_uv_interp;
-in vec2 transformed_light_uv;
+#endif
 
-in vec4 local_rot;
+#ifdef USE_NINEPATCH
 
-#ifdef USE_SHADOWS
+float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) {
+	float tex_size = 1.0 / tex_pixel_size;
 
-uniform highp sampler2D shadow_texture; // texunit:-5
-in highp vec2 pos;
+	if (pixel < margin_begin) {
+		return pixel * tex_pixel_size;
+	} else if (pixel >= draw_size - margin_end) {
+		return (tex_size - (draw_size - pixel)) * tex_pixel_size;
+	} else {
+		if (!bool(draw_data.flags & FLAGS_NINEPACH_DRAW_CENTER)) {
+			draw_center--;
+		}
 
-#endif
+		// np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum.
+		if (np_repeat == 0) { // Stretch.
+			// Convert to ratio.
+			float ratio = (pixel - margin_begin) / (draw_size - margin_begin - margin_end);
+			// Scale to source texture.
+			return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size;
+		} else if (np_repeat == 1) { // Tile.
+			// Convert to offset.
+			float ofs = mod((pixel - margin_begin), tex_size - margin_begin - margin_end);
+			// Scale to source texture.
+			return (margin_begin + ofs) * tex_pixel_size;
+		} else if (np_repeat == 2) { // Tile Fit.
+			// Calculate scale.
+			float src_area = draw_size - margin_begin - margin_end;
+			float dst_area = tex_size - margin_begin - margin_end;
+			float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5));
+			// Convert to ratio.
+			float ratio = (pixel - margin_begin) / src_area;
+			ratio = mod(ratio * scale, 1.0);
+			// Scale to source texture.
+			return (margin_begin + ratio * dst_area) * tex_pixel_size;
+		} else { // Shouldn't happen, but silences compiler warning.
+			return 0.0;
+		}
+	}
+}
 
-const bool at_light_pass = true;
-#else
-const bool at_light_pass = false;
 #endif
 
-uniform bool use_default_normal;
+vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) {
+	float cNdotL = max(0.0, dot(normal, light_vec));
 
-layout(location = 0) out mediump vec4 frag_color;
+	if (specular_shininess_used) {
+		//blinn
+		vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough
+		vec3 half_vec = normalize(view + light_vec);
 
-/* clang-format off */
+		float cNdotV = max(dot(normal, view), 0.0);
+		float cNdotH = max(dot(normal, half_vec), 0.0);
+		float cVdotH = max(dot(view, half_vec), 0.0);
+		float cLdotH = max(dot(light_vec, half_vec), 0.0);
+		float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25;
+		float blinn = pow(cNdotH, shininess);
+		blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
+		float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
 
-FRAGMENT_SHADER_GLOBALS
+		return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL;
+	} else {
+		return light_color * base_color * cNdotL;
+	}
+}
 
-/* clang-format on */
+//float distance = length(shadow_pos);
+vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
+#ifdef LIGHT_CODE_USED
+		,
+		vec3 shadow_modulate
+#endif
+) {
+	float shadow;
+	uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
+
+	if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
+		shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
+	} else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
+		vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
+		shadow = 0.0;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
+		shadow /= 5.0;
+	} else { //PCF13
+		vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
+		shadow = 0.0;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x;
+		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x;
+		shadow /= 13.0;
+	}
 
-void light_compute(
-		inout vec4 light,
-		inout vec2 light_vec,
-		inout float light_height,
-		inout vec4 light_color,
-		vec2 light_uv,
-		inout vec4 shadow_color,
-		inout vec2 shadow_vec,
-		vec3 normal,
-		vec2 uv,
-#if defined(SCREEN_UV_USED)
-		vec2 screen_uv,
+	vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color);
+#ifdef LIGHT_CODE_USED
+	shadow_color.rgb *= shadow_modulate;
 #endif
-		vec4 color) {
 
-#if defined(USE_LIGHT_SHADER_CODE)
+	shadow_color.a *= light_color.a; //respect light alpha
 
-	/* clang-format off */
+	return mix(light_color, shadow_color, shadow);
+}
 
-LIGHT_SHADER_CODE
+void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
+	uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
+
+	switch (blend_mode) {
+		case LIGHT_FLAGS_BLEND_MODE_ADD: {
+			color.rgb += light_color.rgb * light_color.a;
+		} break;
+		case LIGHT_FLAGS_BLEND_MODE_SUB: {
+			color.rgb -= light_color.rgb * light_color.a;
+		} break;
+		case LIGHT_FLAGS_BLEND_MODE_MIX: {
+			color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
+		} break;
+	}
+}
 
-	/* clang-format on */
+float msdf_median(float r, float g, float b, float a) {
+	return min(max(min(r, g), min(max(r, g), b)), a);
+}
 
-#endif
+vec2 msdf_map(vec2 value, vec2 in_min, vec2 in_max, vec2 out_min, vec2 out_max) {
+	return out_min + (out_max - out_min) * (value - in_min) / (in_max - in_min);
 }
 
 void main() {
 	vec4 color = color_interp;
 	vec2 uv = uv_interp;
-#ifdef USE_FORCE_REPEAT
-	//needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that don't support it
-	uv = mod(uv, vec2(1.0, 1.0));
+	vec2 vertex = vertex_interp;
+
+#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
+
+#ifdef USE_NINEPATCH
+
+	int draw_center = 2;
+	uv = vec2(
+			map_ninepatch_axis(pixel_size_interp.x, abs(draw_data.dst_rect.z), draw_data.color_texture_pixel_size.x, draw_data.ninepatch_margins.x, draw_data.ninepatch_margins.z, int(draw_data.flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
+			map_ninepatch_axis(pixel_size_interp.y, abs(draw_data.dst_rect.w), draw_data.color_texture_pixel_size.y, draw_data.ninepatch_margins.y, draw_data.ninepatch_margins.w, int(draw_data.flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
+
+	if (draw_center == 0) {
+		color.a = 0.0;
+	}
+
+	uv = uv * draw_data.src_rect.zw + draw_data.src_rect.xy; //apply region if needed
+
 #endif
+	if (bool(draw_data.flags & FLAGS_CLIP_RECT_UV)) {
+		uv = clamp(uv, draw_data.src_rect.xy, draw_data.src_rect.xy + abs(draw_data.src_rect.zw));
+	}
 
-#if !defined(COLOR_USED)
-	//default behavior, texture by color
-	color *= texture(color_texture, uv);
 #endif
 
-#ifdef SCREEN_UV_USED
-	vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
+#ifndef USE_PRIMITIVE
+	if (bool(draw_data.flags & FLAGS_USE_MSDF)) {
+		float px_range = draw_data.ninepatch_margins.x;
+		float outline_thickness = draw_data.ninepatch_margins.y;
+		//float reserved1 = draw_data.ninepatch_margins.z;
+		//float reserved2 = draw_data.ninepatch_margins.w;
+
+		vec4 msdf_sample = texture(sampler2D(color_texture, texture_sampler), uv);
+		vec2 msdf_size = vec2(textureSize(sampler2D(color_texture, texture_sampler), 0));
+		vec2 dest_size = vec2(1.0) / fwidth(uv);
+		float px_size = max(0.5 * dot((vec2(px_range) / msdf_size), dest_size), 1.0);
+		float d = msdf_median(msdf_sample.r, msdf_sample.g, msdf_sample.b, msdf_sample.a) - 0.5;
+
+		if (outline_thickness > 0) {
+			float cr = clamp(outline_thickness, 0.0, px_range / 2) / px_range;
+			float a = clamp((d + cr) * px_size, 0.0, 1.0);
+			color.a = a * color.a;
+		} else {
+			float a = clamp(d * px_size + 0.5, 0.0, 1.0);
+			color.a = a * color.a;
+		}
+
+	} else {
+#else
+	{
 #endif
+		color *= texture(sampler2D(color_texture, texture_sampler), uv);
+	}
+
+	uint light_count = (draw_data.flags >> FLAGS_LIGHT_COUNT_SHIFT) & 0xF; //max 16 lights
+	bool using_light = light_count > 0 || canvas_data.directional_light_count > 0;
 
 	vec3 normal;
 
 #if defined(NORMAL_USED)
-
 	bool normal_used = true;
 #else
 	bool normal_used = false;
 #endif
 
-	if (use_default_normal) {
-		normal.xy = texture(normal_texture, uv).xy * 2.0 - 1.0;
+	if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
+		normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
 		normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
 		normal_used = true;
 	} else {
 		normal = vec3(0.0, 0.0, 1.0);
 	}
 
-	{
-		float normal_depth = 1.0;
-
-#if defined(NORMALMAP_USED)
-		vec3 normal_map = vec3(0.0, 0.0, 1.0);
-		normal_used = true;
-#endif
-
-		/* clang-format off */
-
-FRAGMENT_SHADER_CODE
-
-		/* clang-format on */
+	vec4 specular_shininess;
 
-#if defined(NORMALMAP_USED)
-		normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth);
-#endif
-	}
+#if defined(SPECULAR_SHININESS_USED)
 
-#ifdef USE_ATTRIB_MODULATE
-	color *= modulate_interp;
+	bool specular_shininess_used = true;
 #else
-#if !defined(MODULATE_USED)
-	color *= final_modulate;
-#endif
+	bool specular_shininess_used = false;
 #endif
 
-#ifdef USE_LIGHTING
-
-	vec2 light_vec = transformed_light_uv;
-	vec2 shadow_vec = transformed_light_uv;
-
-	if (normal_used) {
-		normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy;
+	if (specular_shininess_used || (using_light && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
+		specular_shininess = texture(sampler2D(specular_texture, texture_sampler), uv);
+		specular_shininess *= unpackUnorm4x8(draw_data.specular_shininess);
+		specular_shininess_used = true;
+	} else {
+		specular_shininess = vec4(1.0);
 	}
 
-	float att = 1.0;
-
-	vec2 light_uv = light_uv_interp.xy;
-	vec4 light = texture(light_texture, light_uv);
-
-	if (any(lessThan(light_uv_interp.xy, vec2(0.0, 0.0))) || any(greaterThanEqual(light_uv_interp.xy, vec2(1.0, 1.0)))) {
-		color.a *= light_outside_alpha; //invisible
-
-	} else {
-		float real_light_height = light_height;
-		vec4 real_light_color = light_color;
-		vec4 real_light_shadow_color = light_shadow_color;
-
-#if defined(USE_LIGHT_SHADER_CODE)
-		//light is written by the light shader
-		light_compute(
-				light,
-				light_vec,
-				real_light_height,
-				real_light_color,
-				light_uv,
-				real_light_shadow_color,
-				shadow_vec,
-				normal,
-				uv,
 #if defined(SCREEN_UV_USED)
-				screen_uv,
-#endif
-				color);
+	vec2 screen_uv = gl_FragCoord.xy * canvas_data.screen_pixel_size;
+#else
+	vec2 screen_uv = vec2(0.0);
 #endif
 
-		light *= real_light_color;
-
-		if (normal_used) {
-			vec3 light_normal = normalize(vec3(light_vec, -real_light_height));
-			light *= max(dot(-light_normal, normal), 0.0);
-		}
-
-		color *= light;
+	vec3 light_vertex = vec3(vertex, 0.0);
+	vec2 shadow_vertex = vertex;
 
-#ifdef USE_SHADOWS
+	{
+		float normal_map_depth = 1.0;
 
-#ifdef SHADOW_VEC_USED
-		mat3 inverse_light_matrix = mat3(light_matrix);
-		inverse_light_matrix[0] = normalize(inverse_light_matrix[0]);
-		inverse_light_matrix[1] = normalize(inverse_light_matrix[1]);
-		inverse_light_matrix[2] = normalize(inverse_light_matrix[2]);
-		shadow_vec = (inverse_light_matrix * vec3(shadow_vec, 0.0)).xy;
-#else
-		shadow_vec = light_uv_interp.zw;
+#if defined(NORMAL_MAP_USED)
+		vec3 normal_map = vec3(0.0, 0.0, 1.0);
+		normal_used = true;
 #endif
 
-		float angle_to_light = -atan(shadow_vec.x, shadow_vec.y);
-		float PI = 3.14159265358979323846264;
-		/*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays
-		float ang*/
-
-		float su, sz;
-
-		float abs_angle = abs(angle_to_light);
-		vec2 point;
-		float sh;
-		if (abs_angle < 45.0 * PI / 180.0) {
-			point = shadow_vec;
-			sh = 0.0 + (1.0 / 8.0);
-		} else if (abs_angle > 135.0 * PI / 180.0) {
-			point = -shadow_vec;
-			sh = 0.5 + (1.0 / 8.0);
-		} else if (angle_to_light > 0.0) {
-			point = vec2(shadow_vec.y, -shadow_vec.x);
-			sh = 0.25 + (1.0 / 8.0);
-		} else {
-			point = vec2(-shadow_vec.y, shadow_vec.x);
-			sh = 0.75 + (1.0 / 8.0);
-		}
+#CODE : FRAGMENT
 
-		highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0);
-		s.xyz /= s.w;
-		su = s.x * 0.5 + 0.5;
-		sz = s.z * 0.5 + 0.5;
-		//sz=lightlength(light_vec);
+#if defined(NORMAL_MAP_USED)
+		normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_map_depth);
+#endif
+	}
 
-		highp float shadow_attenuation = 0.0;
+	if (normal_used) {
+		//convert by item transform
+		normal.xy = mat2(normalize(draw_data.world_x), normalize(draw_data.world_y)) * normal.xy;
+		//convert by canvas transform
+		normal = normalize((canvas_data.canvas_normal_transform * vec4(normal, 0.0)).xyz);
+	}
 
-#ifdef USE_RGBA_SHADOWS
-#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0))
+	vec3 base_color = color.rgb;
+	if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) {
+		color = vec4(0.0); //invisible by default due to using light mask
+	}
 
+#ifdef MODE_LIGHT_ONLY
+	color = vec4(0.0);
 #else
+	color *= canvas_data.canvas_modulation;
+#endif
 
-#define SHADOW_DEPTH(m_tex, m_uv) (texture((m_tex), (m_uv)).r)
+#if !defined(DISABLE_LIGHTING) && !defined(MODE_UNSHADED)
 
-#endif
+	for (uint i = 0; i < canvas_data.directional_light_count; i++) {
+		uint light_base = i;
 
-#ifdef SHADOW_USE_GRADIENT
+		vec2 direction = light_array.data[light_base].position;
+		vec4 light_color = light_array.data[light_base].color;
 
-		/* clang-format off */
-		/* GLSL es 100 doesn't support line continuation characters(backslashes) */
-#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); }
+#ifdef LIGHT_CODE_USED
 
+		vec4 shadow_modulate = vec4(1.0);
+		light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true);
 #else
 
-#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += step(sz, sd); }
-		/* clang-format on */
-
+		if (normal_used) {
+			vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array.data[light_base].height));
+			light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
+		}
 #endif
 
-#ifdef SHADOW_FILTER_NEAREST
+		if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+			vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
 
-		SHADOW_TEST(su);
+			vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0);
 
+			light_color = light_shadow_compute(light_base, light_color, shadow_uv
+#ifdef LIGHT_CODE_USED
+					,
+					shadow_modulate.rgb
 #endif
+			);
+		}
 
-#ifdef SHADOW_FILTER_PCF3
-
-		SHADOW_TEST(su + shadowpixel_size);
-		SHADOW_TEST(su);
-		SHADOW_TEST(su - shadowpixel_size);
-		shadow_attenuation /= 3.0;
-
-#endif
+		light_blend_compute(light_base, light_color, color.rgb);
+	}
 
-#ifdef SHADOW_FILTER_PCF5
+	// Positional Lights
 
-		SHADOW_TEST(su + shadowpixel_size * 2.0);
-		SHADOW_TEST(su + shadowpixel_size);
-		SHADOW_TEST(su);
-		SHADOW_TEST(su - shadowpixel_size);
-		SHADOW_TEST(su - shadowpixel_size * 2.0);
-		shadow_attenuation /= 5.0;
+	for (uint i = 0; i < MAX_LIGHTS_PER_ITEM; i++) {
+		if (i >= light_count) {
+			break;
+		}
+		uint light_base;
+		if (i < 8) {
+			if (i < 4) {
+				light_base = draw_data.lights[0];
+			} else {
+				light_base = draw_data.lights[1];
+			}
+		} else {
+			if (i < 12) {
+				light_base = draw_data.lights[2];
+			} else {
+				light_base = draw_data.lights[3];
+			}
+		}
+		light_base >>= (i & 3) * 8;
+		light_base &= 0xFF;
 
-#endif
+		vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_array.data[light_base].texture_matrix[0], light_array.data[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+		vec2 tex_uv_atlas = tex_uv * light_array.data[light_base].atlas_rect.zw + light_array.data[light_base].atlas_rect.xy;
+		vec4 light_color = textureLod(sampler2D(atlas_texture, texture_sampler), tex_uv_atlas, 0.0);
+		vec4 light_base_color = light_array.data[light_base].color;
 
-#ifdef SHADOW_FILTER_PCF7
+#ifdef LIGHT_CODE_USED
 
-		SHADOW_TEST(su + shadowpixel_size * 3.0);
-		SHADOW_TEST(su + shadowpixel_size * 2.0);
-		SHADOW_TEST(su + shadowpixel_size);
-		SHADOW_TEST(su);
-		SHADOW_TEST(su - shadowpixel_size);
-		SHADOW_TEST(su - shadowpixel_size * 2.0);
-		SHADOW_TEST(su - shadowpixel_size * 3.0);
-		shadow_attenuation /= 7.0;
+		vec4 shadow_modulate = vec4(1.0);
+		vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
 
-#endif
+		light_color.rgb *= light_base_color.rgb;
+		light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, false);
+#else
 
-#ifdef SHADOW_FILTER_PCF9
+		light_color.rgb *= light_base_color.rgb * light_base_color.a;
 
-		SHADOW_TEST(su + shadowpixel_size * 4.0);
-		SHADOW_TEST(su + shadowpixel_size * 3.0);
-		SHADOW_TEST(su + shadowpixel_size * 2.0);
-		SHADOW_TEST(su + shadowpixel_size);
-		SHADOW_TEST(su);
-		SHADOW_TEST(su - shadowpixel_size);
-		SHADOW_TEST(su - shadowpixel_size * 2.0);
-		SHADOW_TEST(su - shadowpixel_size * 3.0);
-		SHADOW_TEST(su - shadowpixel_size * 4.0);
-		shadow_attenuation /= 9.0;
+		if (normal_used) {
+			vec3 light_pos = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
+			vec3 pos = light_vertex;
+			vec3 light_vec = normalize(light_pos - pos);
+			float cNdotL = max(0.0, dot(normal, light_vec));
 
+			light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
+		}
 #endif
+		if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
+			//if outside the light texture, light color is zero
+			light_color.a = 0.0;
+		}
 
-#ifdef SHADOW_FILTER_PCF13
-
-		SHADOW_TEST(su + shadowpixel_size * 6.0);
-		SHADOW_TEST(su + shadowpixel_size * 5.0);
-		SHADOW_TEST(su + shadowpixel_size * 4.0);
-		SHADOW_TEST(su + shadowpixel_size * 3.0);
-		SHADOW_TEST(su + shadowpixel_size * 2.0);
-		SHADOW_TEST(su + shadowpixel_size);
-		SHADOW_TEST(su);
-		SHADOW_TEST(su - shadowpixel_size);
-		SHADOW_TEST(su - shadowpixel_size * 2.0);
-		SHADOW_TEST(su - shadowpixel_size * 3.0);
-		SHADOW_TEST(su - shadowpixel_size * 4.0);
-		SHADOW_TEST(su - shadowpixel_size * 5.0);
-		SHADOW_TEST(su - shadowpixel_size * 6.0);
-		shadow_attenuation /= 13.0;
-
-#endif
+		if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+			vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+
+			vec2 pos_norm = normalize(shadow_pos);
+			vec2 pos_abs = abs(pos_norm);
+			vec2 pos_box = pos_norm / max(pos_abs.x, pos_abs.y);
+			vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot?
+			float tex_ofs;
+			float distance;
+			if (pos_rot.y > 0) {
+				if (pos_rot.x > 0) {
+					tex_ofs = pos_box.y * 0.125 + 0.125;
+					distance = shadow_pos.x;
+				} else {
+					tex_ofs = pos_box.x * -0.125 + (0.25 + 0.125);
+					distance = shadow_pos.y;
+				}
+			} else {
+				if (pos_rot.x < 0) {
+					tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125);
+					distance = -shadow_pos.x;
+				} else {
+					tex_ofs = pos_box.x * 0.125 + (0.75 + 0.125);
+					distance = -shadow_pos.y;
+				}
+			}
+
+			distance *= light_array.data[light_base].shadow_zfar_inv;
+
+			//float distance = length(shadow_pos);
+			vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0);
+
+			light_color = light_shadow_compute(light_base, light_color, shadow_uv
+#ifdef LIGHT_CODE_USED
+					,
+					shadow_modulate.rgb
+#endif
+			);
+		}
 
-		//color *= shadow_attenuation;
-		color = mix(real_light_shadow_color, color, shadow_attenuation);
-//use shadows
-#endif
+		light_blend_compute(light_base, light_color, color.rgb);
 	}
-
-//use lighting
-#endif
+#endif // UNSHADED
 
 	frag_color = color;
 }

+ 665 - 0
drivers/gles3/shaders/canvas_old.glsl

@@ -0,0 +1,665 @@
+/* clang-format off */
+[vertex]
+
+#ifdef USE_GLES_OVER_GL
+#define lowp
+#define mediump
+#define highp
+#else
+precision highp float;
+precision highp int;
+#endif
+
+uniform highp mat4 projection_matrix;
+/* clang-format on */
+
+uniform highp mat4 modelview_matrix;
+uniform highp mat4 extra_matrix;
+layout(location = 0) in highp vec2 vertex;
+
+#ifdef USE_ATTRIB_LIGHT_ANGLE
+// shared with tangent, not used in canvas shader
+layout(location = 2) in highp float light_angle;
+#endif
+
+layout(location = 3) in vec4 color_attrib;
+layout(location = 4) in vec2 uv_attrib;
+
+#ifdef USE_ATTRIB_MODULATE
+layout(location = 5) in highp vec4 modulate_attrib;
+#endif
+
+#ifdef USE_ATTRIB_LARGE_VERTEX
+// shared with skeleton attributes, not used in batched shader
+layout(location = 6) in highp vec2 translate_attrib;
+layout(location = 7) in highp vec4 basis_attrib;
+#endif
+
+#ifdef USE_SKELETON
+layout(location = 6) in highp vec4 bone_indices;
+layout(location = 7) in highp vec4 bone_weights;
+#endif
+
+#ifdef USE_INSTANCING
+
+layout(location = 8) in highp vec4 instance_xform0;
+layout(location = 9) in highp vec4 instance_xform1;
+layout(location = 10) in highp vec4 instance_xform2;
+layout(location = 11) in highp vec4 instance_color;
+
+#ifdef USE_INSTANCE_CUSTOM
+layout(location = 12) in highp vec4 instance_custom_data;
+#endif
+
+#endif
+
+#ifdef USE_SKELETON
+uniform highp sampler2D skeleton_texture; // texunit:-3
+uniform highp ivec2 skeleton_texture_size;
+uniform highp mat4 skeleton_transform;
+uniform highp mat4 skeleton_transform_inverse;
+#endif
+
+out vec2 uv_interp;
+out vec4 color_interp;
+
+#ifdef USE_ATTRIB_MODULATE
+// modulate doesn't need interpolating but we need to send it to the fragment shader
+flat out vec4 modulate_interp;
+#endif
+
+#ifdef MODULATE_USED
+uniform vec4 final_modulate;
+#endif
+
+uniform highp vec2 color_texpixel_size;
+
+#ifdef USE_TEXTURE_RECT
+
+uniform vec4 dst_rect;
+uniform vec4 src_rect;
+
+#endif
+
+uniform highp float time;
+
+#ifdef USE_LIGHTING
+
+// light matrices
+uniform highp mat4 light_matrix;
+uniform highp mat4 light_matrix_inverse;
+uniform highp mat4 light_local_matrix;
+uniform highp mat4 shadow_matrix;
+uniform highp vec4 light_color;
+uniform highp vec4 light_shadow_color;
+uniform highp vec2 light_pos;
+uniform highp float shadowpixel_size;
+uniform highp float shadow_gradient;
+uniform highp float light_height;
+uniform highp float light_outside_alpha;
+uniform highp float shadow_distance_mult;
+
+out vec4 light_uv_interp;
+out vec2 transformed_light_uv;
+out vec4 local_rot;
+
+#ifdef USE_SHADOWS
+out highp vec2 pos;
+#endif
+
+const bool at_light_pass = true;
+#else
+const bool at_light_pass = false;
+#endif
+
+/* clang-format off */
+
+VERTEX_SHADER_GLOBALS
+
+/* clang-format on */
+
+vec2 select(vec2 a, vec2 b, bvec2 c) {
+	vec2 ret;
+
+	ret.x = c.x ? b.x : a.x;
+	ret.y = c.y ? b.y : a.y;
+
+	return ret;
+}
+
+void main() {
+	vec4 color = color_attrib;
+	vec2 uv;
+
+#ifdef USE_INSTANCING
+	mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
+	color *= instance_color;
+
+#ifdef USE_INSTANCE_CUSTOM
+	vec4 instance_custom = instance_custom_data;
+#else
+	vec4 instance_custom = vec4(0.0);
+#endif
+
+#else
+	mat4 extra_matrix_instance = extra_matrix;
+	vec4 instance_custom = vec4(0.0);
+#endif
+
+#ifdef USE_TEXTURE_RECT
+
+	if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z
+		uv = src_rect.xy + abs(src_rect.zw) * vertex.yx;
+	} else {
+		uv = src_rect.xy + abs(src_rect.zw) * vertex;
+	}
+
+	vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0);
+
+	// This is what is done in the GLES 3 bindings and should
+	// take care of flipped rects.
+	//
+	// But it doesn't.
+	// I don't know why, will need to investigate further.
+
+	outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0)));
+
+	// outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex;
+#else
+	vec4 outvec = vec4(vertex.xy, 0.0, 1.0);
+
+	uv = uv_attrib;
+#endif
+
+	float point_size = 1.0;
+
+	{
+		vec2 src_vtx = outvec.xy;
+		/* clang-format off */
+
+VERTEX_SHADER_CODE
+
+		/* clang-format on */
+	}
+
+	gl_PointSize = point_size;
+
+#ifdef USE_ATTRIB_MODULATE
+	// modulate doesn't need interpolating but we need to send it to the fragment shader
+	modulate_interp = modulate_attrib;
+#endif
+
+#ifdef USE_ATTRIB_LARGE_VERTEX
+	// transform is in attributes
+	vec2 temp;
+
+	temp = outvec.xy;
+	temp.x = (outvec.x * basis_attrib.x) + (outvec.y * basis_attrib.z);
+	temp.y = (outvec.x * basis_attrib.y) + (outvec.y * basis_attrib.w);
+
+	temp += translate_attrib;
+	outvec.xy = temp;
+
+#else
+
+	// transform is in uniforms
+#if !defined(SKIP_TRANSFORM_USED)
+	outvec = extra_matrix_instance * outvec;
+	outvec = modelview_matrix * outvec;
+#endif
+
+#endif // not large integer
+
+	color_interp = color;
+
+#ifdef USE_PIXEL_SNAP
+	outvec.xy = floor(outvec + 0.5).xy;
+	// precision issue on some hardware creates artifacts within texture
+	// offset uv by a small amount to avoid
+	uv += 1e-5;
+#endif
+
+#ifdef USE_SKELETON
+
+	// look up transform from the "pose texture"
+	if (bone_weights != vec4(0.0)) {
+		highp mat4 bone_transform = mat4(0.0);
+
+		for (int i = 0; i < 4; i++) {
+			ivec2 tex_ofs = ivec2(int(bone_indices[i]) * 2, 0);
+
+			highp mat4 b = mat4(
+					texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(0, 0)),
+					texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(1, 0)),
+					vec4(0.0, 0.0, 1.0, 0.0),
+					vec4(0.0, 0.0, 0.0, 1.0));
+
+			bone_transform += b * bone_weights[i];
+		}
+
+		mat4 bone_matrix = skeleton_transform * transpose(bone_transform) * skeleton_transform_inverse;
+
+		outvec = bone_matrix * outvec;
+	}
+
+#endif
+
+	uv_interp = uv;
+	gl_Position = projection_matrix * outvec;
+
+#ifdef USE_LIGHTING
+
+	light_uv_interp.xy = (light_matrix * outvec).xy;
+	light_uv_interp.zw = (light_local_matrix * outvec).xy;
+
+	transformed_light_uv = (mat3(light_matrix_inverse) * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping
+
+#ifdef USE_SHADOWS
+	pos = outvec.xy;
+#endif
+
+#ifdef USE_ATTRIB_LIGHT_ANGLE
+	// we add a fixed offset because we are using the sign later,
+	// and don't want floating point error around 0.0
+	float la = abs(light_angle) - 1.0;
+
+	// vector light angle
+	vec4 vla;
+	vla.xy = vec2(cos(la), sin(la));
+	vla.zw = vec2(-vla.y, vla.x);
+
+	// vertical flip encoded in the sign
+	vla.zw *= sign(light_angle);
+
+	// apply the transform matrix.
+	// The rotate will be encoded in the transform matrix for single rects,
+	// and just the flips in the light angle.
+	// For batching we will encode the rotation and the flips
+	// in the light angle, and can use the same shader.
+	local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.xy, 0.0, 0.0))).xy);
+	local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.zw, 0.0, 0.0))).xy);
+#else
+	local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy);
+	local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy);
+#ifdef USE_TEXTURE_RECT
+	local_rot.xy *= sign(src_rect.z);
+	local_rot.zw *= sign(src_rect.w);
+#endif
+#endif // not using light angle
+
+#endif
+}
+
+/* clang-format off */
+[fragment]
+
+#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
+
+uniform sampler2D color_texture; // texunit:-1
+/* clang-format on */
+uniform highp vec2 color_texpixel_size;
+uniform mediump sampler2D normal_texture; // texunit:-2
+
+in mediump vec2 uv_interp;
+in mediump vec4 color_interp;
+
+#ifdef USE_ATTRIB_MODULATE
+in mediump vec4 modulate_interp;
+#endif
+
+uniform highp float time;
+
+uniform vec4 final_modulate;
+
+#ifdef SCREEN_TEXTURE_USED
+
+uniform sampler2D screen_texture; // texunit:-4
+
+#endif
+
+#ifdef SCREEN_UV_USED
+
+uniform vec2 screen_pixel_size;
+
+#endif
+
+#ifdef USE_LIGHTING
+
+uniform highp mat4 light_matrix;
+uniform highp mat4 light_local_matrix;
+uniform highp mat4 shadow_matrix;
+uniform highp vec4 light_color;
+uniform highp vec4 light_shadow_color;
+uniform highp vec2 light_pos;
+uniform highp float shadowpixel_size;
+uniform highp float shadow_gradient;
+uniform highp float light_height;
+uniform highp float light_outside_alpha;
+uniform highp float shadow_distance_mult;
+
+uniform lowp sampler2D light_texture; // texunit:-6
+in vec4 light_uv_interp;
+in vec2 transformed_light_uv;
+
+in vec4 local_rot;
+
+#ifdef USE_SHADOWS
+
+uniform highp sampler2D shadow_texture; // texunit:-5
+in highp vec2 pos;
+
+#endif
+
+const bool at_light_pass = true;
+#else
+const bool at_light_pass = false;
+#endif
+
+uniform bool use_default_normal;
+
+layout(location = 0) out mediump vec4 frag_color;
+
+/* clang-format off */
+
+FRAGMENT_SHADER_GLOBALS
+
+/* clang-format on */
+
+void light_compute(
+		inout vec4 light,
+		inout vec2 light_vec,
+		inout float light_height,
+		inout vec4 light_color,
+		vec2 light_uv,
+		inout vec4 shadow_color,
+		inout vec2 shadow_vec,
+		vec3 normal,
+		vec2 uv,
+#if defined(SCREEN_UV_USED)
+		vec2 screen_uv,
+#endif
+		vec4 color) {
+
+#if defined(USE_LIGHT_SHADER_CODE)
+
+	/* clang-format off */
+
+LIGHT_SHADER_CODE
+
+	/* clang-format on */
+
+#endif
+}
+
+void main() {
+	vec4 color = color_interp;
+	vec2 uv = uv_interp;
+#ifdef USE_FORCE_REPEAT
+	//needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that don't support it
+	uv = mod(uv, vec2(1.0, 1.0));
+#endif
+
+#if !defined(COLOR_USED)
+	//default behavior, texture by color
+	color *= texture(color_texture, uv);
+#endif
+
+#ifdef SCREEN_UV_USED
+	vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
+#endif
+
+	vec3 normal;
+
+#if defined(NORMAL_USED)
+
+	bool normal_used = true;
+#else
+	bool normal_used = false;
+#endif
+
+	if (use_default_normal) {
+		normal.xy = texture(normal_texture, uv).xy * 2.0 - 1.0;
+		normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
+		normal_used = true;
+	} else {
+		normal = vec3(0.0, 0.0, 1.0);
+	}
+
+	{
+		float normal_depth = 1.0;
+
+#if defined(NORMALMAP_USED)
+		vec3 normal_map = vec3(0.0, 0.0, 1.0);
+		normal_used = true;
+#endif
+
+		/* clang-format off */
+
+FRAGMENT_SHADER_CODE
+
+		/* clang-format on */
+
+#if defined(NORMALMAP_USED)
+		normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth);
+#endif
+	}
+
+#ifdef USE_ATTRIB_MODULATE
+	color *= modulate_interp;
+#else
+#if !defined(MODULATE_USED)
+	color *= final_modulate;
+#endif
+#endif
+
+#ifdef USE_LIGHTING
+
+	vec2 light_vec = transformed_light_uv;
+	vec2 shadow_vec = transformed_light_uv;
+
+	if (normal_used) {
+		normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy;
+	}
+
+	float att = 1.0;
+
+	vec2 light_uv = light_uv_interp.xy;
+	vec4 light = texture(light_texture, light_uv);
+
+	if (any(lessThan(light_uv_interp.xy, vec2(0.0, 0.0))) || any(greaterThanEqual(light_uv_interp.xy, vec2(1.0, 1.0)))) {
+		color.a *= light_outside_alpha; //invisible
+
+	} else {
+		float real_light_height = light_height;
+		vec4 real_light_color = light_color;
+		vec4 real_light_shadow_color = light_shadow_color;
+
+#if defined(USE_LIGHT_SHADER_CODE)
+		//light is written by the light shader
+		light_compute(
+				light,
+				light_vec,
+				real_light_height,
+				real_light_color,
+				light_uv,
+				real_light_shadow_color,
+				shadow_vec,
+				normal,
+				uv,
+#if defined(SCREEN_UV_USED)
+				screen_uv,
+#endif
+				color);
+#endif
+
+		light *= real_light_color;
+
+		if (normal_used) {
+			vec3 light_normal = normalize(vec3(light_vec, -real_light_height));
+			light *= max(dot(-light_normal, normal), 0.0);
+		}
+
+		color *= light;
+
+#ifdef USE_SHADOWS
+
+#ifdef SHADOW_VEC_USED
+		mat3 inverse_light_matrix = mat3(light_matrix);
+		inverse_light_matrix[0] = normalize(inverse_light_matrix[0]);
+		inverse_light_matrix[1] = normalize(inverse_light_matrix[1]);
+		inverse_light_matrix[2] = normalize(inverse_light_matrix[2]);
+		shadow_vec = (inverse_light_matrix * vec3(shadow_vec, 0.0)).xy;
+#else
+		shadow_vec = light_uv_interp.zw;
+#endif
+
+		float angle_to_light = -atan(shadow_vec.x, shadow_vec.y);
+		float PI = 3.14159265358979323846264;
+		/*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays
+		float ang*/
+
+		float su, sz;
+
+		float abs_angle = abs(angle_to_light);
+		vec2 point;
+		float sh;
+		if (abs_angle < 45.0 * PI / 180.0) {
+			point = shadow_vec;
+			sh = 0.0 + (1.0 / 8.0);
+		} else if (abs_angle > 135.0 * PI / 180.0) {
+			point = -shadow_vec;
+			sh = 0.5 + (1.0 / 8.0);
+		} else if (angle_to_light > 0.0) {
+			point = vec2(shadow_vec.y, -shadow_vec.x);
+			sh = 0.25 + (1.0 / 8.0);
+		} else {
+			point = vec2(-shadow_vec.y, shadow_vec.x);
+			sh = 0.75 + (1.0 / 8.0);
+		}
+
+		highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0);
+		s.xyz /= s.w;
+		su = s.x * 0.5 + 0.5;
+		sz = s.z * 0.5 + 0.5;
+		//sz=lightlength(light_vec);
+
+		highp float shadow_attenuation = 0.0;
+
+#ifdef USE_RGBA_SHADOWS
+#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0))
+
+#else
+
+#define SHADOW_DEPTH(m_tex, m_uv) (texture((m_tex), (m_uv)).r)
+
+#endif
+
+#ifdef SHADOW_USE_GRADIENT
+
+		/* clang-format off */
+		/* GLSL es 100 doesn't support line continuation characters(backslashes) */
+#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); }
+
+#else
+
+#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += step(sz, sd); }
+		/* clang-format on */
+
+#endif
+
+#ifdef SHADOW_FILTER_NEAREST
+
+		SHADOW_TEST(su);
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF3
+
+		SHADOW_TEST(su + shadowpixel_size);
+		SHADOW_TEST(su);
+		SHADOW_TEST(su - shadowpixel_size);
+		shadow_attenuation /= 3.0;
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF5
+
+		SHADOW_TEST(su + shadowpixel_size * 2.0);
+		SHADOW_TEST(su + shadowpixel_size);
+		SHADOW_TEST(su);
+		SHADOW_TEST(su - shadowpixel_size);
+		SHADOW_TEST(su - shadowpixel_size * 2.0);
+		shadow_attenuation /= 5.0;
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF7
+
+		SHADOW_TEST(su + shadowpixel_size * 3.0);
+		SHADOW_TEST(su + shadowpixel_size * 2.0);
+		SHADOW_TEST(su + shadowpixel_size);
+		SHADOW_TEST(su);
+		SHADOW_TEST(su - shadowpixel_size);
+		SHADOW_TEST(su - shadowpixel_size * 2.0);
+		SHADOW_TEST(su - shadowpixel_size * 3.0);
+		shadow_attenuation /= 7.0;
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF9
+
+		SHADOW_TEST(su + shadowpixel_size * 4.0);
+		SHADOW_TEST(su + shadowpixel_size * 3.0);
+		SHADOW_TEST(su + shadowpixel_size * 2.0);
+		SHADOW_TEST(su + shadowpixel_size);
+		SHADOW_TEST(su);
+		SHADOW_TEST(su - shadowpixel_size);
+		SHADOW_TEST(su - shadowpixel_size * 2.0);
+		SHADOW_TEST(su - shadowpixel_size * 3.0);
+		SHADOW_TEST(su - shadowpixel_size * 4.0);
+		shadow_attenuation /= 9.0;
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF13
+
+		SHADOW_TEST(su + shadowpixel_size * 6.0);
+		SHADOW_TEST(su + shadowpixel_size * 5.0);
+		SHADOW_TEST(su + shadowpixel_size * 4.0);
+		SHADOW_TEST(su + shadowpixel_size * 3.0);
+		SHADOW_TEST(su + shadowpixel_size * 2.0);
+		SHADOW_TEST(su + shadowpixel_size);
+		SHADOW_TEST(su);
+		SHADOW_TEST(su - shadowpixel_size);
+		SHADOW_TEST(su - shadowpixel_size * 2.0);
+		SHADOW_TEST(su - shadowpixel_size * 3.0);
+		SHADOW_TEST(su - shadowpixel_size * 4.0);
+		SHADOW_TEST(su - shadowpixel_size * 5.0);
+		SHADOW_TEST(su - shadowpixel_size * 6.0);
+		shadow_attenuation /= 13.0;
+
+#endif
+
+		//color *= shadow_attenuation;
+		color = mix(real_light_shadow_color, color, shadow_attenuation);
+//use shadows
+#endif
+	}
+
+//use lighting
+#endif
+
+	frag_color = color;
+}

+ 111 - 0
drivers/gles3/shaders/canvas_uniforms_inc.glsl

@@ -0,0 +1,111 @@
+
+#define MAX_LIGHTS_PER_ITEM 16
+
+#define M_PI 3.14159265359
+
+#define SDF_MAX_LENGTH 16384.0
+
+//1 means enabled, 2+ means trails in use
+#define FLAGS_INSTANCING_MASK 0x7F
+#define FLAGS_INSTANCING_HAS_COLORS (1 << 7)
+#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 8)
+
+#define FLAGS_CLIP_RECT_UV (1 << 9)
+#define FLAGS_TRANSPOSE_RECT (1 << 10)
+#define FLAGS_USING_LIGHT_MASK (1 << 11)
+#define FLAGS_NINEPACH_DRAW_CENTER (1 << 12)
+#define FLAGS_USING_PARTICLES (1 << 13)
+
+#define FLAGS_NINEPATCH_H_MODE_SHIFT 16
+#define FLAGS_NINEPATCH_V_MODE_SHIFT 18
+
+#define FLAGS_LIGHT_COUNT_SHIFT 20
+
+#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26)
+#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27)
+
+#define FLAGS_USE_MSDF (1 << 28)
+
+// must be always 128 bytes long
+struct DrawData {
+	vec2 world_x;
+	vec2 world_y;
+	vec2 world_ofs;
+	uint flags;
+	uint specular_shininess;
+#ifdef USE_PRIMITIVE
+	vec2 points[3];
+	vec2 uvs[3];
+	uint colors[6];
+#else
+	vec4 modulation;
+	vec4 ninepatch_margins;
+	vec4 dst_rect; //for built-in rect and UV
+	vec4 src_rect;
+	vec2 pad;
+
+#endif
+	vec2 color_texture_pixel_size;
+	uint lights[4];
+}
+
+layout(std140) uniform GlobalVariableData { //ubo:1
+	vec4 global_variables[MAX_GLOBAL_VARIABLES];
+};
+
+layout(std140) uniform CanvasData { //ubo:0
+	mat4 canvas_transform;
+	mat4 screen_transform;
+	mat4 canvas_normal_transform;
+	vec4 canvas_modulation;
+	vec2 screen_pixel_size;
+	float time;
+	bool use_pixel_snap;
+
+	vec4 sdf_to_tex;
+	vec2 screen_to_sdf;
+	vec2 sdf_to_screen;
+
+	uint directional_light_count;
+	float tex_to_sdf;
+	uint pad1;
+	uint pad2;
+};
+
+#define LIGHT_FLAGS_BLEND_MASK (3 << 16)
+#define LIGHT_FLAGS_BLEND_MODE_ADD (0 << 16)
+#define LIGHT_FLAGS_BLEND_MODE_SUB (1 << 16)
+#define LIGHT_FLAGS_BLEND_MODE_MIX (2 << 16)
+#define LIGHT_FLAGS_BLEND_MODE_MASK (3 << 16)
+#define LIGHT_FLAGS_HAS_SHADOW (1 << 20)
+#define LIGHT_FLAGS_FILTER_SHIFT 22
+#define LIGHT_FLAGS_FILTER_MASK (3 << 22)
+#define LIGHT_FLAGS_SHADOW_NEAREST (0 << 22)
+#define LIGHT_FLAGS_SHADOW_PCF5 (1 << 22)
+#define LIGHT_FLAGS_SHADOW_PCF13 (2 << 22)
+
+struct Light {
+	mat2x4 texture_matrix; //light to texture coordinate matrix (transposed)
+	mat2x4 shadow_matrix; //light to shadow coordinate matrix (transposed)
+	vec4 color;
+
+	uint shadow_color; // packed
+	uint flags; //index to light texture
+	float shadow_pixel_size;
+	float height;
+
+	vec2 position;
+	float shadow_zfar_inv;
+	float shadow_y_ofs;
+
+	vec4 atlas_rect;
+};
+
+layout(std140) uniform LightData { //ubo:2
+	Light light_data[MAX_LIGHTS];
+};
+
+layout(std140) uniform DrawDataInstances { //ubo:3
+
+	DrawData draw_data[MAX_DRAW_DATA_INSTANCES];
+};

+ 132 - 176
gles3_builders.py

@@ -6,16 +6,12 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki
 from platform_methods import subprocess_main
 
 
-class LegacyGLHeaderStruct:
+class GLES3HeaderStruct:
     def __init__(self):
         self.vertex_lines = []
         self.fragment_lines = []
         self.uniforms = []
-        self.attributes = []
-        self.feedbacks = []
         self.fbos = []
-        self.conditionals = []
-        self.enums = {}
         self.texunits = []
         self.texunit_names = []
         self.ubos = []
@@ -28,22 +24,65 @@ class LegacyGLHeaderStruct:
         self.line_offset = 0
         self.vertex_offset = 0
         self.fragment_offset = 0
+        self.variant_defines=[]
+        self.variant_names=[]
+        self.specialization_names=[]
+        self.specialization_values=[]
 
 
-def include_file_in_legacygl_header(filename, header_data, depth):
+def include_file_in_gles3_header(filename, header_data, depth):
     fs = open(filename, "r")
     line = fs.readline()
 
     while line:
 
-        if line.find("[vertex]") != -1:
+        if line.find("=") != -1 and header_data.reading=="": 
+            # Mode
+            eqpos = line.find("=")
+            defname = line[:eqpos].strip().upper()
+            define = line[eqpos+1:].strip()
+            header_data.variant_names.append( defname )
+            header_data.variant_defines.append( define )
+            line = fs.readline()
+            header_data.line_offset += 1
+            header_data.vertex_offset = header_data.line_offset
+            continue
+
+        if line.find("=") != -1 and header_data.reading=="specializations": 
+            # Specialization
+            eqpos = line.find("=")
+            specname = line[:eqpos].strip()
+            specvalue = line[eqpos+1:]
+            header_data.specialization_names.append( specname )
+            header_data.specialization_values.append( specvalue )
+            line = fs.readline()
+            header_data.line_offset += 1
+            header_data.vertex_offset = header_data.line_offset
+            continue
+
+        if line.find("#[modes]") != -1:
+            # Nothing really, just skip
+            line = fs.readline()
+            header_data.line_offset += 1
+            header_data.vertex_offset = header_data.line_offset
+            continue
+            
+
+        if line.find("#[specializations]") != -1:
+            header_data.reading = "specializations"
+            line = fs.readline()
+            header_data.line_offset += 1
+            header_data.vertex_offset = header_data.line_offset
+            continue
+
+        if line.find("#[vertex]") != -1:
             header_data.reading = "vertex"
             line = fs.readline()
             header_data.line_offset += 1
             header_data.vertex_offset = header_data.line_offset
             continue
 
-        if line.find("[fragment]") != -1:
+        if line.find("#[fragment]") != -1:
             header_data.reading = "fragment"
             line = fs.readline()
             header_data.line_offset += 1
@@ -58,31 +97,15 @@ def include_file_in_legacygl_header(filename, header_data, depth):
             included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline)
             if not included_file in header_data.vertex_included_files and header_data.reading == "vertex":
                 header_data.vertex_included_files += [included_file]
-                if include_file_in_legacygl_header(included_file, header_data, depth + 1) is None:
+                if include_file_in_gles3_header(included_file, header_data, depth + 1) is None:
                     print("Error in file '" + filename + "': #include " + includeline + "could not be found!")
             elif not included_file in header_data.fragment_included_files and header_data.reading == "fragment":
                 header_data.fragment_included_files += [included_file]
-                if include_file_in_legacygl_header(included_file, header_data, depth + 1) is None:
+                if include_file_in_gles3_header(included_file, header_data, depth + 1) is None:
                     print("Error in file '" + filename + "': #include " + includeline + "could not be found!")
 
             line = fs.readline()
 
-        if line.find("#ifdef ") != -1:
-            if line.find("#ifdef ") != -1:
-                ifdefline = line.replace("#ifdef ", "").strip()
-
-            if line.find("_EN_") != -1:
-                enumbase = ifdefline[: ifdefline.find("_EN_")]
-                ifdefline = ifdefline.replace("_EN_", "_")
-                line = line.replace("_EN_", "_")
-                if enumbase not in header_data.enums:
-                    header_data.enums[enumbase] = []
-                if ifdefline not in header_data.enums[enumbase]:
-                    header_data.enums[enumbase].append(ifdefline)
-
-            elif not ifdefline in header_data.conditionals:
-                header_data.conditionals += [ifdefline]
-
         if line.find("uniform") != -1 and line.lower().find("texunit:") != -1:
             # texture unit
             texunitstr = line[line.find(":") + 1 :].strip()
@@ -144,33 +167,6 @@ def include_file_in_legacygl_header(filename, header_data, depth):
                 if not x in header_data.uniforms:
                     header_data.uniforms += [x]
 
-        if line.strip().find("attribute ") == 0 and line.find("attrib:") != -1:
-            uline = line.replace("in ", "")
-            uline = uline.replace("attribute ", "")
-            uline = uline.replace("highp ", "")
-            uline = uline.replace(";", "")
-            uline = uline[uline.find(" ") :].strip()
-
-            if uline.find("//") != -1:
-                name, bind = uline.split("//")
-                if bind.find("attrib:") != -1:
-                    name = name.strip()
-                    bind = bind.replace("attrib:", "").strip()
-                    header_data.attributes += [(name, bind)]
-
-        if line.strip().find("out ") == 0 and line.find("tfb:") != -1:
-            uline = line.replace("out ", "")
-            uline = uline.replace("highp ", "")
-            uline = uline.replace(";", "")
-            uline = uline[uline.find(" ") :].strip()
-
-            if uline.find("//") != -1:
-                name, bind = uline.split("//")
-                if bind.find("tfb:") != -1:
-                    name = name.strip()
-                    bind = bind.replace("tfb:", "").strip()
-                    header_data.feedbacks += [(name, bind)]
-
         line = line.replace("\r", "")
         line = line.replace("\n", "")
 
@@ -187,12 +183,14 @@ def include_file_in_legacygl_header(filename, header_data, depth):
     return header_data
 
 
-def build_legacygl_header(filename, include, class_suffix, output_attribs):
-    header_data = LegacyGLHeaderStruct()
-    include_file_in_legacygl_header(filename, header_data, 0)
+def build_gles3_header(filename, include, class_suffix, output_attribs):
+    header_data = GLES3HeaderStruct()
+    include_file_in_gles3_header(filename, header_data, 0)
 
     out_file = filename + ".gen.h"
     fd = open(out_file, "w")
+    defspec = 0
+    defvariant = ""
 
     enum_constants = []
 
@@ -202,8 +200,8 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
     out_file_base = out_file_base[out_file_base.rfind("/") + 1 :]
     out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :]
     out_file_ifdef = out_file_base.replace(".", "_").upper()
-    fd.write("#ifndef " + out_file_ifdef + class_suffix + "_120\n")
-    fd.write("#define " + out_file_ifdef + class_suffix + "_120\n")
+    fd.write("#ifndef " + out_file_ifdef + class_suffix + "_GLES3\n")
+    fd.write("#define " + out_file_ifdef + class_suffix + "_GLES3\n")
 
     out_file_class = (
         out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "Shader" + class_suffix
@@ -211,27 +209,42 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
     fd.write("\n\n")
     fd.write('#include "' + include + '"\n\n\n')
     fd.write("class " + out_file_class + " : public Shader" + class_suffix + " {\n\n")
-    fd.write('\t virtual String get_shader_name() const { return "' + out_file_class + '"; }\n')
 
     fd.write("public:\n\n")
 
-    if header_data.conditionals:
-        fd.write("\tenum Conditionals {\n")
-        for x in header_data.conditionals:
-            fd.write("\t\t" + x.upper() + ",\n")
-        fd.write("\t};\n\n")
-
     if header_data.uniforms:
         fd.write("\tenum Uniforms {\n")
         for x in header_data.uniforms:
             fd.write("\t\t" + x.upper() + ",\n")
         fd.write("\t};\n\n")
 
+    if header_data.variant_names:
+        fd.write("\tenum ShaderVariant {\n")
+        for x in header_data.variant_names:
+            fd.write("\t\t" + x + ",\n")
+        fd.write("\t};\n\n")
+    else:
+        fd.write("\tenum ShaderVariant { DEFAULT };\n\n")
+        defvariant="=DEFAULT"
+
+    if header_data.specialization_names:
+        fd.write("\tenum Specializations {\n")
+        counter=0
+        for x in header_data.specialization_names:
+            fd.write("\t\t" + x.upper() + "=" + str(1<<counter)+",\n")            
+            counter+=1
+        fd.write("\t};\n\n")
+        
+    for i in range(len(header_data.specialization_names)):
+            defval = header_data.specialization_values[i].strip()
+            if (defval.upper() == "TRUE" or defval=="1"):
+                defspec|=(1<<i)
+
     fd.write("\t_FORCE_INLINE_ int get_uniform(Uniforms p_uniform) const { return _get_uniform(p_uniform); }\n\n")
-    if header_data.conditionals:
-        fd.write(
-            "\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable)  {  _set_conditional(p_conditional,p_enable); }\n\n"
-        )
+    
+    fd.write(
+        "\t_FORCE_INLINE_ void version_bind_shader(RID p_version,ShaderVariant p_variant"+defvariant+",uint64_t p_specialization="+str(defspec)+") { _version_bind_shader(p_version,p_variant,p_specialization); }\n\n"
+    )
     fd.write("\t#ifdef DEBUG_ENABLED\n ")
     fd.write(
         "\t#define _FU if (get_uniform(p_uniform)<0) return; if (!is_version_valid()) return; ERR_FAIL_COND( get_active()!=this ); \n\n "
@@ -368,64 +381,9 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
 
     fd.write("\n\n#undef _FU\n\n\n")
 
-    fd.write("\tvirtual void init() {\n\n")
-
-    enum_value_count = 0
-
-    if header_data.enums:
-
-        fd.write("\t\t//Written using math, given nonstandarity of 64 bits integer constants..\n")
-        fd.write("\t\tstatic const Enum _enums[]={\n")
-
-        bitofs = len(header_data.conditionals)
-        enum_vals = []
-
-        for xv in header_data.enums:
-            x = header_data.enums[xv]
-            bits = 1
-            amt = len(x)
-            while 2 ** bits < amt:
-                bits += 1
-            strs = "{"
-            for i in range(amt):
-                strs += '"#define ' + x[i] + '\\n",'
-
-                c = {}
-                c["set_mask"] = "uint64_t(" + str(i) + ")<<" + str(bitofs)
-                c["clear_mask"] = (
-                    "((uint64_t(1)<<40)-1) ^ (((uint64_t(1)<<" + str(bits) + ") - 1)<<" + str(bitofs) + ")"
-                )
-                enum_vals.append(c)
-                enum_constants.append(x[i])
-
-            strs += "NULL}"
-
-            fd.write(
-                "\t\t\t{(uint64_t(1<<" + str(bits) + ")-1)<<" + str(bitofs) + "," + str(bitofs) + "," + strs + "},\n"
-            )
-            bitofs += bits
+    fd.write("protected:\n\n")
 
-        fd.write("\t\t};\n\n")
-
-        fd.write("\t\tstatic const EnumValue _enum_values[]={\n")
-
-        enum_value_count = len(enum_vals)
-        for x in enum_vals:
-            fd.write("\t\t\t{" + x["set_mask"] + "," + x["clear_mask"] + "},\n")
-
-        fd.write("\t\t};\n\n")
-
-    conditionals_found = []
-    if header_data.conditionals:
-
-        fd.write("\t\tstatic const char* _conditional_strings[]={\n")
-        if header_data.conditionals:
-            for x in header_data.conditionals:
-                fd.write('\t\t\t"#define ' + x + '\\n",\n')
-                conditionals_found.append(x)
-        fd.write("\t\t};\n\n")
-    else:
-        fd.write("\t\tstatic const char **_conditional_strings=NULL;\n")
+    fd.write("\tvirtual void _init() override {\n\n")
 
     if header_data.uniforms:
 
@@ -435,19 +393,18 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
                 fd.write('\t\t\t"' + x + '",\n')
         fd.write("\t\t};\n\n")
     else:
-        fd.write("\t\tstatic const char **_uniform_strings=NULL;\n")
+        fd.write("\t\tstatic const char **_uniform_strings=nullptr;\n")
 
-    if output_attribs:
-        if header_data.attributes:
+    variant_count = 1
+    if len(header_data.variant_defines)>0:
 
-            fd.write("\t\tstatic AttributePair _attribute_pairs[]={\n")
-            for x in header_data.attributes:
-                fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n")
-            fd.write("\t\t};\n\n")
-        else:
-            fd.write("\t\tstatic AttributePair *_attribute_pairs=NULL;\n")
-
-    feedback_count = 0
+        fd.write("\t\tstatic const char* _variant_defines[]={\n")
+        for x in header_data.variant_defines:
+            fd.write('\t\t\t"' + x + '",\n')
+        fd.write("\t\t};\n\n")
+        variant_count=len(header_data.variant_defines)
+    else:
+        fd.write("\t\tstatic const char **_variant_defines[]={""};\n")
 
     if header_data.texunits:
         fd.write("\t\tstatic TexUnitPair _texunit_pairs[]={\n")
@@ -455,7 +412,29 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
             fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n")
         fd.write("\t\t};\n\n")
     else:
-        fd.write("\t\tstatic TexUnitPair *_texunit_pairs=NULL;\n")
+        fd.write("\t\tstatic TexUnitPair *_texunit_pairs=nullptr;\n")
+
+    if header_data.ubos:
+        fd.write("\t\tstatic UBOPair _ubo_pairs[]={\n")
+        for x in header_data.ubos:
+            fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n")
+        fd.write("\t\t};\n\n")
+    else:
+        fd.write("\t\tstatic UBOPair *_ubo_pairs=nullptr;\n")
+
+    if header_data.specialization_names:
+        fd.write("\t\tstatic Specialization _spec_pairs[]={\n")
+        for i in range(len(header_data.specialization_names)):
+            defval = header_data.specialization_values[i].strip()
+            if (defval.upper() == "TRUE" or defval=="1"):
+                defal="true"
+            else:
+                defval="false"
+                
+            fd.write('\t\t\t{"' + header_data.specialization_names[i] + '",' + defval + "},\n")
+        fd.write("\t\t};\n\n")
+    else:
+        fd.write("\t\tstatic Specialization *_spec_pairs=nullptr;\n")
 
     fd.write("\t\tstatic const char _vertex_code[]={\n")
     for x in header_data.vertex_lines:
@@ -465,8 +444,6 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
         fd.write(str(ord("\n")) + ",")
     fd.write("\t\t0};\n\n")
 
-    fd.write("\t\tstatic const int _vertex_code_start=" + str(header_data.vertex_offset) + ";\n")
-
     fd.write("\t\tstatic const char _fragment_code[]={\n")
     for x in header_data.fragment_lines:
         for c in x:
@@ -475,44 +452,23 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
         fd.write(str(ord("\n")) + ",")
     fd.write("\t\t0};\n\n")
 
-    fd.write("\t\tstatic const int _fragment_code_start=" + str(header_data.fragment_offset) + ";\n")
-
-    if output_attribs:
-        fd.write(
-            "\t\tsetup(_conditional_strings,"
-            + str(len(header_data.conditionals))
-            + ",_uniform_strings,"
-            + str(len(header_data.uniforms))
-            + ",_attribute_pairs,"
-            + str(len(header_data.attributes))
-            + ", _texunit_pairs,"
-            + str(len(header_data.texunits))
-            + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n"
-        )
-    else:
-        fd.write(
-            "\t\tsetup(_conditional_strings,"
-            + str(len(header_data.conditionals))
-            + ",_uniform_strings,"
-            + str(len(header_data.uniforms))
-            + ",_texunit_pairs,"
-            + str(len(header_data.texunits))
-            + ",_enums,"
-            + str(len(header_data.enums))
-            + ",_enum_values,"
-            + str(enum_value_count)
-            + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n"
-        )
+    fd.write(
+        "\t\tsetup(_vertex_code,_fragment_code,\""
+        + out_file_class + "\","
+        + str(len(header_data.uniforms))
+        + ",_uniform_strings,"
+        + str(len(header_data.ubos))
+        + ",_ubo_pairs,"
+        + str(len(header_data.texunits))
+        + ",_texunit_pairs,"
+        + str(len(header_data.specialization_names))
+        + ",_spec_pairs,"
+        + str(variant_count)
+        + ",_variant_defines);\n"
+    )
 
     fd.write("\t}\n\n")
 
-    if enum_constants:
-
-        fd.write("\tenum EnumConditionals {\n")
-        for x in enum_constants:
-            fd.write("\t\t" + x.upper() + ",\n")
-        fd.write("\t};\n\n")
-        fd.write("\tvoid set_enum_conditional(EnumConditionals p_cond) { _set_enum_conditional(p_cond); }\n")
 
     fd.write("};\n\n")
     fd.write("#endif\n\n")
@@ -521,7 +477,7 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
 
 def build_gles3_headers(target, source, env):
     for x in source:
-        build_legacygl_header(str(x), include="drivers/gles3/shader_gles3.h", class_suffix="GLES3", output_attribs=True)
+        build_gles3_header(str(x), include="drivers/gles3/shader_gles3.h", class_suffix="GLES3", output_attribs=True)
 
 
 if __name__ == "__main__":

+ 528 - 0
gles3_old_builders.py

@@ -0,0 +1,528 @@
+"""Functions used to generate source files during build time
+
+All such functions are invoked in a subprocess on Windows to prevent build flakiness.
+
+"""
+from platform_methods import subprocess_main
+
+
+class LegacyGLHeaderStruct:
+    def __init__(self):
+        self.vertex_lines = []
+        self.fragment_lines = []
+        self.uniforms = []
+        self.attributes = []
+        self.feedbacks = []
+        self.fbos = []
+        self.conditionals = []
+        self.enums = {}
+        self.texunits = []
+        self.texunit_names = []
+        self.ubos = []
+        self.ubo_names = []
+
+        self.vertex_included_files = []
+        self.fragment_included_files = []
+
+        self.reading = ""
+        self.line_offset = 0
+        self.vertex_offset = 0
+        self.fragment_offset = 0
+
+
+def include_file_in_legacygl_header(filename, header_data, depth):
+    fs = open(filename, "r")
+    line = fs.readline()
+
+    while line:
+
+        if line.find("[vertex]") != -1:
+            header_data.reading = "vertex"
+            line = fs.readline()
+            header_data.line_offset += 1
+            header_data.vertex_offset = header_data.line_offset
+            continue
+
+        if line.find("[fragment]") != -1:
+            header_data.reading = "fragment"
+            line = fs.readline()
+            header_data.line_offset += 1
+            header_data.fragment_offset = header_data.line_offset
+            continue
+
+        while line.find("#include ") != -1:
+            includeline = line.replace("#include ", "").strip()[1:-1]
+
+            import os.path
+
+            included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline)
+            if not included_file in header_data.vertex_included_files and header_data.reading == "vertex":
+                header_data.vertex_included_files += [included_file]
+                if include_file_in_legacygl_header(included_file, header_data, depth + 1) is None:
+                    print("Error in file '" + filename + "': #include " + includeline + "could not be found!")
+            elif not included_file in header_data.fragment_included_files and header_data.reading == "fragment":
+                header_data.fragment_included_files += [included_file]
+                if include_file_in_legacygl_header(included_file, header_data, depth + 1) is None:
+                    print("Error in file '" + filename + "': #include " + includeline + "could not be found!")
+
+            line = fs.readline()
+
+        if line.find("#ifdef ") != -1:
+            if line.find("#ifdef ") != -1:
+                ifdefline = line.replace("#ifdef ", "").strip()
+
+            if line.find("_EN_") != -1:
+                enumbase = ifdefline[: ifdefline.find("_EN_")]
+                ifdefline = ifdefline.replace("_EN_", "_")
+                line = line.replace("_EN_", "_")
+                if enumbase not in header_data.enums:
+                    header_data.enums[enumbase] = []
+                if ifdefline not in header_data.enums[enumbase]:
+                    header_data.enums[enumbase].append(ifdefline)
+
+            elif not ifdefline in header_data.conditionals:
+                header_data.conditionals += [ifdefline]
+
+        if line.find("uniform") != -1 and line.lower().find("texunit:") != -1:
+            # texture unit
+            texunitstr = line[line.find(":") + 1 :].strip()
+            if texunitstr == "auto":
+                texunit = "-1"
+            else:
+                texunit = str(int(texunitstr))
+            uline = line[: line.lower().find("//")]
+            uline = uline.replace("uniform", "")
+            uline = uline.replace("highp", "")
+            uline = uline.replace(";", "")
+            lines = uline.split(",")
+            for x in lines:
+
+                x = x.strip()
+                x = x[x.rfind(" ") + 1 :]
+                if x.find("[") != -1:
+                    # unfiorm array
+                    x = x[: x.find("[")]
+
+                if not x in header_data.texunit_names:
+                    header_data.texunits += [(x, texunit)]
+                    header_data.texunit_names += [x]
+
+        elif line.find("uniform") != -1 and line.lower().find("ubo:") != -1:
+            # uniform buffer object
+            ubostr = line[line.find(":") + 1 :].strip()
+            ubo = str(int(ubostr))
+            uline = line[: line.lower().find("//")]
+            uline = uline[uline.find("uniform") + len("uniform") :]
+            uline = uline.replace("highp", "")
+            uline = uline.replace(";", "")
+            uline = uline.replace("{", "").strip()
+            lines = uline.split(",")
+            for x in lines:
+
+                x = x.strip()
+                x = x[x.rfind(" ") + 1 :]
+                if x.find("[") != -1:
+                    # unfiorm array
+                    x = x[: x.find("[")]
+
+                if not x in header_data.ubo_names:
+                    header_data.ubos += [(x, ubo)]
+                    header_data.ubo_names += [x]
+
+        elif line.find("uniform") != -1 and line.find("{") == -1 and line.find(";") != -1:
+            uline = line.replace("uniform", "")
+            uline = uline.replace(";", "")
+            lines = uline.split(",")
+            for x in lines:
+
+                x = x.strip()
+                x = x[x.rfind(" ") + 1 :]
+                if x.find("[") != -1:
+                    # unfiorm array
+                    x = x[: x.find("[")]
+
+                if not x in header_data.uniforms:
+                    header_data.uniforms += [x]
+
+        if line.strip().find("attribute ") == 0 and line.find("attrib:") != -1:
+            uline = line.replace("in ", "")
+            uline = uline.replace("attribute ", "")
+            uline = uline.replace("highp ", "")
+            uline = uline.replace(";", "")
+            uline = uline[uline.find(" ") :].strip()
+
+            if uline.find("//") != -1:
+                name, bind = uline.split("//")
+                if bind.find("attrib:") != -1:
+                    name = name.strip()
+                    bind = bind.replace("attrib:", "").strip()
+                    header_data.attributes += [(name, bind)]
+
+        if line.strip().find("out ") == 0 and line.find("tfb:") != -1:
+            uline = line.replace("out ", "")
+            uline = uline.replace("highp ", "")
+            uline = uline.replace(";", "")
+            uline = uline[uline.find(" ") :].strip()
+
+            if uline.find("//") != -1:
+                name, bind = uline.split("//")
+                if bind.find("tfb:") != -1:
+                    name = name.strip()
+                    bind = bind.replace("tfb:", "").strip()
+                    header_data.feedbacks += [(name, bind)]
+
+        line = line.replace("\r", "")
+        line = line.replace("\n", "")
+
+        if header_data.reading == "vertex":
+            header_data.vertex_lines += [line]
+        if header_data.reading == "fragment":
+            header_data.fragment_lines += [line]
+
+        line = fs.readline()
+        header_data.line_offset += 1
+
+    fs.close()
+
+    return header_data
+
+
+def build_legacygl_header(filename, include, class_suffix, output_attribs):
+    header_data = LegacyGLHeaderStruct()
+    include_file_in_legacygl_header(filename, header_data, 0)
+
+    out_file = filename + ".gen.h"
+    fd = open(out_file, "w")
+
+    enum_constants = []
+
+    fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n")
+
+    out_file_base = out_file
+    out_file_base = out_file_base[out_file_base.rfind("/") + 1 :]
+    out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :]
+    out_file_ifdef = out_file_base.replace(".", "_").upper()
+    fd.write("#ifndef " + out_file_ifdef + class_suffix + "_120\n")
+    fd.write("#define " + out_file_ifdef + class_suffix + "_120\n")
+
+    out_file_class = (
+        out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "Shader" + class_suffix
+    )
+    fd.write("\n\n")
+    fd.write('#include "' + include + '"\n\n\n')
+    fd.write("class " + out_file_class + " : public ShaderOLD" + class_suffix + " {\n\n")
+    fd.write('\t virtual String get_shader_name() const { return "' + out_file_class + '"; }\n')
+
+    fd.write("public:\n\n")
+
+    if header_data.conditionals:
+        fd.write("\tenum Conditionals {\n")
+        for x in header_data.conditionals:
+            fd.write("\t\t" + x.upper() + ",\n")
+        fd.write("\t};\n\n")
+
+    if header_data.uniforms:
+        fd.write("\tenum Uniforms {\n")
+        for x in header_data.uniforms:
+            fd.write("\t\t" + x.upper() + ",\n")
+        fd.write("\t};\n\n")
+
+    fd.write("\t_FORCE_INLINE_ int get_uniform(Uniforms p_uniform) const { return _get_uniform(p_uniform); }\n\n")
+    if header_data.conditionals:
+        fd.write(
+            "\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable)  {  _set_conditional(p_conditional,p_enable); }\n\n"
+        )
+    fd.write("\t#ifdef DEBUG_ENABLED\n ")
+    fd.write(
+        "\t#define _FU if (get_uniform(p_uniform)<0) return; if (!is_version_valid()) return; ERR_FAIL_COND( get_active()!=this ); \n\n "
+    )
+    fd.write("\t#else\n ")
+    fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; \n\n ")
+    fd.write("\t#endif\n")
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Color& p_color) { _FU GLfloat col[4]={p_color.r,p_color.g,p_color.b,p_color.a}; glUniform4fv(get_uniform(p_uniform),1,col); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector2& p_vec2) { _FU GLfloat vec2[2]={p_vec2.x,p_vec2.y}; glUniform2fv(get_uniform(p_uniform),1,vec2); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Size2i& p_vec2) { _FU GLint vec2[2]={p_vec2.x,p_vec2.y}; glUniform2iv(get_uniform(p_uniform),1,vec2); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector3& p_vec3) { _FU GLfloat vec3[3]={p_vec3.x,p_vec3.y,p_vec3.z}; glUniform3fv(get_uniform(p_uniform),1,vec3); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b) { _FU glUniform2f(get_uniform(p_uniform),p_a,p_b); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c) { _FU glUniform3f(get_uniform(p_uniform),p_a,p_b,p_c); }\n\n"
+    )
+    fd.write(
+        "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c, float p_d) { _FU glUniform4f(get_uniform(p_uniform),p_a,p_b,p_c,p_d); }\n\n"
+    )
+
+    fd.write(
+        """\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform3D& p_transform) {  _FU
+
+        const Transform3D &tr = p_transform;
+
+        GLfloat matrix[16]={ /* build a 16x16 matrix */
+            tr.basis.elements[0][0],
+            tr.basis.elements[1][0],
+            tr.basis.elements[2][0],
+            0,
+            tr.basis.elements[0][1],
+            tr.basis.elements[1][1],
+            tr.basis.elements[2][1],
+            0,
+            tr.basis.elements[0][2],
+            tr.basis.elements[1][2],
+            tr.basis.elements[2][2],
+            0,
+            tr.origin.x,
+            tr.origin.y,
+            tr.origin.z,
+            1
+        };
+
+
+                glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
+
+
+    }
+
+    """
+    )
+
+    fd.write(
+        """_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform2D& p_transform) {  _FU
+
+        const Transform2D &tr = p_transform;
+
+        GLfloat matrix[16]={ /* build a 16x16 matrix */
+            tr.elements[0][0],
+            tr.elements[0][1],
+            0,
+            0,
+            tr.elements[1][0],
+            tr.elements[1][1],
+            0,
+            0,
+            0,
+            0,
+            1,
+            0,
+            tr.elements[2][0],
+            tr.elements[2][1],
+            0,
+            1
+        };
+
+
+        glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
+
+
+    }
+
+    """
+    )
+
+    fd.write(
+        """_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const CameraMatrix& p_matrix) {  _FU
+
+        GLfloat matrix[16];
+
+        for (int i=0;i<4;i++) {
+            for (int j=0;j<4;j++) {
+                matrix[i*4+j]=p_matrix.matrix[i][j];
+            }
+        }
+
+        glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
+}"""
+    )
+
+    fd.write("\n\n#undef _FU\n\n\n")
+
+    fd.write("\tvirtual void init() {\n\n")
+
+    enum_value_count = 0
+
+    if header_data.enums:
+
+        fd.write("\t\t//Written using math, given nonstandarity of 64 bits integer constants..\n")
+        fd.write("\t\tstatic const Enum _enums[]={\n")
+
+        bitofs = len(header_data.conditionals)
+        enum_vals = []
+
+        for xv in header_data.enums:
+            x = header_data.enums[xv]
+            bits = 1
+            amt = len(x)
+            while 2 ** bits < amt:
+                bits += 1
+            strs = "{"
+            for i in range(amt):
+                strs += '"#define ' + x[i] + '\\n",'
+
+                c = {}
+                c["set_mask"] = "uint64_t(" + str(i) + ")<<" + str(bitofs)
+                c["clear_mask"] = (
+                    "((uint64_t(1)<<40)-1) ^ (((uint64_t(1)<<" + str(bits) + ") - 1)<<" + str(bitofs) + ")"
+                )
+                enum_vals.append(c)
+                enum_constants.append(x[i])
+
+            strs += "NULL}"
+
+            fd.write(
+                "\t\t\t{(uint64_t(1<<" + str(bits) + ")-1)<<" + str(bitofs) + "," + str(bitofs) + "," + strs + "},\n"
+            )
+            bitofs += bits
+
+        fd.write("\t\t};\n\n")
+
+        fd.write("\t\tstatic const EnumValue _enum_values[]={\n")
+
+        enum_value_count = len(enum_vals)
+        for x in enum_vals:
+            fd.write("\t\t\t{" + x["set_mask"] + "," + x["clear_mask"] + "},\n")
+
+        fd.write("\t\t};\n\n")
+
+    conditionals_found = []
+    if header_data.conditionals:
+
+        fd.write("\t\tstatic const char* _conditional_strings[]={\n")
+        if header_data.conditionals:
+            for x in header_data.conditionals:
+                fd.write('\t\t\t"#define ' + x + '\\n",\n')
+                conditionals_found.append(x)
+        fd.write("\t\t};\n\n")
+    else:
+        fd.write("\t\tstatic const char **_conditional_strings=NULL;\n")
+
+    if header_data.uniforms:
+
+        fd.write("\t\tstatic const char* _uniform_strings[]={\n")
+        if header_data.uniforms:
+            for x in header_data.uniforms:
+                fd.write('\t\t\t"' + x + '",\n')
+        fd.write("\t\t};\n\n")
+    else:
+        fd.write("\t\tstatic const char **_uniform_strings=NULL;\n")
+
+    if output_attribs:
+        if header_data.attributes:
+
+            fd.write("\t\tstatic AttributePair _attribute_pairs[]={\n")
+            for x in header_data.attributes:
+                fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n")
+            fd.write("\t\t};\n\n")
+        else:
+            fd.write("\t\tstatic AttributePair *_attribute_pairs=NULL;\n")
+
+    feedback_count = 0
+
+    if header_data.texunits:
+        fd.write("\t\tstatic TexUnitPair _texunit_pairs[]={\n")
+        for x in header_data.texunits:
+            fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n")
+        fd.write("\t\t};\n\n")
+    else:
+        fd.write("\t\tstatic TexUnitPair *_texunit_pairs=NULL;\n")
+
+    fd.write("\t\tstatic const char _vertex_code[]={\n")
+    for x in header_data.vertex_lines:
+        for c in x:
+            fd.write(str(ord(c)) + ",")
+
+        fd.write(str(ord("\n")) + ",")
+    fd.write("\t\t0};\n\n")
+
+    fd.write("\t\tstatic const int _vertex_code_start=" + str(header_data.vertex_offset) + ";\n")
+
+    fd.write("\t\tstatic const char _fragment_code[]={\n")
+    for x in header_data.fragment_lines:
+        for c in x:
+            fd.write(str(ord(c)) + ",")
+
+        fd.write(str(ord("\n")) + ",")
+    fd.write("\t\t0};\n\n")
+
+    fd.write("\t\tstatic const int _fragment_code_start=" + str(header_data.fragment_offset) + ";\n")
+
+    if output_attribs:
+        fd.write(
+            "\t\tsetup(_conditional_strings,"
+            + str(len(header_data.conditionals))
+            + ",_uniform_strings,"
+            + str(len(header_data.uniforms))
+            + ",_attribute_pairs,"
+            + str(len(header_data.attributes))
+            + ", _texunit_pairs,"
+            + str(len(header_data.texunits))
+            + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n"
+        )
+    else:
+        fd.write(
+            "\t\tsetup(_conditional_strings,"
+            + str(len(header_data.conditionals))
+            + ",_uniform_strings,"
+            + str(len(header_data.uniforms))
+            + ",_texunit_pairs,"
+            + str(len(header_data.texunits))
+            + ",_enums,"
+            + str(len(header_data.enums))
+            + ",_enum_values,"
+            + str(enum_value_count)
+            + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n"
+        )
+
+    fd.write("\t}\n\n")
+
+    if enum_constants:
+
+        fd.write("\tenum EnumConditionals {\n")
+        for x in enum_constants:
+            fd.write("\t\t" + x.upper() + ",\n")
+        fd.write("\t};\n\n")
+        fd.write("\tvoid set_enum_conditional(EnumConditionals p_cond) { _set_enum_conditional(p_cond); }\n")
+
+    fd.write("};\n\n")
+    fd.write("#endif\n\n")
+    fd.close()
+
+
+def build_gles3_headers(target, source, env):
+    for x in source:
+        build_legacygl_header(str(x), include="drivers/gles3/shader_old_gles3.h", class_suffix="GLES3", output_attribs=True)
+
+
+if __name__ == "__main__":
+    subprocess_main(globals())