diff --git a/OGLCompilersDLL/InitializeDll.cpp b/OGLCompilersDLL/InitializeDll.cpp index 4c42e59e..01125ce4 100644 --- a/OGLCompilersDLL/InitializeDll.cpp +++ b/OGLCompilersDLL/InitializeDll.cpp @@ -34,6 +34,8 @@ #define SH_EXPORTING +#include + #include "InitializeDll.h" #include "Include/InitializeGlobals.h" @@ -43,10 +45,14 @@ OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX; bool InitProcess() { + glslang::GetGlobalLock(); + if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) { // // Function is re-entrant. // + + glslang::ReleaseGlobalLock(); return true; } @@ -54,16 +60,21 @@ bool InitProcess() if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) { assert(0 && "InitProcess(): Failed to allocate TLS area for init flag"); + + glslang::ReleaseGlobalLock(); return false; } if (! InitializePoolIndex()) { assert(0 && "InitProcess(): Failed to initalize global pool"); + + glslang::ReleaseGlobalLock(); return false; } InitThread(); + glslang::ReleaseGlobalLock(); return true; } diff --git a/StandAlone.vcxproj b/StandAlone.vcxproj index 0e2cb87d..8e2cfd29 100644 --- a/StandAlone.vcxproj +++ b/StandAlone.vcxproj @@ -48,7 +48,7 @@ Disabled - glslang;%(AdditionalIncludeDirectories) + glslang;glslang\OSDependent\Windows WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) EnableFastChecks @@ -94,7 +94,7 @@ MaxSpeed OnlyExplicitInline true - glslang;%(AdditionalIncludeDirectories) + glslang;glslang\OSDependent\Windows WIN32;NDEBUG;_CONSOLE;GENERIC_COMPILER;%(PreprocessorDefinitions) true Default @@ -150,6 +150,9 @@ false + + + diff --git a/StandAlone.vcxproj.filters b/StandAlone.vcxproj.filters index 637dd825..05d04bba 100644 --- a/StandAlone.vcxproj.filters +++ b/StandAlone.vcxproj.filters @@ -17,4 +17,9 @@ Source Files + + + Source Files + + \ No newline at end of file diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 31f17253..fdf7490f 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -33,16 +33,14 @@ //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //POSSIBILITY OF SUCH DAMAGE. // +#include "Worklist.h" #include "./../glslang/Include/ShHandle.h" #include "./../glslang/Public/ShaderLang.h" #include #include #include -#ifdef _WIN32 - #include - #include -#endif +#include "osinclude.h" extern "C" { SH_IMPORT_EXPORT void ShOutputHtml(); @@ -57,6 +55,7 @@ enum TFailCode { EFailCompile, EFailLink, EFailCompilerCreate, + EFailThreadCreate, EFailLinkerCreate }; @@ -73,7 +72,7 @@ ShBinding FixedAttributeBindings[] = { ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings }; -static EShLanguage FindLanguage(char *lang); +static EShLanguage FindLanguage(const std::string& name); bool CompileFile(const char *fileName, ShHandle, int options, const TBuiltInResource*); void usage(); void FreeFileData(char **data); @@ -109,110 +108,103 @@ void GenerateResources(TBuiltInResource& resources) resources.maxProgramTexelOffset = 7; } +glslang::TWorklist Worklist; +int DebugOptions = 0; +bool Delay = false; + +bool ProcessArguments(int argc, char* argv[]) +{ + argc--; + argv++; + for (; argc >= 1; argc--, argv++) { + if (argv[0][0] == '-') { + switch (argv[0][1]) { + case 'd': + Delay = true; + break; + case 'i': + DebugOptions |= EDebugOpIntermediate; + break; + case 'l': + DebugOptions |= EDebugOpMemoryLeakMode; + break; + case 'r': + DebugOptions |= EDebugOpRelaxedErrors; + break; + case 's': + DebugOptions |= EDebugOpSuppressInfolog; + break; + case 't': + DebugOptions |= EDebugOpTexturePrototypes; + break; + default: + usage(); + return false; + } + } else + Worklist.add(std::string(argv[0])); + } + + return true; +} + +// Thread entry point +unsigned int __stdcall CompileShaders(void*) +{ + ShHandle compiler; + + std::string shaderName; + while (Worklist.remove(shaderName)) { + compiler = ShConstructCompiler(FindLanguage(shaderName), DebugOptions); + if (compiler == 0) + return false; + + TBuiltInResource resources; + GenerateResources(resources); + CompileFile(shaderName.c_str(), compiler, DebugOptions, &resources); + + if (! (DebugOptions & EDebugOpSuppressInfolog)) + puts(ShGetInfoLog(compiler)); + + ShDestruct(compiler); + } + + return 0; +} + int C_DECL main(int argc, char* argv[]) { - bool delay = false; - int numCompilers = 0; bool compileFailed = false; bool linkFailed = false; - int debugOptions = 0; - int i; - ShHandle linker = 0; - ShHandle uniformMap = 0; - ShHandle compilers[EShLangCount]; - + // Init for front-end proper ShInitialize(); -#ifdef _WIN32 - __try { -#endif - argc--; - argv++; - for (; argc >= 1; argc--, argv++) { - if (argv[0][0] == '-') { - switch (argv[0][1]) { - case 'd': - delay = true; - break; - case 'i': - debugOptions |= EDebugOpIntermediate; - break; - case 'l': - debugOptions |= EDebugOpMemoryLeakMode; - break; - case 'r': - debugOptions |= EDebugOpRelaxedErrors; - break; - case 's': - debugOptions |= EDebugOpSuppressInfolog; - break; - case 't': - debugOptions |= EDebugOpTexturePrototypes; - break; - default: - usage(); - return EFailUsage; - } - } else { - compilers[numCompilers] = ShConstructCompiler(FindLanguage(argv[0]), debugOptions); - if (compilers[numCompilers] == 0) - return EFailCompilerCreate; - ++numCompilers; + // Init for for standalone + glslang::InitGlobalLock(); - TBuiltInResource resources; - GenerateResources(resources); - if (! CompileFile(argv[0], compilers[numCompilers-1], debugOptions, &resources)) - compileFailed = true; + if (! ProcessArguments(argc, argv)) + return EFailUsage; + + // TODO: finish threading, allow external control over number of threads + const int NumThreads = 1; + if (NumThreads > 1) { + void* threads[NumThreads]; + for (int t = 0; t < NumThreads; ++t) { + threads[t] = glslang::OS_CreateThread(&CompileShaders); + if (! threads[t]) { + printf("Failed to create thread\n"); + return EFailThreadCreate; } } - - if (!numCompilers) { - usage(); - return EFailUsage; - } - - linker = ShConstructLinker(EShExVertexFragment, debugOptions); - if (linker == 0) - return EFailLinkerCreate; - - uniformMap = ShConstructUniformMap(); - if (uniformMap == 0) - return EFailLinkerCreate; - - if (numCompilers > 0) { - ShSetFixedAttributeBindings(linker, &FixedAttributeTable); - if (! ShLink(linker, compilers, numCompilers, uniformMap, 0, 0)) - linkFailed = true; - } - - if (! (debugOptions & EDebugOpSuppressInfolog)) { - for (i = 0; i < numCompilers; ++i) { - InfoLogMsg("BEGIN", "COMPILER", i); - puts(ShGetInfoLog(compilers[i])); - InfoLogMsg("END", "COMPILER", i); - } - - InfoLogMsg("BEGIN", "LINKER", -1); - puts(ShGetInfoLog(linker)); - InfoLogMsg("END", "LINKER", -1); - } - -#ifdef _WIN32 - } __finally { -#endif - for (i = 0; i < numCompilers; ++i) - ShDestruct(compilers[i]); - - ShDestruct(linker); - ShDestruct(uniformMap); - -#ifdef _WIN32 - if (delay) - Sleep(1000000); - + glslang::OS_WaitForAllThreads(threads, NumThreads); + } else { + if (! CompileShaders(0)) + compileFailed = true; } -#endif + + if (Delay) + glslang::OS_Sleep(1000000); if (compileFailed) return EFailCompile; @@ -226,27 +218,36 @@ int C_DECL main(int argc, char* argv[]) // Deduce the language from the filename. Files must end in one of the // following extensions: // -// .frag* = fragment programs -// .vert* = vertex programs +// .vert = vertex +// .tesc = tessellation control +// .tese = tessellation evaluation +// .geom = geometry +// .frag = fragment // -static EShLanguage FindLanguage(char *name) +static EShLanguage FindLanguage(const std::string& name) { - if (!name) + size_t ext = name.rfind('.'); + if (ext == std::string::npos) { + usage(); return EShLangVertex; - - char *ext = strrchr(name, '.'); - - if (ext && strcmp(ext, ".sl") == 0) - for (; ext > name && ext[0] != '.'; ext--); - - if (ext = strrchr(name, '.')) { - if (strncmp(ext, ".frag", 4) == 0) return EShLangFragment; } + std::string suffix = name.substr(ext + 1, std::string::npos); + if (suffix == "vert") + return EShLangVertex; + else if (suffix == "tesc") + return EShLangTessControl; + else if (suffix == "tese") + return EShLangTessEvaluation; + else if (suffix == "geom") + return EShLangGeometry; + else if (suffix == "frag") + return EShLangFragment; + + usage(); return EShLangVertex; } - // // Read a file's data into a string, and compile it using ShCompile // @@ -265,10 +266,6 @@ bool CompileFile(const char *fileName, ShHandle compiler, int debugOptions, cons for (int s = 0; s < NumShaderStrings; ++s) lengths[s] = strlen(shaderStrings[s]); -#ifdef _WIN32 - PROCESS_MEMORY_COUNTERS counters; // just for memory leak testing -#endif - if (! shaderStrings) return false; @@ -284,12 +281,8 @@ bool CompileFile(const char *fileName, ShHandle compiler, int debugOptions, cons //ret = ShCompile(compiler, multi, 4, 0, EShOptNone, resources, debugOptions, 100, false, messages); } -#ifdef _WIN32 - if (debugOptions & EDebugOpMemoryLeakMode) { - GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters)); - printf("Working set size: %d\n", counters.WorkingSetSize); - } -#endif + if (debugOptions & EDebugOpMemoryLeakMode) + glslang::OS_DumpMemoryCounters(); } delete [] lengths; diff --git a/StandAlone/Worklist.h b/StandAlone/Worklist.h new file mode 100644 index 00000000..0c9a4eed --- /dev/null +++ b/StandAlone/Worklist.h @@ -0,0 +1,77 @@ +// +//Copyright (C) 2013 LunarG, Inc. +// +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +#ifndef WORKLIST_H_INCLUDED +#define WORKLIST_H_INCLUDED + +#include "osinclude.h" +#include + +namespace glslang { + + class TWorklist { + public: + TWorklist() { } + virtual ~TWorklist() { } + + void add(const std::string& s) + { + GetGlobalLock(); + + worklist.push_back(s); + + ReleaseGlobalLock(); + } + + bool remove(std::string& s) + { + GetGlobalLock(); + + if (worklist.empty()) + return false; + s = worklist.front(); + worklist.pop_front(); + + ReleaseGlobalLock(); + + return true; + } + + protected: + std::list worklist; + }; + +}; + +#endif // WORKLIST_H_INCLUDED diff --git a/glslang/Include/Common.h b/glslang/Include/Common.h index e9366830..ee1bc75f 100644 --- a/glslang/Include/Common.h +++ b/glslang/Include/Common.h @@ -92,7 +92,7 @@ typedef pool_allocator TStringAllocator; typedef std::basic_string , TStringAllocator > TString; inline TString* NewPoolTString(const char* s) { - void* memory = GlobalPoolAllocator.allocate(sizeof(TString)); + void* memory = GetThreadPoolAllocator().allocate(sizeof(TString)); return new(memory) TString(s); } diff --git a/glslang/Include/ConstantUnion.h b/glslang/Include/ConstantUnion.h index b5652976..b50b230e 100644 --- a/glslang/Include/ConstantUnion.h +++ b/glslang/Include/ConstantUnion.h @@ -41,7 +41,7 @@ class constUnion { public: - POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) void setIConst(int i) { iConst = i; diff --git a/glslang/Include/PoolAlloc.h b/glslang/Include/PoolAlloc.h index 7da21756..5d222fc0 100644 --- a/glslang/Include/PoolAlloc.h +++ b/glslang/Include/PoolAlloc.h @@ -144,7 +144,7 @@ private: // class TPoolAllocator { public: - TPoolAllocator(bool global = false, int growthIncrement = 8*1024, int allocationAlignment = 16); + TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16); // // Don't call the destructor just to free up the memory, call pop() @@ -222,7 +222,6 @@ protected: return TAllocation::offsetAllocation(memory); } - bool global; // should be true if this object is globally scoped size_t pageSize; // granularity of allocation from the OS size_t alignment; // all returned allocations will be aligned at // this granularity, which will be a power of 2 @@ -249,16 +248,14 @@ private: // with everyone using the same global allocator. // typedef TPoolAllocator* PoolAllocatorPointer; -extern TPoolAllocator& GetGlobalPoolAllocator(); -#define GlobalPoolAllocator GetGlobalPoolAllocator() - +extern TPoolAllocator& GetThreadPoolAllocator(); struct TThreadGlobalPools { TPoolAllocator* globalPoolAllocator; }; -void SetGlobalPoolAllocatorPtr(TPoolAllocator& poolAllocator); +void SetThreadPoolAllocator(TPoolAllocator& poolAllocator); // // This STL compatible allocator is intended to be used as the allocator @@ -284,7 +281,7 @@ public: pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } - pool_allocator() : allocator(GlobalPoolAllocator) { } + pool_allocator() : allocator(GetThreadPoolAllocator()) { } pool_allocator(TPoolAllocator& a) : allocator(a) { } pool_allocator(const pool_allocator& p) : allocator(p.allocator) { } diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 4b7681a3..3d9e089d 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -150,7 +150,7 @@ typedef TVector TTypeList; inline TTypeList* NewPoolTTypeList() { - void* memory = GlobalPoolAllocator.allocate(sizeof(TTypeList)); + void* memory = GetThreadPoolAllocator().allocate(sizeof(TTypeList)); return new(memory) TTypeList; } @@ -158,7 +158,7 @@ typedef TVector TIdentifierList; inline TIdentifierList* NewPoolTIdentifierList() { - void* memory = GlobalPoolAllocator.allocate(sizeof(TIdentifierList)); + void* memory = GetThreadPoolAllocator().allocate(sizeof(TIdentifierList)); return new(memory) TIdentifierList; } @@ -176,7 +176,7 @@ typedef TVector* TArraySizes; inline TArraySizes NewPoolTArraySizes() { - void* memory = GlobalPoolAllocator.allocate(sizeof(TVector)); + void* memory = GetThreadPoolAllocator().allocate(sizeof(TVector)); return new(memory) TVector; } @@ -401,7 +401,7 @@ typedef std::map::const_iterator TStructureMapIterator; // class TType { public: - POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) explicit TType(TBasicType t, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) : basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0), structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h index 6ced6a41..ae22cf38 100644 --- a/glslang/Include/intermediate.h +++ b/glslang/Include/intermediate.h @@ -318,7 +318,7 @@ class TInfoSink; // class TIntermNode { public: - POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) TIntermNode() { loc.line = 0; loc.string = 0; } virtual TSourceLoc getLoc() const { return loc; } @@ -601,7 +601,7 @@ protected: // class TIntermTraverser { public: - POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) TIntermTraverser() : visitSymbol(0), diff --git a/glslang/MachineIndependent/Initialize.h b/glslang/MachineIndependent/Initialize.h index c3e9b0e8..34d86b1f 100644 --- a/glslang/MachineIndependent/Initialize.h +++ b/glslang/MachineIndependent/Initialize.h @@ -47,7 +47,7 @@ typedef TVector TBuiltInStrings; class TBuiltIns { public: - POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) TBuiltIns(); virtual ~TBuiltIns(); void initialize(int version, EProfile); diff --git a/glslang/MachineIndependent/PoolAlloc.cpp b/glslang/MachineIndependent/PoolAlloc.cpp index ad5de3b8..4a88429b 100644 --- a/glslang/MachineIndependent/PoolAlloc.cpp +++ b/glslang/MachineIndependent/PoolAlloc.cpp @@ -46,7 +46,7 @@ void InitializeGlobalPools() if (globalPools) return; - TPoolAllocator *globalPoolAllocator = new TPoolAllocator(true); + TPoolAllocator *globalPoolAllocator = new TPoolAllocator(); TThreadGlobalPools* threadData = new TThreadGlobalPools(); @@ -58,12 +58,12 @@ void InitializeGlobalPools() void FreeGlobalPools() { // Release the allocated memory for this thread. - TThreadGlobalPools* globalPools= static_cast(OS_GetTLSValue(PoolIndex)); - if (!globalPools) + TThreadGlobalPools* globalPools = static_cast(OS_GetTLSValue(PoolIndex)); + if (! globalPools) return; - GlobalPoolAllocator.popAll(); - delete &GlobalPoolAllocator; + GetThreadPoolAllocator().popAll(); + delete &GetThreadPoolAllocator(); delete globalPools; } @@ -82,14 +82,14 @@ void FreePoolIndex() OS_FreeTLSIndex(PoolIndex); } -TPoolAllocator& GetGlobalPoolAllocator() +TPoolAllocator& GetThreadPoolAllocator() { TThreadGlobalPools* threadData = static_cast(OS_GetTLSValue(PoolIndex)); return *threadData->globalPoolAllocator; } -void SetGlobalPoolAllocatorPtr(TPoolAllocator& poolAllocator) +void SetThreadPoolAllocator(TPoolAllocator& poolAllocator) { TThreadGlobalPools* threadData = static_cast(OS_GetTLSValue(PoolIndex)); @@ -100,8 +100,7 @@ void SetGlobalPoolAllocatorPtr(TPoolAllocator& poolAllocator) // Implement the functionality of the TPoolAllocator class, which // is documented in PoolAlloc.h. // -TPoolAllocator::TPoolAllocator(bool g, int growthIncrement, int allocationAlignment) : - global(g), +TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : pageSize(growthIncrement), alignment(allocationAlignment), freeList(0), @@ -148,19 +147,12 @@ TPoolAllocator::TPoolAllocator(bool g, int growthIncrement, int allocationAlignm TPoolAllocator::~TPoolAllocator() { - if (!global) { - // - // Then we know that this object is not being - // allocated after other, globally scoped objects - // that depend on it. So we can delete the "in use" memory. - // - while (inUseList) { - tHeader* next = inUseList->nextPage; - inUseList->~tHeader(); - delete [] reinterpret_cast(inUseList); - inUseList = next; - } - } + while (inUseList) { + tHeader* next = inUseList->nextPage; + inUseList->~tHeader(); + delete [] reinterpret_cast(inUseList); + inUseList = next; + } // // Always delete the free list memory - it can't be being diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index 8bb6c5bd..8f244a51 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -79,7 +79,7 @@ int MapVersionToIndex(int version) const int VersionCount = 12; // -// A symbol table per version per profile per language. This will be sparsely +// A process-global symbol table per version per profile per language. This will be sparsely // populated, so they will only only be generated as needed. // // Each has a different set of built-ins, and we want to preserve that from @@ -163,41 +163,59 @@ bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& inf return true; } +// +// To do this on the fly, we want to leave the current state of our thread's +// pool allocator intact, so: +// - Switch to a new pool for parsing the built-ins +// - Do the parsing, which builds the symbol table, using the new pool +// - Switch to the process-global pool to save a copy the resulting symbol table +// - Free up the new pool used to parse the built-ins +// - Switch back to the original thread's pool +// +// This only gets done the first time any thread needs a particular symbol table +// (lazy evaluation). +// void SetupBuiltinSymbolTable(int version, EProfile profile) { TInfoSink infoSink; - // This function is for lazy setup. See if already done. + // Make sure only one thread tries to do this at a time + glslang::GetGlobalLock(); + + // See if it's already been done. int versionIndex = MapVersionToIndex(version); - if (SharedSymbolTables[versionIndex][profile][EShLangVertex]) + if (SharedSymbolTables[versionIndex][profile][EShLangVertex]) { + glslang::ReleaseGlobalLock(); + return; + } - TPoolAllocator& savedGPA = GetGlobalPoolAllocator(); - TPoolAllocator *builtInPoolAllocator = new TPoolAllocator(true); - SetGlobalPoolAllocatorPtr(*builtInPoolAllocator); + // Switch to a new pool + TPoolAllocator& savedGPA = GetThreadPoolAllocator(); + TPoolAllocator* builtInPoolAllocator = new TPoolAllocator(); + SetThreadPoolAllocator(*builtInPoolAllocator); + // Generate the symbol table using the new pool TSymbolTable symTables[EShLangCount]; if (profile == EEsProfile) { for (int stage = 0; stage < EShLangCount; ++stage) symTables[stage].setNoBuiltInRedeclarations(); } - GenerateBuiltInSymbolTable(infoSink, symTables, version, profile); - SetGlobalPoolAllocatorPtr(*PerProcessGPA); + // Switch to the process-global pool + SetThreadPoolAllocator(*PerProcessGPA); + // Copy the symbol table from the new pool to the process-global pool SharedSymbolTables[versionIndex][profile][EShLangVertex] = new TSymbolTable; SharedSymbolTables[versionIndex][profile][EShLangVertex]->copyTable(symTables[EShLangVertex]); SharedSymbolTables[versionIndex][profile][EShLangFragment] = new TSymbolTable; SharedSymbolTables[versionIndex][profile][EShLangFragment]->copyTable(symTables[EShLangFragment]); - - symTables[EShLangVertex].pop(0); - symTables[EShLangFragment].pop(0); - builtInPoolAllocator->popAll(); delete builtInPoolAllocator; + SetThreadPoolAllocator(savedGPA); - SetGlobalPoolAllocatorPtr(savedGPA); + glslang::ReleaseGlobalLock(); } bool DeduceProfile(TInfoSink& infoSink, int version, EProfile& profile) @@ -261,7 +279,7 @@ int ShInitialize() return 0; if (! PerProcessGPA) { - PerProcessGPA = new TPoolAllocator(true); + PerProcessGPA = new TPoolAllocator(); } glslang::TScanContext::fillInKeywordMap(); @@ -333,6 +351,7 @@ int __fastcall ShFinalize() PerProcessGPA->popAll(); delete PerProcessGPA; } + return 1; } @@ -361,6 +380,7 @@ int ShCompile( if (handle == 0) return 0; + TShHandleBase* base = reinterpret_cast(handle); TCompiler* compiler = base->getAsCompiler(); if (compiler == 0) @@ -372,7 +392,7 @@ int ShCompile( if (numStrings == 0) return 1; - GlobalPoolAllocator.push(); + GetThreadPoolAllocator().push(); // move to length-based strings, rather than null-terminated strings int* lengths = new int[numStrings]; @@ -395,7 +415,6 @@ int ShCompile( bool goodProfile = DeduceProfile(compiler->infoSink, version, profile); TIntermediate intermediate(compiler->infoSink, version, profile); - SetupBuiltinSymbolTable(version, profile); TSymbolTable symbolTable(*SharedSymbolTables[MapVersionToIndex(version)] [profile] @@ -480,7 +499,7 @@ int ShCompile( // // Throw away all the temporary memory used by the compilation process. // - GlobalPoolAllocator.pop(); + GetThreadPoolAllocator().pop(); delete [] lengths; return success ? 1 : 0; @@ -510,9 +529,9 @@ int ShLink( return 0; int returnValue; - GlobalPoolAllocator.push(); + GetThreadPoolAllocator().push(); returnValue = ShLinkExt(linkHandle, compHandles, numHandles); - GlobalPoolAllocator.pop(); + GetThreadPoolAllocator().pop(); if (returnValue) return 1; diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h index 79325393..4c62656f 100644 --- a/glslang/MachineIndependent/SymbolTable.h +++ b/glslang/MachineIndependent/SymbolTable.h @@ -77,7 +77,7 @@ class TFunction; class TAnonMember; class TSymbol { public: - POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) explicit TSymbol(const TString *n) : name(n) { } virtual TSymbol* clone(TStructureMap& remapper) = 0; virtual ~TSymbol() { } @@ -245,7 +245,7 @@ protected: class TSymbolTableLevel { public: - POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) TSymbolTableLevel() : defaultPrecision (0), anonId(0) { } ~TSymbolTableLevel(); @@ -365,24 +365,23 @@ protected: class TSymbolTable { public: - TSymbolTable() : uniqueId(0), noBuiltInRedeclarations(false) + TSymbolTable() : uniqueId(0), noBuiltInRedeclarations(false), adoptedLevels(1) // TODO: memory: can we make adoptedLevels be 0 for symbol tables we don't keep? { // - // The symbol table cannot be used until push() is called, but - // the lack of an initial call to push() can be used to detect - // that the symbol table has not been preloaded with built-ins. + // This symbol table cannot be used until push() is called. // } explicit TSymbolTable(TSymbolTable& symTable) { table.push_back(symTable.table[0]); + adoptedLevels = 1; uniqueId = symTable.uniqueId; noBuiltInRedeclarations = symTable.noBuiltInRedeclarations; } ~TSymbolTable() { - // level 0 is always built-in symbols, so we never pop that out - while (table.size() > 1) + // don't deallocate levels passed in from elsewhere + while (table.size() > adoptedLevels) pop(0); } @@ -463,6 +462,7 @@ protected: std::vector table; int uniqueId; // for unique identification in code generation bool noBuiltInRedeclarations; + unsigned int adoptedLevels; }; #endif // _SYMBOL_TABLE_INCLUDED_ diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index 486b639a..9a470f51 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -319,6 +319,7 @@ postfix_expression TType newType($1->getType()); newType.dereference(); $$->setType(newType); + // TODO: functionality: does this drop const qualification for const[const] ? } } | function_call { diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index fb7602d3..471bee82 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -51,7 +51,7 @@ struct TVectorFields { class TInfoSink; class TIntermediate { public: - POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) TIntermediate(TInfoSink& i, int v, EProfile p) : infoSink(i), version(v), profile(p) { } TIntermSymbol* addSymbol(int Id, const TString&, const TType&, TSourceLoc); diff --git a/glslang/OSDependent/Linux/osinclude.h b/glslang/OSDependent/Linux/osinclude.h index c894dc40..4de99778 100644 --- a/glslang/OSDependent/Linux/osinclude.h +++ b/glslang/OSDependent/Linux/osinclude.h @@ -71,4 +71,18 @@ inline void * OS_GetTLSValue(OS_TLSIndex nIndex) return pthread_getspecific(nIndex); } +namespace glslang { + void InitGlobalLock(); + void GetGlobalLock(); + void ReleaseGlobalLock(); + + typedef unsigned int (*TThreadEntrypoint)(void*); + void* OS_CreateThread(TThreadEntrypoint); + void OS_WaitForAllThreads(void* threads, int numThreads); + + void OS_Sleep(int milliseconds); + + void OS_DumpMemoryCounters(); +}; + #endif // __OSINCLUDE_H diff --git a/glslang/OSDependent/Linux/ossource.cpp b/glslang/OSDependent/Linux/ossource.cpp index 879e8385..1f6cbefe 100644 --- a/glslang/OSDependent/Linux/ossource.cpp +++ b/glslang/OSDependent/Linux/ossource.cpp @@ -134,3 +134,26 @@ bool OS_FreeTLSIndex(OS_TLSIndex nIndex) else return false; } + +namespace glslang { + // TODO: if we need these on linux, flesh them out + void InitGlobalLock() { } + void GetGlobalLock() { } + void ReleaseGlobalLock() { } + + void* OS_CreateThread(TThreadEntrypoint entry) + { + } + + void OS_WaitForAllThreads(void* threads, int numThreads) + { + } + + void OS_Sleep(int milliseconds) + { + } + + void OS_DumpMemoryCounters() + { + } +}; diff --git a/glslang/OSDependent/Windows/main.cpp b/glslang/OSDependent/Windows/main.cpp index ee4ad55b..7e4d9a35 100644 --- a/glslang/OSDependent/Windows/main.cpp +++ b/glslang/OSDependent/Windows/main.cpp @@ -34,6 +34,11 @@ #include "InitializeDll.h" +#define STRICT +#define VC_EXTRALEAN 1 +#include +#include + BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) diff --git a/glslang/OSDependent/Windows/osinclude.h b/glslang/OSDependent/Windows/osinclude.h index 652f5586..63ed3e0f 100644 --- a/glslang/OSDependent/Windows/osinclude.h +++ b/glslang/OSDependent/Windows/osinclude.h @@ -44,26 +44,30 @@ #error Trying to include a windows specific file in a non windows build. #endif -#define STRICT -#define VC_EXTRALEAN 1 -#include -#include - - // // Thread Local Storage Operations // -typedef DWORD OS_TLSIndex; -#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES) +typedef unsigned long OS_TLSIndex; +#define OS_INVALID_TLS_INDEX ((unsigned long)0xFFFFFFFF) OS_TLSIndex OS_AllocTLSIndex(); bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue); bool OS_FreeTLSIndex(OS_TLSIndex nIndex); -inline void* OS_GetTLSValue(OS_TLSIndex nIndex) -{ - assert(nIndex != OS_INVALID_TLS_INDEX); - return TlsGetValue(nIndex); -} +void* OS_GetTLSValue(OS_TLSIndex nIndex); + +namespace glslang { + void InitGlobalLock(); + void GetGlobalLock(); + void ReleaseGlobalLock(); + + typedef unsigned int (__stdcall *TThreadEntrypoint)(void*); + void* OS_CreateThread(TThreadEntrypoint); + void OS_WaitForAllThreads(void* threads, int numThreads); + + void OS_Sleep(int milliseconds); + + void OS_DumpMemoryCounters(); +}; #endif // __OSINCLUDE_H diff --git a/glslang/OSDependent/Windows/ossource.cpp b/glslang/OSDependent/Windows/ossource.cpp index 697e690d..5bc3102b 100644 --- a/glslang/OSDependent/Windows/ossource.cpp +++ b/glslang/OSDependent/Windows/ossource.cpp @@ -33,6 +33,15 @@ // #include "osinclude.h" + +#define STRICT +#define VC_EXTRALEAN 1 +#include +#include +#include +#include +#include + // // This file contains contains the Window-OS-specific functions // @@ -41,7 +50,6 @@ #error Trying to build a windows specific file in a non windows build. #endif - // // Thread Local Storage Operations // @@ -70,6 +78,11 @@ bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) return false; } +void* OS_GetTLSValue(OS_TLSIndex nIndex) +{ + assert(nIndex != OS_INVALID_TLS_INDEX); + return TlsGetValue(nIndex); +} bool OS_FreeTLSIndex(OS_TLSIndex nIndex) { @@ -83,3 +96,45 @@ bool OS_FreeTLSIndex(OS_TLSIndex nIndex) else return false; } + +namespace glslang { + HANDLE GlobalLock; + + void InitGlobalLock() + { + GlobalLock = CreateMutex(0, false, 0); + } + + void GetGlobalLock() + { + WaitForSingleObject(GlobalLock, INFINITE); + } + + void ReleaseGlobalLock() + { + ReleaseMutex(GlobalLock); + } + + void* OS_CreateThread(TThreadEntrypoint entry) + { + return (void*)_beginthreadex(0, 0, entry, 0, 0, 0); + //return CreateThread(0, 0, entry, 0, 0, 0); + } + + void OS_WaitForAllThreads(void* threads, int numThreads) + { + WaitForMultipleObjects(numThreads, (HANDLE*)threads, true, INFINITE); + } + + void OS_Sleep(int milliseconds) + { + Sleep(milliseconds); + } + + void OS_DumpMemoryCounters() + { + PROCESS_MEMORY_COUNTERS counters; + GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters)); + printf("Working set size: %d\n", counters.WorkingSetSize); + } +};