Skip to content

Commit a2b4aa6

Browse files
committed
[Feat] (Shader): Emulate atomicCounter advanced operations.
1 parent cea5d7a commit a2b4aa6

7 files changed

Lines changed: 143 additions & 63 deletions

File tree

src/main/cpp/gl/drawing.cpp

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ GLuint bufSampelerLoc;
1919
std::string bufSampelerName;
2020

2121
extern std::unordered_map<GLuint, bool> program_map_is_sampler_buffer_emulated;
22+
extern std::unordered_map<GLuint, bool> program_map_is_atomic_counter_emulated;
2223

2324
unordered_map<GLuint, SamplerInfo> g_samplerCacheForSamplerBuffer;
2425

@@ -99,10 +100,6 @@ void prepareForDraw() {
99100
}
100101
}
101102

102-
// solve the crash error for ANGLE, but it will make Derivative Main with Optifine not work!
103-
104-
//_Thread_local static bool unexpected_error = false;
105-
106103
void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount) {
107104
LOG()
108105
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
116113
LOG()
117114
LOG_D("glDrawElements, mode: %d, count: %d, type: %d, indices: %p", mode, count, type, indices)
118115
prepareForDraw();
119-
//LOAD_GLES_FUNC(glGetError)
120-
//GLenum pre_err = GLES.glGetError();
121-
//if(pre_err != GL_NO_ERROR) {
122-
// LOG_D("Skipping due to prior error: 0x%04X", pre_err)
123-
// return;
124-
//}
125-
//if (!unexpected_error) {
126-
// LOG_D("es_glDrawElements, mode: %d, count: %d, type: %d, indices: %p", mode, count, type, indices)
127116
GLES.glDrawElements(mode, count, type, indices);
128117
CHECK_GL_ERROR
129-
//} else {
130-
// unexpected_error = false;
131-
//}
132118
}
133119

134120
void glBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) {
135-
136121
LOG()
137122
LOG_D("glBindImageTexture, unit: %d, texture: %d, level: %d, layered: %d, layer: %d, access: %d, format: %d",
138123
unit, texture, level, layered, layer, access, format)
139-
//LOAD_GLES_FUNC(glGetError)
140124
GLES.glBindImageTexture(unit, texture, level, layered, layer, access, format);
141125
CHECK_GL_ERROR
142-
//GLenum err;
143-
//while((err = GLES.glGetError()) != GL_NO_ERROR) {
144-
// LOG_D("GL Error: 0x%04X", err)
145-
// unexpected_error = true;
146-
//}
147126
}
148127

149128
void glUniform1i(GLint location, GLint v0) {
150129
LOG()
151130
LOG_D("glUniform1i, location: %d, v0: %d", location, v0)
152-
//LOAD_GLES_FUNC(glGetError)
153131
GLES.glUniform1i(location, v0);
154132
CHECK_GL_ERROR
155-
//GLenum err;
156-
//while((err = GLES.glGetError()) != GL_NO_ERROR) {
157-
// LOG_D("GL Error: 0x%04X", err)
158-
// unexpected_error = true;
159-
//}
133+
}
134+
135+
void bindAllAtomicCounterAsSSBO() {
136+
GLint maxBindings = 0;
137+
GLES.glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &maxBindings);
138+
if (maxBindings <= 0) {
139+
LOG_W("No atomic counter buffer bindings available, maxBindings: %d", maxBindings);
140+
return;
141+
}
142+
143+
std::vector<GLuint> buffers(maxBindings, 0);
144+
145+
for (GLint i = 0; i < maxBindings; ++i) {
146+
GLES.glGetIntegeri_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, i, reinterpret_cast<GLint*>(&buffers[i]));
147+
}
148+
149+
for (GLint i = 0; i < maxBindings; ++i) {
150+
GLuint buf = buffers[i];
151+
if (buf != 0) {
152+
GLES.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, buf);
153+
}
154+
}
155+
156+
LOG_D("Bound %d atomic counter buffers as SSBOs", maxBindings);
160157
}
161158

162159
void glDispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) {
163160
LOG()
164161
LOG_D("glDispatchCompute, num_groups_x: %d, num_groups_y: %d, num_groups_z: %d",
165162
num_groups_x, num_groups_y, num_groups_z)
166-
//LOAD_GLES_FUNC(glGetError)
167-
//GLenum pre_err = GLES.glGetError();
168-
//if(pre_err != GL_NO_ERROR) {
169-
// LOG_D("Skipping due to prior error: 0x%04X", pre_err)
170-
// return;
171-
//}
172-
//if (!unexpected_error) {
173-
// LOG_D("es_glDispatchCompute, num_groups_x: %d, num_groups_y: %d, num_groups_z: %d",
174-
// num_groups_x, num_groups_y, num_groups_z)
163+
if (program_map_is_atomic_counter_emulated[gl_state->current_program]) {
164+
bindAllAtomicCounterAsSSBO();
165+
LOG_D("Atomic counters bound as SSBOs for program %d", gl_state->current_program);
166+
}
167+
else {
168+
LOG_D("No atomic counters bound as SSBOs for program %d", gl_state->current_program);
169+
}
175170
GLES.glDispatchCompute(num_groups_x, num_groups_y, num_groups_z);
176171
CHECK_GL_ERROR
177-
//} else {
178-
// unexpected_error = false;
179-
//}
172+
}
173+
174+
void glMemoryBarrier(GLbitfield barriers) {
175+
LOG()
176+
LOG_D("glMemoryBarrier, barriers: %d", barriers)
177+
if (program_map_is_atomic_counter_emulated[gl_state->current_program]) {
178+
barriers |= GL_ATOMIC_COUNTER_BARRIER_BIT;
179+
barriers |= GL_SHADER_STORAGE_BARRIER_BIT;
180+
}
181+
GLES.glMemoryBarrier(barriers);
182+
CHECK_GL_ERROR
180183
}
181184

182185
void glDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex) {

src/main/cpp/gl/drawing.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ GLAPI GLAPIENTRY void glDrawElements(GLenum mode, GLsizei count, GLenum type, co
3535

3636
GLAPI GLAPIENTRY void glBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
3737
GLAPI GLAPIENTRY void glDispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
38+
GLAPI GLAPIENTRY void glMemoryBarrier(GLbitfield barriers);
3839
GLAPI GLAPIENTRY void glUniform1i(GLint location, GLint v0);
3940

4041
#ifdef __cplusplus

src/main/cpp/gl/gl_native.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ NATIVE_FUNCTION_HEAD(void, glValidateProgramPipeline, GLuint pipeline) NATIVE_FU
311311
NATIVE_FUNCTION_HEAD(void, glGetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) NATIVE_FUNCTION_END_NO_RETURN(void, glGetProgramPipelineInfoLog, pipeline,bufSize,length,infoLog)
312312
//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)
313313
NATIVE_FUNCTION_HEAD(void, glGetBooleani_v, GLenum target, GLuint index, GLboolean *data) NATIVE_FUNCTION_END_NO_RETURN(void, glGetBooleani_v, target,index,data)
314-
NATIVE_FUNCTION_HEAD(void, glMemoryBarrier, GLbitfield barriers) NATIVE_FUNCTION_END_NO_RETURN(void, glMemoryBarrier, barriers)
314+
//NATIVE_FUNCTION_HEAD(void, glMemoryBarrier, GLbitfield barriers) NATIVE_FUNCTION_END_NO_RETURN(void, glMemoryBarrier, barriers)
315315
NATIVE_FUNCTION_HEAD(void, glMemoryBarrierByRegion, GLbitfield barriers) NATIVE_FUNCTION_END_NO_RETURN(void, glMemoryBarrierByRegion, barriers)
316316
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)
317317
NATIVE_FUNCTION_HEAD(void, glGetMultisamplefv, GLenum pname, GLuint index, GLfloat *val) NATIVE_FUNCTION_END_NO_RETURN(void, glGetMultisamplefv, pname,index,val)

src/main/cpp/gl/glsl/glsl_for_es.cpp

Lines changed: 82 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
#include "cache.h"
1717
#include "../../version.h"
1818

19-
#define DEBUG 0
19+
#define DEBUG 0
20+
21+
const char* atomicCounterEmulatedWatermark = "\n// Non-opaque atomic uniform converted to SSBO\n";
2022

2123
#if !defined(__APPLE__)
2224
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) {
335337
return std::regex_replace(glslCode, pattern, replacement);
336338
}
337339

338-
std::string getCachedESSL(const char* glsl_code, uint essl_version) {
339-
std::string sha256_string(glsl_code);
340-
sha256_string += "\n//" + std::to_string(MAJOR) + "." + std::to_string(MINOR) + "." + std::to_string(REVISION) + "|" + std::to_string(essl_version);
341-
const char* cachedESSL = Cache::get_instance().get(sha256_string.c_str());
342-
if (cachedESSL) {
343-
LOG_D("GLSL Hit Cache:\n%s\n-->\n%s", glsl_code, cachedESSL)
344-
return cachedESSL;
345-
} else return "";
340+
bool checkIfAtomicCounterBufferEmulated(const std::string& glslCode) {
341+
return glslCode.find(atomicCounterEmulatedWatermark) != std::string::npos;
346342
}
347343

348-
std::string GLSLtoGLSLES(const char* glsl_code, GLenum glsl_type, uint essl_version, uint glsl_version) {
344+
std::string GLSLtoGLSLES(const char* glsl_code, GLenum glsl_type, uint essl_version, uint glsl_version, int& return_code) {
349345
std::string sha256_string(glsl_code);
350346
sha256_string += "\n//" + std::to_string(MAJOR) + "." + std::to_string(MINOR) + "." + std::to_string(REVISION) + "|" + std::to_string(essl_version);
351347
const char* cachedESSL = Cache::get_instance().get(sha256_string.c_str());
352348
if (cachedESSL) {
353349
LOG_D("GLSL Hit Cache:\n%s\n-->\n%s", glsl_code, cachedESSL)
350+
bool atomicCounterEmulated = checkIfAtomicCounterBufferEmulated(std::string(cachedESSL));
351+
return_code = atomicCounterEmulated ? 1 : 0;
354352
return (char*)cachedESSL;
355353
}
356354

357-
int return_code = -1;
355+
return_code = -1;
358356
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);
359-
if (return_code == 0 && !converted.empty()) {
357+
if (return_code >= 0 && !converted.empty()) {
360358
converted = process_uniform_declarations(converted);
361359
Cache::get_instance().put(sha256_string.c_str(), converted.c_str());
362360
}
363361

364-
return (return_code == 0) ? converted : glsl_code;
362+
return (return_code >= 0) ? converted : glsl_code;
365363
}
366364

367365
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) {
487485
return insertion_point;
488486
}
489487

488+
bool process_non_opaque_atomic_to_ssbo(std::string& source) {
489+
if (source.find("atomicCounter") == std::string::npos) return false;
490+
491+
std::set<std::string> atomic_vars;
492+
std::map<std::string, std::string> binding_map;
493+
std::regex decl_rx(
494+
R"(layout\s*\(\s*binding\s*=\s*(\d+)\s*(?:,\s*offset\s*=\s*(\d+)\s*)?\)\s*uniform\s+atomic_uint\s+(\w+)\s*;)",
495+
std::regex::icase
496+
);
497+
498+
std::smatch m;
499+
auto it = source.cbegin();
500+
while (std::regex_search(it, source.cend(), m, decl_rx)) {
501+
size_t prefix = std::distance(source.cbegin(), it);
502+
size_t match_pos = prefix + m.position(0);
503+
size_t match_len = m.length(0);
504+
505+
std::string binding = m[1].str();
506+
std::string var = m[3].str();
507+
atomic_vars.insert(var);
508+
binding_map[var] = binding;
509+
510+
std::string repl =
511+
"layout(std430, binding=" + binding + ") buffer AtomicCounterSSBO_" + binding + " {\n"
512+
" uint " + var + ";\n"
513+
"};\n";
514+
source.replace(match_pos, match_len, repl);
515+
516+
it = source.cbegin() + match_pos + repl.size();
517+
}
518+
519+
if (atomic_vars.empty()) return true;
520+
521+
for (auto& var : atomic_vars) {
522+
source = std::regex_replace(source,
523+
std::regex(R"(\batomicCounterIncrement\s*\(\s*)" + var + R"(\s*\))", std::regex::icase),
524+
"atomicAdd(" + var + ", 1u)"
525+
);
526+
source = std::regex_replace(source,
527+
std::regex(R"(\batomicCounterDecrement\s*\(\s*)" + var + R"(\s*\))", std::regex::icase),
528+
"atomicAdd(" + var + ", uint(-1))"
529+
);
530+
source = std::regex_replace(source,
531+
std::regex(R"(\batomicCounterAdd\s*\(\s*)" + var + R"(\s*,\s*([^)]+)\s*\))", std::regex::icase),
532+
"atomicAdd(" + var + ", $1)"
533+
);
534+
source = std::regex_replace(source,
535+
std::regex(R"(\batomicCounter\s*\(\s*)" + var + R"(\s*\))", std::regex::icase),
536+
var
537+
);
538+
}
539+
540+
{
541+
std::regex rx_barrier(R"(\batomicAdd\s*\([^;]*\);)");
542+
source = std::regex_replace(source,
543+
rx_barrier,
544+
"$&\n memoryBarrierBuffer();"
545+
);
546+
}
547+
548+
source += atomicCounterEmulatedWatermark;
549+
return true;
550+
}
551+
490552
void process_sampler_buffer(std::string& source) { // a simplized version, should be rewritten in the future
491553
if (source.find("isamplerBuffer") == std::string::npos) {
492554
return;
@@ -636,8 +698,7 @@ void inject_mg_macro_definition(std::string& glslCode) {
636698
glslCode.insert(insertionPos, macro_definitions);
637699
}
638700

639-
640-
std::string preprocess_glsl(const std::string& glsl, GLenum shaderType) {
701+
std::string preprocess_glsl(const std::string& glsl, GLenum shaderType, bool* atomicCounterEmulated) {
641702
std::string ret = glsl;
642703
// Remove lines beginning with `#line`
643704
ret = replace_line_starting_with(ret, "#line");
@@ -666,6 +727,7 @@ std::string preprocess_glsl(const std::string& glsl, GLenum shaderType) {
666727
process_sampler_buffer(ret);
667728
}
668729

730+
*atomicCounterEmulated = process_non_opaque_atomic_to_ssbo(ret);
669731
return ret;
670732
}
671733

@@ -783,7 +845,8 @@ std::string spirv_to_essl(std::vector<unsigned int> spirv, uint essl_version, in
783845

784846
static bool glslang_inited = false;
785847
std::string GLSLtoGLSLES_2(const char *glsl_code, GLenum glsl_type, uint essl_version, int& return_code) {
786-
std::string correct_glsl_str = preprocess_glsl(glsl_code, glsl_type);
848+
bool atomicCounterEmulated = false;
849+
std::string correct_glsl_str = preprocess_glsl(glsl_code, glsl_type, &atomicCounterEmulated);
787850
LOG_D("Firstly converted GLSL:\n%s", correct_glsl_str.c_str())
788851
int glsl_version = get_or_add_glsl_version(correct_glsl_str);
789852

@@ -814,8 +877,10 @@ std::string GLSLtoGLSLES_2(const char *glsl_code, GLenum glsl_type, uint essl_ve
814877
essl = forceSupporterOutput(essl);
815878

816879
LOG_D("Originally GLSL to GLSL ES Complete: \n%s", essl.c_str())
817-
818880
return_code = errc;
881+
if (return_code == 0) {
882+
return_code = atomicCounterEmulated ? 1 : 0;
883+
}
819884
return essl;
820885
}
821886

src/main/cpp/gl/glsl/glsl_for_es.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ extern "C" {
1616
}
1717
#endif
1818

19-
std::string getCachedESSL(const char* glsl_code, uint essl_version);
20-
std::string GLSLtoGLSLES(const char *glsl_code, GLenum glsl_type, uint esversion, uint glsl_version);
19+
std::string GLSLtoGLSLES(const char* glsl_code, GLenum glsl_type, uint essl_version, uint glsl_version, int& return_code);
2120
std::string GLSLtoGLSLES_1(const char *glsl_code, GLenum glsl_type, uint esversion, int& return_code);
2221
std::string GLSLtoGLSLES_2(const char *glsl_code, GLenum glsl_type, uint essl_version, int& return_code);
2322
int getGLSLVersion(const char* glsl_code);

src/main/cpp/gl/program.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
extern std::unordered_map<GLuint, bool> shader_map_is_sampler_buffer_emulated;
1919
std::unordered_map<GLuint, bool> program_map_is_sampler_buffer_emulated;
2020

21+
extern std::unordered_map<GLuint, bool> shader_map_is_atomic_counter_emulated;
22+
std::unordered_map<GLuint, bool> program_map_is_atomic_counter_emulated;
23+
2124
char* updateLayoutLocation(const char* esslSource, GLuint color, const char* name) {
2225
std::string shaderCode(esslSource);
2326

@@ -142,6 +145,10 @@ void glAttachShader(GLuint program, GLuint shader) {
142145
LOG_D("glAttachShader(%u, %u)", program, shader)
143146
if (hardware->emulate_texture_buffer && shader_map_is_sampler_buffer_emulated[shader])
144147
program_map_is_sampler_buffer_emulated[program] = true;
148+
if (shader_map_is_atomic_counter_emulated[shader]) {
149+
program_map_is_atomic_counter_emulated[program] = true;
150+
LOG_D("Shader %d is atomic counter emulated, setting program %d to atomic counter emulated", shader, program)
151+
}
145152

146153
GLES.glAttachShader(program, shader);
147154
CHECK_GL_ERROR

src/main/cpp/gl/shader.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
struct shader_t shaderInfo;
2020

2121
std::unordered_map<GLuint, bool> shader_map_is_sampler_buffer_emulated;
22+
std::unordered_map<GLuint, bool> shader_map_is_atomic_counter_emulated;
2223

2324
bool can_run_essl3(unsigned int esversion, const char *glsl) {
2425
if (strncmp(glsl, "#version 100", 12) == 0) {
@@ -83,9 +84,13 @@ void glShaderSource(GLuint shader, GLsizei count, const GLchar *const* string, c
8384
LOG_D("%s", glsl_src.c_str())
8485
GLint shaderType;
8586
GLES.glGetShaderiv(shader, GL_SHADER_TYPE, &shaderType);
86-
essl_src = getCachedESSL(glsl_src.c_str(), hardware->es_version);
87-
if (essl_src.empty())
88-
essl_src = GLSLtoGLSLES(glsl_src.c_str(), shaderType, hardware->es_version, glsl_version);
87+
int return_code = 0;
88+
essl_src = GLSLtoGLSLES(glsl_src.c_str(), shaderType, hardware->es_version, glsl_version, return_code);
89+
if (return_code == 1) { //atomicCounterEmulated
90+
shader_map_is_atomic_counter_emulated[shader] = true;
91+
LOG_D("[INFO] [Shader] Atomic counter emulated in shader %d", shader)
92+
}
93+
8994
if (essl_src.empty()) {
9095
LOG_E("Failed to convert shader %d.", shader)
9196
return;

0 commit comments

Comments
 (0)