ShaderGLES2::Version *ShaderGLES2::get_current_version() { 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 120\n"); strings.push_back("#define USE_GLES_OVER_GL\n"); #else strings.push_back("#version 100\n"); //angle does not like #ifdef JAVASCRIPT_ENABLED strings.push_back("#define USE_HIGHP_PRECISION\n"); #endif #endif int define_line_ofs = 1; for (int j = 0; j < conditional_count; j++) { bool enable = (conditional_version.version & (1 << j)) > 0; if (enable) { strings.push_back(conditional_defines[j]); define_line_ofs++; 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; define_line_ofs += 2; } // 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; } } glUseProgram(0); v.ok = true; if (cc) { cc->versions.insert(conditional_version.version); } return &v; }
ShaderGLES3::Version *ShaderGLES3::get_current_version() { 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) { //bye bye shaders glDeleteShader(v.vert_id); glDeleteShader(v.frag_id); glDeleteProgram(v.id); v.id = 0; } } v.ok = false; /* SETUP CONDITIONALS */ Vector<const char *> strings; #ifdef GLES_OVER_GL strings.push_back("#version 330\n"); strings.push_back("#define GLES_OVER_GL\n"); #else strings.push_back("#version 300 es\n"); #endif int define_line_ofs = 1; for (int i = 0; i < custom_defines.size(); i++) { strings.push_back(custom_defines[i].get_data()); define_line_ofs++; } for (int j = 0; j < conditional_count; j++) { bool enable = ((1 << j) & conditional_version.version); strings.push_back(enable ? conditional_defines[j] : ""); if (enable) define_line_ofs++; if (enable) { DEBUG_PRINT(conditional_defines[j]); } } //keep them around during the function CharString code_string; CharString code_string2; CharString code_globals; CharString material_string; CustomCode *cc = NULL; if (conditional_version.code_version > 0) { //do custom code related stuff ERR_FAIL_COND_V(!custom_code_map.has(conditional_version.code_version), NULL); cc = &custom_code_map[conditional_version.code_version]; v.code_version = cc->version; define_line_ofs += 2; } /* CREATE PROGRAM */ v.id = glCreateProgram(); ERR_FAIL_COND_V(v.id == 0, NULL); /* VERTEX SHADER */ if (cc) { for (int i = 0; i < cc->custom_defines.size(); i++) { strings.push_back(cc->custom_defines[i].get_data()); DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i])); } } int strings_base_size = strings.size(); //vertex precision is high strings.push_back("precision highp float;\n"); strings.push_back("precision highp int;\n"); #ifndef GLES_OVER_GL strings.push_back("precision highp sampler2D;\n"); strings.push_back("precision highp samplerCube;\n"); strings.push_back("precision highp sampler2DArray;\n"); #endif strings.push_back(vertex_code0.get_data()); if (cc) { material_string = cc->uniforms.ascii(); strings.push_back(material_string.get_data()); } strings.push_back(vertex_code1.get_data()); if (cc) { code_globals = cc->vertex_globals.ascii(); strings.push_back(code_globals.get_data()); } strings.push_back(vertex_code2.get_data()); if (cc) { code_string = cc->vertex.ascii(); strings.push_back(code_string.get_data()); } strings.push_back(vertex_code3.get_data()); #ifdef DEBUG_SHADER DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data())); for (int i = 0; i < strings.size(); i++) { //print_line("vert strings "+itos(i)+":"+String(strings[i])); } #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) { // error compiling 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("Vertex shader compilation failed with empty log"); } else { if (iloglen == 0) { iloglen = 4096; //buggy driver (Adreno 220+....) } char *ilogmem = (char *)memalloc(iloglen + 1); ilogmem[iloglen] = 0; glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem); String err_string = get_shader_name() + ": Vertex Program Compilation Failed:\n"; err_string += ilogmem; _display_error_with_code(err_string, strings); memfree(ilogmem); glDeleteShader(v.vert_id); glDeleteProgram(v.id); v.id = 0; } ERR_FAIL_V(NULL); } //_display_error_with_code("pepo", strings); /* FRAGMENT SHADER */ strings.resize(strings_base_size); //fragment precision is medium strings.push_back("precision highp float;\n"); strings.push_back("precision highp int;\n"); #ifndef GLES_OVER_GL strings.push_back("precision highp sampler2D;\n"); strings.push_back("precision highp samplerCube;\n"); strings.push_back("precision highp sampler2DArray;\n"); #endif strings.push_back(fragment_code0.get_data()); if (cc) { material_string = cc->uniforms.ascii(); strings.push_back(material_string.get_data()); } strings.push_back(fragment_code1.get_data()); if (cc) { code_globals = cc->fragment_globals.ascii(); strings.push_back(code_globals.get_data()); } strings.push_back(fragment_code2.get_data()); if (cc) { code_string = cc->light.ascii(); strings.push_back(code_string.get_data()); } strings.push_back(fragment_code3.get_data()); if (cc) { code_string2 = cc->fragment.ascii(); strings.push_back(code_string2.get_data()); } strings.push_back(fragment_code4.get_data()); #ifdef DEBUG_SHADER DEBUG_PRINT("\nFragment Globals:\n\n" + String(code_globals.get_data())); DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string2.get_data())); for (int i = 0; i < strings.size(); i++) { //print_line("frag strings "+itos(i)+":"+String(strings[i])); } #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) { // error compiling 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("Fragment shader compilation failed with empty log"); } else { if (iloglen == 0) { iloglen = 4096; //buggy driver (Adreno 220+....) } char *ilogmem = (char *)memalloc(iloglen + 1); ilogmem[iloglen] = 0; glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem); String err_string = get_shader_name() + ": Fragment Program Compilation Failed:\n"; err_string += ilogmem; _display_error_with_code(err_string, strings); ERR_PRINT(err_string.ascii().get_data()); memfree(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 attributes before linking for (int i = 0; i < attribute_pair_count; i++) { glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name); } //if feedback exists, set it up if (feedback_count) { Vector<const char *> feedback; for (int i = 0; i < feedback_count; i++) { if (feedbacks[i].conditional == -1 || (1 << feedbacks[i].conditional) & conditional_version.version) { //conditional for this feedback is enabled feedback.push_back(feedbacks[i].name); } } if (feedback.size()) { glTransformFeedbackVaryings(v.id, feedback.size(), feedback.ptr(), GL_INTERLEAVED_ATTRIBS); } } glLinkProgram(v.id); glGetProgramiv(v.id, GL_LINK_STATUS, &status); if (status == GL_FALSE) { // error linking 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_FAIL_COND_V(iloglen <= 0, 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 LINK FAILED:\n"; err_string += ilogmem; _display_error_with_code(err_string, strings); ERR_PRINT(err_string.ascii().get_data()); Memory::free_static(ilogmem); glDeleteShader(v.frag_id); glDeleteShader(v.vert_id); glDeleteProgram(v.id); v.id = 0; ERR_FAIL_V(NULL); } /* UNIFORMS */ glUseProgram(v.id); //print_line("uniforms: "); for (int j = 0; j < uniform_count; j++) { v.uniform_location[j] = glGetUniformLocation(v.id, uniform_names[j]); //print_line("uniform "+String(uniform_names[j])+" location "+itos(v.uniform_location[j])); } // set texture uniforms 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); //negative, goes down } else { glUniform1i(loc, texunit_pairs[i].index); } } } // assign uniform block bind points for (int i = 0; i < ubo_count; i++) { GLint loc = glGetUniformBlockIndex(v.id, ubo_pairs[i].name); if (loc >= 0) glUniformBlockBinding(v.id, loc, ubo_pairs[i].index); } if (cc) { v.texture_uniform_locations.resize(cc->texture_uniforms.size()); for (int i = 0; i < cc->texture_uniforms.size(); i++) { v.texture_uniform_locations.write[i] = glGetUniformLocation(v.id, String(cc->texture_uniforms[i]).ascii().get_data()); glUniform1i(v.texture_uniform_locations[i], i + base_material_tex_index); } } glUseProgram(0); v.ok = true; return &v; }