diff --git a/src/main/cpp/gl/drawing.cpp b/src/main/cpp/gl/drawing.cpp index ed0d4b0..abd778d 100644 --- a/src/main/cpp/gl/drawing.cpp +++ b/src/main/cpp/gl/drawing.cpp @@ -19,6 +19,7 @@ GLuint bufSampelerLoc; std::string bufSampelerName; extern std::unordered_map program_map_is_sampler_buffer_emulated; +extern std::unordered_map program_map_is_atomic_counter_emulated; unordered_map g_samplerCacheForSamplerBuffer; @@ -99,10 +100,6 @@ void prepareForDraw() { } } -// solve the crash error for ANGLE, but it will make Derivative Main with Optifine not work! - -//_Thread_local static bool unexpected_error = false; - void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount) { LOG() LOG_D("glDrawElementsInstanced, mode: %d, count: %d, type: %d, indices: %p, primcount: %d", @@ -116,67 +113,73 @@ void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices LOG() LOG_D("glDrawElements, mode: %d, count: %d, type: %d, indices: %p", mode, count, type, indices) prepareForDraw(); - //LOAD_GLES_FUNC(glGetError) - //GLenum pre_err = GLES.glGetError(); - //if(pre_err != GL_NO_ERROR) { - // LOG_D("Skipping due to prior error: 0x%04X", pre_err) - // return; - //} - //if (!unexpected_error) { - // LOG_D("es_glDrawElements, mode: %d, count: %d, type: %d, indices: %p", mode, count, type, indices) GLES.glDrawElements(mode, count, type, indices); CHECK_GL_ERROR - //} else { - // unexpected_error = false; - //} } void glBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) { - LOG() LOG_D("glBindImageTexture, unit: %d, texture: %d, level: %d, layered: %d, layer: %d, access: %d, format: %d", unit, texture, level, layered, layer, access, format) - //LOAD_GLES_FUNC(glGetError) GLES.glBindImageTexture(unit, texture, level, layered, layer, access, format); CHECK_GL_ERROR - //GLenum err; - //while((err = GLES.glGetError()) != GL_NO_ERROR) { - // LOG_D("GL Error: 0x%04X", err) - // unexpected_error = true; - //} } void glUniform1i(GLint location, GLint v0) { LOG() LOG_D("glUniform1i, location: %d, v0: %d", location, v0) - //LOAD_GLES_FUNC(glGetError) GLES.glUniform1i(location, v0); CHECK_GL_ERROR - //GLenum err; - //while((err = GLES.glGetError()) != GL_NO_ERROR) { - // LOG_D("GL Error: 0x%04X", err) - // unexpected_error = true; - //} +} + +void bindAllAtomicCounterAsSSBO() { + GLint maxBindings = 0; + GLES.glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &maxBindings); + if (maxBindings <= 0) { + LOG_W("No atomic counter buffer bindings available, maxBindings: %d", maxBindings); + return; + } + + std::vector buffers(maxBindings, 0); + + for (GLint i = 0; i < maxBindings; ++i) { + GLES.glGetIntegeri_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, i, reinterpret_cast(&buffers[i])); + } + + for (GLint i = 0; i < maxBindings; ++i) { + GLuint buf = buffers[i]; + if (buf != 0) { + GLES.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, buf); + } + } + + LOG_D("Bound %d atomic counter buffers as SSBOs", maxBindings); } void glDispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) { LOG() LOG_D("glDispatchCompute, num_groups_x: %d, num_groups_y: %d, num_groups_z: %d", num_groups_x, num_groups_y, num_groups_z) - //LOAD_GLES_FUNC(glGetError) - //GLenum pre_err = GLES.glGetError(); - //if(pre_err != GL_NO_ERROR) { - // LOG_D("Skipping due to prior error: 0x%04X", pre_err) - // return; - //} - //if (!unexpected_error) { - // LOG_D("es_glDispatchCompute, num_groups_x: %d, num_groups_y: %d, num_groups_z: %d", - // num_groups_x, num_groups_y, num_groups_z) + if (program_map_is_atomic_counter_emulated[gl_state->current_program]) { + bindAllAtomicCounterAsSSBO(); + LOG_D("Atomic counters bound as SSBOs for program %d", gl_state->current_program); + } + else { + LOG_D("No atomic counters bound as SSBOs for program %d", gl_state->current_program); + } GLES.glDispatchCompute(num_groups_x, num_groups_y, num_groups_z); CHECK_GL_ERROR - //} else { - // unexpected_error = false; - //} +} + +void glMemoryBarrier(GLbitfield barriers) { + LOG() + LOG_D("glMemoryBarrier, barriers: %d", barriers) + if (program_map_is_atomic_counter_emulated[gl_state->current_program]) { + barriers |= GL_ATOMIC_COUNTER_BARRIER_BIT; + barriers |= GL_SHADER_STORAGE_BARRIER_BIT; + } + GLES.glMemoryBarrier(barriers); + CHECK_GL_ERROR } void glDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex) { diff --git a/src/main/cpp/gl/drawing.h b/src/main/cpp/gl/drawing.h index 7e61613..c97ee1f 100644 --- a/src/main/cpp/gl/drawing.h +++ b/src/main/cpp/gl/drawing.h @@ -35,6 +35,7 @@ GLAPI GLAPIENTRY void glDrawElements(GLenum mode, GLsizei count, GLenum type, co GLAPI GLAPIENTRY void glBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); GLAPI GLAPIENTRY void glDispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +GLAPI GLAPIENTRY void glMemoryBarrier(GLbitfield barriers); GLAPI GLAPIENTRY void glUniform1i(GLint location, GLint v0); #ifdef __cplusplus diff --git a/src/main/cpp/gl/gl_native.cpp b/src/main/cpp/gl/gl_native.cpp index 972c01c..ca0cfbe 100644 --- a/src/main/cpp/gl/gl_native.cpp +++ b/src/main/cpp/gl/gl_native.cpp @@ -311,7 +311,7 @@ NATIVE_FUNCTION_HEAD(void, glValidateProgramPipeline, GLuint pipeline) NATIVE_FU NATIVE_FUNCTION_HEAD(void, glGetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) NATIVE_FUNCTION_END_NO_RETURN(void, glGetProgramPipelineInfoLog, pipeline,bufSize,length,infoLog) //NATIVE_FUNCTION_HEAD(void, glBindImageTexture, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) NATIVE_FUNCTION_END_NO_RETURN(void, glBindImageTexture, unit,texture,level,layered,layer,access,format) NATIVE_FUNCTION_HEAD(void, glGetBooleani_v, GLenum target, GLuint index, GLboolean *data) NATIVE_FUNCTION_END_NO_RETURN(void, glGetBooleani_v, target,index,data) -NATIVE_FUNCTION_HEAD(void, glMemoryBarrier, GLbitfield barriers) NATIVE_FUNCTION_END_NO_RETURN(void, glMemoryBarrier, barriers) +//NATIVE_FUNCTION_HEAD(void, glMemoryBarrier, GLbitfield barriers) NATIVE_FUNCTION_END_NO_RETURN(void, glMemoryBarrier, barriers) NATIVE_FUNCTION_HEAD(void, glMemoryBarrierByRegion, GLbitfield barriers) NATIVE_FUNCTION_END_NO_RETURN(void, glMemoryBarrierByRegion, barriers) NATIVE_FUNCTION_HEAD(void, glTexStorage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) NATIVE_FUNCTION_END_NO_RETURN(void, glTexStorage2DMultisample, target,samples,internalformat,width,height,fixedsamplelocations) NATIVE_FUNCTION_HEAD(void, glGetMultisamplefv, GLenum pname, GLuint index, GLfloat *val) NATIVE_FUNCTION_END_NO_RETURN(void, glGetMultisamplefv, pname,index,val) diff --git a/src/main/cpp/gl/glsl/glsl_for_es.cpp b/src/main/cpp/gl/glsl/glsl_for_es.cpp index 107cdea..88e6b1f 100644 --- a/src/main/cpp/gl/glsl/glsl_for_es.cpp +++ b/src/main/cpp/gl/glsl/glsl_for_es.cpp @@ -16,7 +16,9 @@ #include "cache.h" #include "../../version.h" -#define DEBUG 0 +#define DEBUG 0 + +const char* atomicCounterEmulatedWatermark = "\n// Non-opaque atomic uniform converted to SSBO\n"; #if !defined(__APPLE__) char* (*MesaConvertShader)(const char *src, unsigned int type, unsigned int glsl, unsigned int essl); @@ -335,33 +337,29 @@ std::string processOutColorLocations(const std::string& glslCode) { return std::regex_replace(glslCode, pattern, replacement); } -std::string getCachedESSL(const char* glsl_code, uint essl_version) { - std::string sha256_string(glsl_code); - sha256_string += "\n//" + std::to_string(MAJOR) + "." + std::to_string(MINOR) + "." + std::to_string(REVISION) + "|" + std::to_string(essl_version); - const char* cachedESSL = Cache::get_instance().get(sha256_string.c_str()); - if (cachedESSL) { - LOG_D("GLSL Hit Cache:\n%s\n-->\n%s", glsl_code, cachedESSL) - return cachedESSL; - } else return ""; +bool checkIfAtomicCounterBufferEmulated(const std::string& glslCode) { + return glslCode.find(atomicCounterEmulatedWatermark) != std::string::npos; } -std::string GLSLtoGLSLES(const char* glsl_code, GLenum glsl_type, uint essl_version, uint glsl_version) { +std::string GLSLtoGLSLES(const char* glsl_code, GLenum glsl_type, uint essl_version, uint glsl_version, int& return_code) { std::string sha256_string(glsl_code); sha256_string += "\n//" + std::to_string(MAJOR) + "." + std::to_string(MINOR) + "." + std::to_string(REVISION) + "|" + std::to_string(essl_version); const char* cachedESSL = Cache::get_instance().get(sha256_string.c_str()); if (cachedESSL) { LOG_D("GLSL Hit Cache:\n%s\n-->\n%s", glsl_code, cachedESSL) + bool atomicCounterEmulated = checkIfAtomicCounterBufferEmulated(std::string(cachedESSL)); + return_code = atomicCounterEmulated ? 1 : 0; return (char*)cachedESSL; } - int return_code = -1; + return_code = -1; std::string converted = glsl_version<140? GLSLtoGLSLES_1(glsl_code, glsl_type, essl_version, return_code):GLSLtoGLSLES_2(glsl_code, glsl_type, essl_version, return_code); - if (return_code == 0 && !converted.empty()) { + if (return_code >= 0 && !converted.empty()) { converted = process_uniform_declarations(converted); Cache::get_instance().put(sha256_string.c_str(), converted.c_str()); } - return (return_code == 0) ? converted : glsl_code; + return (return_code >= 0) ? converted : glsl_code; } std::string replace_line_starting_with(const std::string& glslCode, const std::string& starting, const std::string& substitution = "") { @@ -487,6 +485,70 @@ static size_t find_insertion_point(const std::string& glsl) { return insertion_point; } +bool process_non_opaque_atomic_to_ssbo(std::string& source) { + if (source.find("atomicCounter") == std::string::npos) return false; + + std::set atomic_vars; + std::map binding_map; + std::regex decl_rx( + R"(layout\s*\(\s*binding\s*=\s*(\d+)\s*(?:,\s*offset\s*=\s*(\d+)\s*)?\)\s*uniform\s+atomic_uint\s+(\w+)\s*;)", + std::regex::icase + ); + + std::smatch m; + auto it = source.cbegin(); + while (std::regex_search(it, source.cend(), m, decl_rx)) { + size_t prefix = std::distance(source.cbegin(), it); + size_t match_pos = prefix + m.position(0); + size_t match_len = m.length(0); + + std::string binding = m[1].str(); + std::string var = m[3].str(); + atomic_vars.insert(var); + binding_map[var] = binding; + + std::string repl = + "layout(std430, binding=" + binding + ") buffer AtomicCounterSSBO_" + binding + " {\n" + " uint " + var + ";\n" + "};\n"; + source.replace(match_pos, match_len, repl); + + it = source.cbegin() + match_pos + repl.size(); + } + + if (atomic_vars.empty()) return true; + + for (auto& var : atomic_vars) { + source = std::regex_replace(source, + std::regex(R"(\batomicCounterIncrement\s*\(\s*)" + var + R"(\s*\))", std::regex::icase), + "atomicAdd(" + var + ", 1u)" + ); + source = std::regex_replace(source, + std::regex(R"(\batomicCounterDecrement\s*\(\s*)" + var + R"(\s*\))", std::regex::icase), + "atomicAdd(" + var + ", uint(-1))" + ); + source = std::regex_replace(source, + std::regex(R"(\batomicCounterAdd\s*\(\s*)" + var + R"(\s*,\s*([^)]+)\s*\))", std::regex::icase), + "atomicAdd(" + var + ", $1)" + ); + source = std::regex_replace(source, + std::regex(R"(\batomicCounter\s*\(\s*)" + var + R"(\s*\))", std::regex::icase), + var + ); + } + + { + std::regex rx_barrier(R"(\batomicAdd\s*\([^;]*\);)"); + source = std::regex_replace(source, + rx_barrier, + "$&\n memoryBarrierBuffer();" + ); + } + + source += atomicCounterEmulatedWatermark; + return true; +} + void process_sampler_buffer(std::string& source) { // a simplized version, should be rewritten in the future if (source.find("isamplerBuffer") == std::string::npos) { return; @@ -636,8 +698,7 @@ void inject_mg_macro_definition(std::string& glslCode) { glslCode.insert(insertionPos, macro_definitions); } - -std::string preprocess_glsl(const std::string& glsl, GLenum shaderType) { +std::string preprocess_glsl(const std::string& glsl, GLenum shaderType, bool* atomicCounterEmulated) { std::string ret = glsl; // Remove lines beginning with `#line` ret = replace_line_starting_with(ret, "#line"); @@ -666,6 +727,7 @@ std::string preprocess_glsl(const std::string& glsl, GLenum shaderType) { process_sampler_buffer(ret); } + *atomicCounterEmulated = process_non_opaque_atomic_to_ssbo(ret); return ret; } @@ -783,7 +845,8 @@ std::string spirv_to_essl(std::vector spirv, uint essl_version, in static bool glslang_inited = false; std::string GLSLtoGLSLES_2(const char *glsl_code, GLenum glsl_type, uint essl_version, int& return_code) { - std::string correct_glsl_str = preprocess_glsl(glsl_code, glsl_type); + bool atomicCounterEmulated = false; + std::string correct_glsl_str = preprocess_glsl(glsl_code, glsl_type, &atomicCounterEmulated); LOG_D("Firstly converted GLSL:\n%s", correct_glsl_str.c_str()) int glsl_version = get_or_add_glsl_version(correct_glsl_str); @@ -814,8 +877,10 @@ std::string GLSLtoGLSLES_2(const char *glsl_code, GLenum glsl_type, uint essl_ve essl = forceSupporterOutput(essl); LOG_D("Originally GLSL to GLSL ES Complete: \n%s", essl.c_str()) - return_code = errc; + if (return_code == 0) { + return_code = atomicCounterEmulated ? 1 : 0; + } return essl; } diff --git a/src/main/cpp/gl/glsl/glsl_for_es.h b/src/main/cpp/gl/glsl/glsl_for_es.h index 4e8f585..3df9afc 100644 --- a/src/main/cpp/gl/glsl/glsl_for_es.h +++ b/src/main/cpp/gl/glsl/glsl_for_es.h @@ -16,8 +16,7 @@ extern "C" { } #endif -std::string getCachedESSL(const char* glsl_code, uint essl_version); -std::string GLSLtoGLSLES(const char *glsl_code, GLenum glsl_type, uint esversion, uint glsl_version); +std::string GLSLtoGLSLES(const char* glsl_code, GLenum glsl_type, uint essl_version, uint glsl_version, int& return_code); std::string GLSLtoGLSLES_1(const char *glsl_code, GLenum glsl_type, uint esversion, int& return_code); std::string GLSLtoGLSLES_2(const char *glsl_code, GLenum glsl_type, uint essl_version, int& return_code); int getGLSLVersion(const char* glsl_code); diff --git a/src/main/cpp/gl/program.cpp b/src/main/cpp/gl/program.cpp index 9c3a4e0..b3e6687 100644 --- a/src/main/cpp/gl/program.cpp +++ b/src/main/cpp/gl/program.cpp @@ -18,6 +18,9 @@ extern std::unordered_map shader_map_is_sampler_buffer_emulated; std::unordered_map program_map_is_sampler_buffer_emulated; +extern std::unordered_map shader_map_is_atomic_counter_emulated; +std::unordered_map program_map_is_atomic_counter_emulated; + char* updateLayoutLocation(const char* esslSource, GLuint color, const char* name) { std::string shaderCode(esslSource); @@ -142,6 +145,10 @@ void glAttachShader(GLuint program, GLuint shader) { LOG_D("glAttachShader(%u, %u)", program, shader) if (hardware->emulate_texture_buffer && shader_map_is_sampler_buffer_emulated[shader]) program_map_is_sampler_buffer_emulated[program] = true; + if (shader_map_is_atomic_counter_emulated[shader]) { + program_map_is_atomic_counter_emulated[program] = true; + LOG_D("Shader %d is atomic counter emulated, setting program %d to atomic counter emulated", shader, program) + } GLES.glAttachShader(program, shader); CHECK_GL_ERROR diff --git a/src/main/cpp/gl/shader.cpp b/src/main/cpp/gl/shader.cpp index 0da65f4..37cd978 100644 --- a/src/main/cpp/gl/shader.cpp +++ b/src/main/cpp/gl/shader.cpp @@ -19,6 +19,7 @@ struct shader_t shaderInfo; std::unordered_map shader_map_is_sampler_buffer_emulated; +std::unordered_map shader_map_is_atomic_counter_emulated; bool can_run_essl3(unsigned int esversion, const char *glsl) { if (strncmp(glsl, "#version 100", 12) == 0) { @@ -83,9 +84,13 @@ void glShaderSource(GLuint shader, GLsizei count, const GLchar *const* string, c LOG_D("%s", glsl_src.c_str()) GLint shaderType; GLES.glGetShaderiv(shader, GL_SHADER_TYPE, &shaderType); - essl_src = getCachedESSL(glsl_src.c_str(), hardware->es_version); - if (essl_src.empty()) - essl_src = GLSLtoGLSLES(glsl_src.c_str(), shaderType, hardware->es_version, glsl_version); + int return_code = 0; + essl_src = GLSLtoGLSLES(glsl_src.c_str(), shaderType, hardware->es_version, glsl_version, return_code); + if (return_code == 1) { //atomicCounterEmulated + shader_map_is_atomic_counter_emulated[shader] = true; + LOG_D("[INFO] [Shader] Atomic counter emulated in shader %d", shader) + } + if (essl_src.empty()) { LOG_E("Failed to convert shader %d.", shader) return;