#include <cctype>
#include <cmath>
#include <array>
+#include <memory>
+#include <thread>
#include "../glslang/OSDependent/osinclude.h"
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;
//
// Does not return (it exits) if command-line is fatally flawed.
//
-void ProcessArguments(int argc, char* argv[])
+void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItems, int argc, char* argv[])
{
baseSamplerBinding.fill(0);
baseTextureBinding.fill(0);
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++;
Options |= EOptionSuppressInfolog;
break;
case 't':
- #ifdef _WIN32
- Options |= EOptionMultiThreaded;
- #endif
+ Options |= EOptionMultiThreaded;
break;
case 'v':
Options |= EOptionDumpVersions;
} 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<glslang::TWorkItem>(new glslang::TWorkItem(name)));
}
}
}
//
// 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);
ShDestruct(compiler);
}
-
- return 0;
}
// Outputs the given string, but only if it is non-null and non-empty.
// 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<ShaderCompUnit> compUnits;
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<std::unique_ptr<glslang::TWorkItem>> workItems;
+ ProcessArguments(workItems, argc, argv);
+
+ glslang::TWorklist workList;
+ std::for_each(workItems.begin(), workItems.end(), [&workList](std::unique_ptr<glslang::TWorkItem>& item) {
+ assert(item);
+ workList.add(item.get());
+ });
if (Options & EOptionDumpConfig) {
printf("%s", glslang::GetDefaultTBuiltInResourceString().c_str());
- if (Worklist.empty())
+ if (workList.empty())
return ESuccess;
}
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();
}
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<std::thread, 16> 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)