diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gles3/rasterizer_canvas_base_gles3.cpp | 68 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_canvas_base_gles3.h | 4 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_canvas_gles3.cpp | 60 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_gles3.cpp | 2 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.cpp | 4 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.h | 14 | ||||
-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.cpp | 1397 | ||||
-rw-r--r-- | drivers/gles3/shader_gles3.h | 316 | ||||
-rw-r--r-- | drivers/gles3/shader_old_gles3.cpp | 1116 | ||||
-rw-r--r-- | drivers/gles3/shader_old_gles3.h | 277 | ||||
-rw-r--r-- | drivers/gles3/shaders/SCsub | 19 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas.glsl | 1055 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas_old.glsl | 665 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas_uniforms_inc.glsl | 111 |
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]; +}; |