summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorreduz <reduzio@gmail.com>2021-11-13 08:54:58 -0300
committerclayjohn <claynjohn@gmail.com>2022-01-11 22:25:01 -0800
commit98ac002c3430b1ff50052b19d16fe6fa8fecf0c3 (patch)
tree916cde02c7da5605c508d654bc290c79ce4d1f28 /drivers
parent96a20e477b8cf2760dacab830ba7807c6f61bb8d (diff)
WIP New GLES3 Shader Compiler
Uses versions and specializations (more similar to RenderingDevice version)
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gles3/rasterizer_canvas_base_gles3.cpp68
-rw-r--r--drivers/gles3/rasterizer_canvas_base_gles3.h4
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp60
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp4
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h14
-rw-r--r--drivers/gles3/shader_compiler_old_gles3.cpp (renamed from drivers/gles3/shader_compiler_gles3.cpp)12
-rw-r--r--drivers/gles3/shader_compiler_old_gles3.h (renamed from drivers/gles3/shader_compiler_gles3.h)8
-rw-r--r--drivers/gles3/shader_gles3.cpp1397
-rw-r--r--drivers/gles3/shader_gles3.h316
-rw-r--r--drivers/gles3/shader_old_gles3.cpp1116
-rw-r--r--drivers/gles3/shader_old_gles3.h277
-rw-r--r--drivers/gles3/shaders/SCsub19
-rw-r--r--drivers/gles3/shaders/canvas.glsl1055
-rw-r--r--drivers/gles3/shaders/canvas_old.glsl665
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl111
16 files changed, 3463 insertions, 1665 deletions
diff --git a/drivers/gles3/rasterizer_canvas_base_gles3.cpp b/drivers/gles3/rasterizer_canvas_base_gles3.cpp
index 899e89cbce..07408ec507 100644
--- a/drivers/gles3/rasterizer_canvas_base_gles3.cpp
+++ b/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;
diff --git a/drivers/gles3/rasterizer_canvas_base_gles3.h b/drivers/gles3/rasterizer_canvas_base_gles3.h
index 60292ff875..898854d26e 100644
--- a/drivers/gles3/rasterizer_canvas_base_gles3.h
+++ b/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;
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 686910e1c6..cbb463549c 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/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();
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 0840d03e44..5f103c34eb 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/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"
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index e010e55307..a114573328 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/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: {
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 807789586b..cf92a991e8 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/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;
diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_old_gles3.cpp
index 555ed6ebd2..a14f69467c 100644
--- a/drivers/gles3/shader_compiler_gles3.cpp
+++ b/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";
diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_old_gles3.h
index 7ed882d03d..daa9475245 100644
--- a/drivers/gles3/shader_compiler_gles3.h
+++ b/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
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 474a80aca1..5580abd586 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/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
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index 3b9177b4eb..54a3688ea2 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/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 <reduzio@gmail.com>
+*/
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
diff --git a/drivers/gles3/shader_old_gles3.cpp b/drivers/gles3/shader_old_gles3.cpp
new file mode 100644
index 0000000000..af22f2ab31
--- /dev/null
+++ b/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
diff --git a/drivers/gles3/shader_old_gles3.h b/drivers/gles3/shader_old_gles3.h
new file mode 100644
index 0000000000..1ff3509bd9
--- /dev/null
+++ b/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
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index 47d56b9947..86542c2de5 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/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")
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index f2b141252a..b64cbf01b9 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/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;
}
diff --git a/drivers/gles3/shaders/canvas_old.glsl b/drivers/gles3/shaders/canvas_old.glsl
new file mode 100644
index 0000000000..f2b141252a
--- /dev/null
+++ b/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;
+}
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
new file mode 100644
index 0000000000..942ad72b93
--- /dev/null
+++ b/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];
+};