diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 0da690e9..56d66194 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include "../glslang/OSDependent/osinclude.h" @@ -150,13 +152,6 @@ void ProcessConfigFile() delete[] config; } -// thread-safe list of shaders to asynchronously grab and compile -glslang::TWorklist Worklist; - -// array of unique places to leave the shader names and infologs for the asynchronous compiles -glslang::TWorkItem** Work = 0; -int NumWorkItems = 0; - int Options = 0; const char* ExecutableName = nullptr; const char* binaryFileName = nullptr; @@ -253,7 +248,7 @@ void ProcessBindingBase(int& argc, char**& argv, std::array>& workItems, int argc, char* argv[]) { baseSamplerBinding.fill(0); baseTextureBinding.fill(0); @@ -262,10 +257,7 @@ void ProcessArguments(int argc, char* argv[]) baseSsboBinding.fill(0); ExecutableName = argv[0]; - NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0 - Work = new glslang::TWorkItem*[NumWorkItems]; - for (int w = 0; w < NumWorkItems; ++w) - Work[w] = 0; + workItems.reserve(argc); argc--; argv++; @@ -420,9 +412,7 @@ void ProcessArguments(int argc, char* argv[]) Options |= EOptionSuppressInfolog; break; case 't': - #ifdef _WIN32 - Options |= EOptionMultiThreaded; - #endif + Options |= EOptionMultiThreaded; break; case 'v': Options |= EOptionDumpVersions; @@ -440,8 +430,7 @@ void ProcessArguments(int argc, char* argv[]) } else { std::string name(argv[0]); if (! SetConfigFile(name)) { - Work[argc] = new glslang::TWorkItem(name); - Worklist.add(Work[argc]); + workItems.push_back(std::unique_ptr(new glslang::TWorkItem(name))); } } } @@ -487,15 +476,13 @@ void SetMessageOptions(EShMessages& messages) // // Thread entry point, for non-linking asynchronous mode. // -// Return 0 for failure, 1 for success. -// -unsigned int CompileShaders(void*) +void CompileShaders(glslang::TWorklist& worklist) { glslang::TWorkItem* workItem; - while (Worklist.remove(workItem)) { + while (worklist.remove(workItem)) { ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options); if (compiler == 0) - return 0; + return; CompileFile(workItem->name.c_str(), compiler); @@ -504,8 +491,6 @@ unsigned int CompileShaders(void*) ShDestruct(compiler); } - - return 0; } // Outputs the given string, but only if it is non-null and non-empty. @@ -705,7 +690,7 @@ void CompileAndLinkShaderUnits(std::vector compUnits) // performance and memory testing, the actual compile/link can be put in // a loop, independent of processing the work items and file IO. // -void CompileAndLinkShaderFiles() +void CompileAndLinkShaderFiles(glslang::TWorklist& Worklist) { std::vector compUnits; @@ -747,11 +732,19 @@ void CompileAndLinkShaderFiles() int C_DECL main(int argc, char* argv[]) { - ProcessArguments(argc, argv); + // array of unique places to leave the shader names and infologs for the asynchronous compiles + std::vector> workItems; + ProcessArguments(workItems, argc, argv); + + glslang::TWorklist workList; + std::for_each(workItems.begin(), workItems.end(), [&workList](std::unique_ptr& item) { + assert(item); + workList.add(item.get()); + }); if (Options & EOptionDumpConfig) { printf("%s", glslang::GetDefaultTBuiltInResourceString().c_str()); - if (Worklist.empty()) + if (workList.empty()) return ESuccess; } @@ -766,11 +759,11 @@ int C_DECL main(int argc, char* argv[]) printf("Khronos Tool ID %d\n", glslang::GetKhronosToolId()); printf("GL_KHR_vulkan_glsl version %d\n", 100); printf("ARB_GL_gl_spirv version %d\n", 100); - if (Worklist.empty()) + if (workList.empty()) return ESuccess; } - if (Worklist.empty()) { + if (workList.empty()) { usage(); } @@ -784,47 +777,42 @@ int C_DECL main(int argc, char* argv[]) if (Options & EOptionLinkProgram || Options & EOptionOutputPreprocessed) { glslang::InitializeProcess(); - CompileAndLinkShaderFiles(); + CompileAndLinkShaderFiles(workList); glslang::FinalizeProcess(); - for (int w = 0; w < NumWorkItems; ++w) { - if (Work[w]) { - delete Work[w]; - } - } } else { ShInitialize(); - bool printShaderNames = Worklist.size() > 1; + bool printShaderNames = workList.size() > 1; - if (Options & EOptionMultiThreaded) { - const int NumThreads = 16; - void* threads[NumThreads]; - for (int t = 0; t < NumThreads; ++t) { - threads[t] = glslang::OS_CreateThread(&CompileShaders); - if (! threads[t]) { + if (Options & EOptionMultiThreaded) + { + std::array threads; + for (unsigned int t = 0; t < threads.size(); ++t) + { + threads[t] = std::thread(CompileShaders, std::ref(workList)); + if (threads[t].get_id() == std::thread::id()) + { printf("Failed to create thread\n"); return EFailThreadCreate; } } - glslang::OS_WaitForAllThreads(threads, NumThreads); + + std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); }); } else - CompileShaders(0); + CompileShaders(workList); // Print out all the resulting infologs - for (int w = 0; w < NumWorkItems; ++w) { - if (Work[w]) { - if (printShaderNames || Work[w]->results.size() > 0) - PutsIfNonEmpty(Work[w]->name.c_str()); - PutsIfNonEmpty(Work[w]->results.c_str()); - delete Work[w]; + for (size_t w = 0; w < workItems.size(); ++w) { + if (workItems[w]) { + if (printShaderNames || workItems[w]->results.size() > 0) + PutsIfNonEmpty(workItems[w]->name.c_str()); + PutsIfNonEmpty(workItems[w]->results.c_str()); } } ShFinalize(); } - delete[] Work; - if (CompileFailed) return EFailCompile; if (LinkFailed) diff --git a/StandAlone/Worklist.h b/StandAlone/Worklist.h index 2a14294e..91b6f516 100644 --- a/StandAlone/Worklist.h +++ b/StandAlone/Worklist.h @@ -36,8 +36,9 @@ #define WORKLIST_H_INCLUDED #include "../glslang/OSDependent/osinclude.h" -#include #include +#include +#include namespace glslang { @@ -58,24 +59,19 @@ namespace glslang { void add(TWorkItem* item) { - GetGlobalLock(); - + std::lock_guard guard(mutex); worklist.push_back(item); - - ReleaseGlobalLock(); } bool remove(TWorkItem*& item) { - GetGlobalLock(); + std::lock_guard guard(mutex); if (worklist.empty()) return false; item = worklist.front(); worklist.pop_front(); - ReleaseGlobalLock(); - return true; } @@ -90,6 +86,7 @@ namespace glslang { } protected: + std::mutex mutex; std::list worklist; }; diff --git a/glslang/OSDependent/Unix/ossource.cpp b/glslang/OSDependent/Unix/ossource.cpp index 4f8098b7..24b77e16 100644 --- a/glslang/OSDependent/Unix/ossource.cpp +++ b/glslang/OSDependent/Unix/ossource.cpp @@ -184,20 +184,6 @@ void ReleaseGlobalLock() pthread_mutex_unlock(&gMutex); } -// TODO: non-windows: if we need these on linux, flesh them out -void* OS_CreateThread(TThreadEntrypoint /*entry*/) -{ - return 0; -} - -void OS_WaitForAllThreads(void* /*threads*/, int /*numThreads*/) -{ -} - -void OS_Sleep(int /*milliseconds*/) -{ -} - void OS_DumpMemoryCounters() { } diff --git a/glslang/OSDependent/Windows/ossource.cpp b/glslang/OSDependent/Windows/ossource.cpp index 73ae0ca7..870840c5 100644 --- a/glslang/OSDependent/Windows/ossource.cpp +++ b/glslang/OSDependent/Windows/ossource.cpp @@ -131,21 +131,6 @@ unsigned int __stdcall EnterGenericThread (void* entry) return ((TThreadEntrypoint)entry)(0); } -void* OS_CreateThread(TThreadEntrypoint entry) -{ - return (void*)_beginthreadex(0, 0, EnterGenericThread, (void*)entry, 0, 0); -} - -void OS_WaitForAllThreads(void* threads, int numThreads) -{ - WaitForMultipleObjects(numThreads, (HANDLE*)threads, true, INFINITE); -} - -void OS_Sleep(int milliseconds) -{ - Sleep(milliseconds); -} - //#define DUMP_COUNTERS void OS_DumpMemoryCounters() diff --git a/glslang/OSDependent/osinclude.h b/glslang/OSDependent/osinclude.h index e8325268..218abe4f 100644 --- a/glslang/OSDependent/osinclude.h +++ b/glslang/OSDependent/osinclude.h @@ -53,11 +53,8 @@ void GetGlobalLock(); void ReleaseGlobalLock(); typedef unsigned int (*TThreadEntrypoint)(void*); -void* OS_CreateThread(TThreadEntrypoint); -void OS_WaitForAllThreads(void* threads, int numThreads); void OS_CleanupThreadData(void); -void OS_Sleep(int milliseconds); void OS_DumpMemoryCounters();