diff options
Diffstat (limited to 'drivers/gles3/shader_gles3.cpp')
-rw-r--r-- | drivers/gles3/shader_gles3.cpp | 1410 |
1 files changed, 498 insertions, 912 deletions
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 2f26acf628..7ae8b4e3bf 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,378 +29,305 @@ /*************************************************************************/ #include "shader_gles3.h" -#include "drivers/gles3/rasterizer_platforms.h" -#ifdef GLES3_BACKEND_ENABLED +#ifdef GLES3_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; +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 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++; + 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].default_value) { + specialization_default_mask |= (uint64_t(1) << uint64_t(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"); -#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"); - //} - + builder.append("#version 300 es\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 & (uint64_t(1) << uint64_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."); + } 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()); - -#ifdef DEBUG_SHADER + //fragment stage + { + StringBuilder builder; + _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT], p_specialization); + + spec.frag_id = glCreateShader(GL_FRAGMENT_SHADER); + String builder_string = builder.as_string(); + CharString cs = builder_string.utf8(); + const char *cstr = cs.ptr(); + glShaderSource(spec.frag_id, 1, &cstr, nullptr); + glCompileShader(spec.frag_id); + + glGetShaderiv(spec.frag_id, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + GLsizei iloglen; + glGetShaderiv(spec.frag_id, GL_INFO_LOG_LENGTH, &iloglen); + + if (iloglen < 0) { + glDeleteShader(spec.frag_id); + glDeleteProgram(spec.id); + spec.id = 0; + + ERR_PRINT("No OpenGL fragment shader compiler log."); + } else { + if (iloglen == 0) { + iloglen = 4096; // buggy driver (Adreno 220+) + } - if (cc) { - DEBUG_PRINT("\nFragment Code:\n\n" + String(cc->fragment_globals)); - } - DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string.get_data())); -#endif + char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); + ilogmem[iloglen] = '\0'; + glGetShaderInfoLog(spec.frag_id, iloglen, &iloglen, ilogmem); - v.frag_id = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(v.frag_id, strings.size(), &strings[0], NULL); - glCompileShader(v.frag_id); + String err_string = name + ": Fragment shader compilation failed:\n"; - glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - GLsizei iloglen; - glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen); + err_string += ilogmem; - if (iloglen < 0) { - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; + _display_error_with_code(err_string, builder_string); - 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.frag_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); + glAttachShader(spec.id, spec.frag_id); + glAttachShader(spec.id, spec.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); - } + //for (int i = 0; i < attribute_pair_count; i++) { + // glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name); + //} - 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 +336,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 +373,330 @@ 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 = glGetUniformBlockIndex(spec.id, ubo_pairs[i].name); + if (loc >= 0) { + glUniformBlockBinding(spec.id, 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; + glUseProgram(0); + spec.ok = true; } -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()); -} +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); -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; + source_code.versions.resize(variant_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()); + for (int i = 0; i < source_code.versions.size(); i++) { + //vertex stage - cpos = code.find(code_tag); + { + StringBuilder builder; + _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX], specialization_default_mask); - 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()); + 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; +String ShaderGLES3::_version_get_sha1(Version *p_version) const { + StringBuilder hash_build; - while ((V = version_map.next(V))) { - Version &v = version_map[*V]; - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); + 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()); - if (v.uniform_location) - 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); } -} - -void ShaderGLES3::clear_caches() { - const VersionKey *V = NULL; + code_sections.sort_custom<StringName::AlphCompare>(); - 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); + 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()); } - - 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 < p_version->custom_defines.size(); i++) { + hash_build.append("[custom_defines:" + itos(i) + "]"); + hash_build.append(p_version->custom_defines[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); - } - - 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 + ERR_FAIL_COND_V(shader.is_null(), false); + } + { + MutexLock lock(variant_set_mutex); + p_version->variants[i] = shader; + } + } - switch (E->get().type) { - case ShaderLanguage::TYPE_BOOL: { - glUniform1i(location, 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_BVEC2: { - glUniform2i(location, 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_BVEC3: { - glUniform3i(location, 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_BVEC4: { - glUniform4i(location, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - } 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_INT: { - glUniform1i(location, 0); - } break; + f->close(); +#endif +} - case ShaderLanguage::TYPE_IVEC2: { - glUniform2i(location, 0, 0); - } break; +void ShaderGLES3::_clear_version(Version *p_version) { + // Variants not compiled yet, just return + if (p_version->variants.size() == 0) { + return; + } - case ShaderLanguage::TYPE_IVEC3: { - glUniform3i(location, 0, 0, 0); - } break; + 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++) { + OAHashMap<uint64_t, Version::Specialization> variant; + p_version->variants.push_back(variant); + 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 |