From a558b26537e47068f027856ab60a9c3ba45ffdbe Mon Sep 17 00:00:00 2001 From: Juan Lopez Date: Sun, 2 Apr 2017 23:04:00 +0200 Subject: [PATCH] This refactor the StandAlone and WorkList files in order to use more C++11 features remove the dependencies from OS specific code. Changes: - Making WorkList class to have its own mutex instead of the OS specific global one. The new mutex is the one from std library. The OS specific code is also removed. - Using the C++11 std library to handle threads in StandAlone application and enabling concurrent processing on non-windows platforms. - converting the global variable Worklist into local variable workList. --- StandAlone/StandAlone.cpp | 92 ++++++++++++++------------------ StandAlone/Worklist.h | 13 ++--- glslang/OSDependent/Unix/ossource.cpp | 14 ----- glslang/OSDependent/Windows/ossource.cpp | 15 ------ glslang/OSDependent/osinclude.h | 3 -- 5 files changed, 45 insertions(+), 92 deletions(-) diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 0da690e..56d6619 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 2a14294..91b6f51 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 4f8098b..24b77e1 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 73ae0ca..870840c 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 e832526..218abe4 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(); -- 2.7.4