|
16 | 16 | #include "cache.h" |
17 | 17 | #include "../../version.h" |
18 | 18 |
|
19 | | -#define DEBUG 0 |
| 19 | +#define DEBUG 0 |
| 20 | + |
| 21 | +const char* atomicCounterEmulatedWatermark = "\n// Non-opaque atomic uniform converted to SSBO\n"; |
20 | 22 |
|
21 | 23 | #if !defined(__APPLE__) |
22 | 24 | 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) { |
335 | 337 | return std::regex_replace(glslCode, pattern, replacement); |
336 | 338 | } |
337 | 339 |
|
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; |
346 | 342 | } |
347 | 343 |
|
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) { |
349 | 345 | std::string sha256_string(glsl_code); |
350 | 346 | sha256_string += "\n//" + std::to_string(MAJOR) + "." + std::to_string(MINOR) + "." + std::to_string(REVISION) + "|" + std::to_string(essl_version); |
351 | 347 | const char* cachedESSL = Cache::get_instance().get(sha256_string.c_str()); |
352 | 348 | if (cachedESSL) { |
353 | 349 | 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; |
354 | 352 | return (char*)cachedESSL; |
355 | 353 | } |
356 | 354 |
|
357 | | - int return_code = -1; |
| 355 | + return_code = -1; |
358 | 356 | 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()) { |
360 | 358 | converted = process_uniform_declarations(converted); |
361 | 359 | Cache::get_instance().put(sha256_string.c_str(), converted.c_str()); |
362 | 360 | } |
363 | 361 |
|
364 | | - return (return_code == 0) ? converted : glsl_code; |
| 362 | + return (return_code >= 0) ? converted : glsl_code; |
365 | 363 | } |
366 | 364 |
|
367 | 365 | 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) { |
487 | 485 | return insertion_point; |
488 | 486 | } |
489 | 487 |
|
| 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 | + |
490 | 552 | void process_sampler_buffer(std::string& source) { // a simplized version, should be rewritten in the future |
491 | 553 | if (source.find("isamplerBuffer") == std::string::npos) { |
492 | 554 | return; |
@@ -636,8 +698,7 @@ void inject_mg_macro_definition(std::string& glslCode) { |
636 | 698 | glslCode.insert(insertionPos, macro_definitions); |
637 | 699 | } |
638 | 700 |
|
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) { |
641 | 702 | std::string ret = glsl; |
642 | 703 | // Remove lines beginning with `#line` |
643 | 704 | ret = replace_line_starting_with(ret, "#line"); |
@@ -666,6 +727,7 @@ std::string preprocess_glsl(const std::string& glsl, GLenum shaderType) { |
666 | 727 | process_sampler_buffer(ret); |
667 | 728 | } |
668 | 729 |
|
| 730 | + *atomicCounterEmulated = process_non_opaque_atomic_to_ssbo(ret); |
669 | 731 | return ret; |
670 | 732 | } |
671 | 733 |
|
@@ -783,7 +845,8 @@ std::string spirv_to_essl(std::vector<unsigned int> spirv, uint essl_version, in |
783 | 845 |
|
784 | 846 | static bool glslang_inited = false; |
785 | 847 | 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); |
787 | 850 | LOG_D("Firstly converted GLSL:\n%s", correct_glsl_str.c_str()) |
788 | 851 | int glsl_version = get_or_add_glsl_version(correct_glsl_str); |
789 | 852 |
|
@@ -814,8 +877,10 @@ std::string GLSLtoGLSLES_2(const char *glsl_code, GLenum glsl_type, uint essl_ve |
814 | 877 | essl = forceSupporterOutput(essl); |
815 | 878 |
|
816 | 879 | LOG_D("Originally GLSL to GLSL ES Complete: \n%s", essl.c_str()) |
817 | | - |
818 | 880 | return_code = errc; |
| 881 | + if (return_code == 0) { |
| 882 | + return_code = atomicCounterEmulated ? 1 : 0; |
| 883 | + } |
819 | 884 | return essl; |
820 | 885 | } |
821 | 886 |
|
|
0 commit comments