diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2020-03-05 10:59:54 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-05 10:59:54 -0500 |
| commit | 6684d32db1f5693bcfb4971558cb30e855cd3bad (patch) | |
| tree | 480e014b917a6eb0fe72faa6c52a25f4856ed1cb /source/slang-glslang | |
| parent | 5951d2a45f3546a619fb5b032a4a422229c46e4c (diff) | |
Feature/glslang spirv version (#1256)
* WIP add support for __spirv_version .
* Added IRRequireSPIRVVersionDecoration
* SPIR-V version passed to glslang.
Enable VK wave tests.
Split ExtensionTracker out, so can be cast and used externally to emit.
Added SourceResult.
* Fix warning on Clang.
* Missing hlsl.meta.h
* Refactor communication/parsing of __spirv_version with glslang.
* Fix some debug typos.
Be more precise in handling of substring handling.
* Make glslang forwards and backwards binary compatible.
* Small comment improvements.
* Added slang-spirv-target-info.h/cpp
* Fix for major/minor on gcc.
* Another fix for gcc/clang.
* VS projects include slang-spirv-target-info.h/cpp
* Removed SPIRVTargetInfo
Added SemanticVersion.
Don't bother with passing a target to glslang. Should be separate from 'version'.
* Renamed slang-emit-glsl-extension-tracker.cpp/.h -> slang-glsl-extension-tracker.cpp/.h
Fixed some VS project issues.
* Fix a comment.
* Added slang-semantic-version.cpp/.h
* Added slang-glsl-extension-tracker.cpp/.h
* Added split that can check for input has all been parsed.
* Fix problem on x86 win build.
Diffstat (limited to 'source/slang-glslang')
| -rw-r--r-- | source/slang-glslang/slang-glslang.cpp | 243 | ||||
| -rw-r--r-- | source/slang-glslang/slang-glslang.h | 21 |
2 files changed, 230 insertions, 34 deletions
diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp index 6b2af69b7..4015e00d9 100644 --- a/source/slang-glslang/slang-glslang.cpp +++ b/source/slang-glslang/slang-glslang.cpp @@ -83,19 +83,18 @@ static void dump( } static void dumpDiagnostics( - glslang_CompileRequest* request, + const glslang_CompileRequest_1_1& request, std::string const& log) { - dump(log.c_str(), log.length(), request->diagnosticFunc, request->diagnosticUserData, stderr); + const auto& request_1_0 = request.request_1_0; + dump(log.c_str(), log.length(), request_1_0.diagnosticFunc, request_1_0.diagnosticUserData, stderr); } // Apply the SPIRV-Tools optimizer to generated SPIR-V based on the desired optimization level // TODO: add flag for optimizing SPIR-V size as well -static void glslang_optimizeSPIRV(std::vector<unsigned int>& spirv, unsigned optimizationLevel, unsigned debugInfoType) +static void glslang_optimizeSPIRV(std::vector<unsigned int>& spirv, spv_target_env targetEnv, unsigned optimizationLevel, unsigned debugInfoType) { - spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2; - - spvtools::Optimizer optimizer(target_env); + spvtools::Optimizer optimizer(targetEnv); optimizer.SetMessageConsumer( [](spv_message_level_t level, const char *source, const spv_position_t &position, const char *message) { auto &out = std::cerr; @@ -202,10 +201,111 @@ static void glslang_optimizeSPIRV(std::vector<unsigned int>& spirv, unsigned opt optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); } -static int glslang_compileGLSLToSPIRV(glslang_CompileRequest* request) + +static glslang::EShTargetLanguageVersion _makeTargetLanguageVersion(int majorVersion, int minorVersion) +{ + return glslang::EShTargetLanguageVersion((uint32_t(majorVersion) << 16) | (uint32_t(minorVersion) << 8)); +} + +static glsl_SPIRVVersion _toSPIRVVersion(glslang::EShTargetLanguageVersion version) +{ + glsl_SPIRVVersion ver; + ver.patch = 0; + ver.major = uint8_t(uint32_t(version) >> 16); + ver.minor = uint8_t(uint32_t(version) >> 8); + return ver; +} + +// For working out the targets based on SPIR-V target strings + +namespace { // anonymous + +struct SPRIVTargetInfo { + const char* name; + spv_target_env targetEnv; +}; + +} // anonymous + +static const SPRIVTargetInfo kSpirvTargetInfos[] = +{ + {"1.0", SPV_ENV_UNIVERSAL_1_0}, + {"vk1.0", SPV_ENV_VULKAN_1_0}, + {"1.1", SPV_ENV_UNIVERSAL_1_1}, + {"cl2.1", SPV_ENV_OPENCL_2_1}, + {"cl2.2", SPV_ENV_OPENCL_2_2}, + {"gl4.0", SPV_ENV_OPENGL_4_0}, + {"gl4.1", SPV_ENV_OPENGL_4_1}, + {"gl4.2", SPV_ENV_OPENGL_4_2}, + {"gl4.3", SPV_ENV_OPENGL_4_3}, + {"gl4.5", SPV_ENV_OPENGL_4_5}, + {"1.2", SPV_ENV_UNIVERSAL_1_2}, + {"cl1.2", SPV_ENV_OPENCL_1_2}, + {"cl_emb1.2", SPV_ENV_OPENCL_EMBEDDED_1_2}, + {"cl2.0", SPV_ENV_OPENCL_2_0}, + {"cl_emb2.0", SPV_ENV_OPENCL_EMBEDDED_2_0}, + {"cl_emb2.1", SPV_ENV_OPENCL_EMBEDDED_2_1}, + {"cl_emb2.2", SPV_ENV_OPENCL_EMBEDDED_2_2}, + {"1.3", SPV_ENV_UNIVERSAL_1_3}, + {"vk1.1", SPV_ENV_VULKAN_1_1}, + {"web_gpu1.0", SPV_ENV_WEBGPU_0}, + {"1.4", SPV_ENV_UNIVERSAL_1_4}, + {"vk1.1_spirv1.4", SPV_ENV_VULKAN_1_1_SPIRV_1_4}, + {"1.5", SPV_ENV_UNIVERSAL_1_5}, +}; + +static int _findTargetIndex(const char* name) +{ + const int count = int(sizeof(kSpirvTargetInfos) / sizeof(kSpirvTargetInfos[0])); + for (int i = 0; i < count; ++i) + { + const SPRIVTargetInfo& info = kSpirvTargetInfos[i]; + + if (::strcmp(info.name, name) == 0) + { + return i; + } + } + return -1; +} + +static spv_target_env _getUniversalTargetEnv(glslang::EShTargetLanguageVersion inVersion) +{ + glsl_SPIRVVersion spirvVersion = _toSPIRVVersion(inVersion); + uint32_t ver = (uint32_t(spirvVersion.major) << 8) | spirvVersion.minor; + + switch (ver) + { + case 0x100: return SPV_ENV_UNIVERSAL_1_0; + case 0x101: return SPV_ENV_UNIVERSAL_1_1; + case 0x102: return SPV_ENV_UNIVERSAL_1_2; + case 0x103: return SPV_ENV_UNIVERSAL_1_3; + case 0x104: return SPV_ENV_UNIVERSAL_1_4; + case 0x105: return SPV_ENV_UNIVERSAL_1_5; + default: + { + if (ver > 0x105) + { + // This is the highest we known for now..., so try that + return SPV_ENV_UNIVERSAL_1_5; + } + break; + } + } + // Just use the default... + return SPV_ENV_UNIVERSAL_1_2; +} + +static int glslang_compileGLSLToSPIRV(const glslang_CompileRequest_1_1& request) +{ + // Check that the encoding matches + assert(glslang::EShTargetSpv_1_4 == _makeTargetLanguageVersion(1, 4)); + + const auto& request_1_0 = request.request_1_0; + EShLanguage glslangStage; - switch( request->slangStage ) + switch( request_1_0.slangStage ) { #define CASE(SP, GL) case SLANG_STAGE_##SP: glslangStage = EShLang##GL; break CASE(VERTEX, Vertex); @@ -229,16 +329,53 @@ static int glslang_compileGLSLToSPIRV(glslang_CompileRequest* request) return 1; } + + spv_target_env targetEnv = SPV_ENV_UNIVERSAL_1_2; + glslang::EShTargetLanguageVersion targetLanguage = glslang::EShTargetLanguageVersion(0); + + int spirvTargetIndex = -1; + if (request.spirvTargetName) + { + spirvTargetIndex = _findTargetIndex(request.spirvTargetName); + if (spirvTargetIndex < 0) + { + dumpDiagnostics(request, "warning: unknown SPIR-V version\n"); + } + else + { + targetEnv = kSpirvTargetInfos[spirvTargetIndex].targetEnv; + } + } + + // If a version is specified, and no target language is specified, set to universal version of that SPIR-V version + if (request.spirvVersion.major != 0 && targetLanguage == glslang::EShTargetLanguageVersion(0)) + { + targetLanguage = _makeTargetLanguageVersion(request.spirvVersion.major, request.spirvVersion.minor); + } + + // If we don't have a target, but do have a language, use that to determine a universal target + if (spirvTargetIndex < 0 && targetLanguage != glslang::EShTargetLanguageVersion(0)) + { + // We can just use the appropriate universal based on the target language + targetEnv = _getUniversalTargetEnv(targetLanguage); + } + // TODO: compute glslang stage to use glslang::TShader* shader = new glslang::TShader(glslangStage); auto shaderPtr = std::unique_ptr<glslang::TShader>(shader); + // Only set the target language if one is determined + if (targetLanguage != glslang::EShTargetLanguageVersion(0)) + { + shader->setEnvTarget(glslang::EShTargetSpv, targetLanguage); + } + glslang::TProgram* program = new glslang::TProgram(); auto programPtr = std::unique_ptr<glslang::TProgram>(program); - char const* sourceText = (char const*)request->inputBegin; - char const* sourceTextEnd = (char const*)request->inputEnd; + char const* sourceText = (char const*)request_1_0.inputBegin; + char const* sourceTextEnd = (char const*)request_1_0.inputEnd; int sourceTextLength = (int)(sourceTextEnd - sourceText); @@ -247,11 +384,11 @@ static int glslang_compileGLSLToSPIRV(glslang_CompileRequest* request) shader->setStringsWithLengthsAndNames( &sourceText, &sourceTextLength, - &request->sourcePath, + &request_1_0.sourcePath, 1); EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules); - + if( !shader->parse(&gResources, 110, false, messages) ) { dumpDiagnostics(request, shader->getInfoLog()); @@ -283,32 +420,34 @@ static int glslang_compileGLSLToSPIRV(glslang_CompileRequest* request) spv::SpvBuildLogger logger; glslang::GlslangToSpv(*stageIntermediate, spirv, &logger); - if (request->optimizationLevel != SLANG_OPTIMIZATION_LEVEL_NONE) + if (request_1_0.optimizationLevel != SLANG_OPTIMIZATION_LEVEL_NONE) { - glslang_optimizeSPIRV(spirv, request->optimizationLevel, request->debugInfoType); + glslang_optimizeSPIRV(spirv, targetEnv, request_1_0.optimizationLevel, request_1_0.debugInfoType); } dumpDiagnostics(request, logger.getAllMessages()); - dump(spirv.data(), spirv.size() * sizeof(unsigned int), request->outputFunc, request->outputUserData, stdout); + dump(spirv.data(), spirv.size() * sizeof(unsigned int), request_1_0.outputFunc, request_1_0.outputUserData, stdout); } return 0; } -static int glslang_dissassembleSPIRV(glslang_CompileRequest* request) +static int glslang_dissassembleSPIRV(const glslang_CompileRequest_1_1& request) { typedef unsigned int SPIRVWord; - SPIRVWord const* spirvBegin = (SPIRVWord const*)request->inputBegin; - SPIRVWord const* spirvEnd = (SPIRVWord const*)request->inputEnd; + auto& request_1_0 = request.request_1_0; + + SPIRVWord const* spirvBegin = (SPIRVWord const*)request_1_0.inputBegin; + SPIRVWord const* spirvEnd = (SPIRVWord const*)request_1_0.inputEnd; std::vector<SPIRVWord> spirv(spirvBegin, spirvEnd); std::stringstream spirvAsmStream; spv::Disassemble(spirvAsmStream, spirv); std::string result = spirvAsmStream.str(); - dump(result.c_str(), result.length(), request->outputFunc, request->outputUserData, stdout); + dump(result.c_str(), result.length(), request_1_0.outputFunc, request_1_0.outputUserData, stdout); return 0; } @@ -349,13 +488,34 @@ public: bool m_isInitialized = false; }; +static int _compile(const glslang_CompileRequest_1_1& request) +{ + int result = 0; + switch (request.request_1_0.action) + { + default: + result = 1; + break; + + case GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV: + result = glslang_compileGLSLToSPIRV(request); + break; + + case GLSLANG_ACTION_DISSASSEMBLE_SPIRV: + result = glslang_dissassembleSPIRV(request); + break; + } + + return result; +} + extern "C" #ifdef _MSC_VER _declspec(dllexport) #else __attribute__((__visibility__("default"))) #endif -int glslang_compile(glslang_CompileRequest* request) +int glslang_compile_1_1(glslang_CompileRequest_1_1* inRequest) { static ProcessInitializer g_processInitializer; if (!g_processInitializer.init()) @@ -369,21 +529,40 @@ int glslang_compile(glslang_CompileRequest* request) return 1; } - int result = 0; - switch(request->action) + // If it's the right size just use it + if (inRequest->sizeInBytes == sizeof(glslang_CompileRequest_1_1)) { - default: - result = 1; - break; + return _compile(*inRequest); + } + else + { + // NOTE! It could be larger, but here we'll assume thats ok, and copy and use. - case GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV: - result = glslang_compileGLSLToSPIRV(request); - break; + // Try to ensure some binary compatibility, by using sizeInBytes member, and copying - case GLSLANG_ACTION_DISSASSEMBLE_SPIRV: - result = glslang_dissassembleSPIRV(request); - break; + glslang_CompileRequest_1_1 request; + + // Copy into request + const size_t copySize = (inRequest->sizeInBytes > sizeof(request)) ? sizeof(request) : inRequest->sizeInBytes; + ::memcpy(&request, inRequest, copySize); + // Zero any remaining members + memset(((uint8_t*)&request) + copySize, 0, sizeof(request) - copySize); + + return _compile(request); } +} - return result; +extern "C" +#ifdef _MSC_VER +_declspec(dllexport) +#else +__attribute__((__visibility__("default"))) +#endif +int glslang_compile(glslang_CompileRequest_1_0* inRequest) +{ + glslang_CompileRequest_1_1 request; + memset(&request, 0, sizeof(request)); + request.sizeInBytes = sizeof(request); + request.request_1_0 = *inRequest; + return glslang_compile_1_1(&request); } diff --git a/source/slang-glslang/slang-glslang.h b/source/slang-glslang/slang-glslang.h index 16b8fb871..ac59e9bfa 100644 --- a/source/slang-glslang/slang-glslang.h +++ b/source/slang-glslang/slang-glslang.h @@ -12,7 +12,12 @@ enum GLSLANG_ACTION_DISSASSEMBLE_SPIRV, }; -struct glslang_CompileRequest +struct glsl_SPIRVVersion +{ + int major, minor, patch; +}; + +struct glslang_CompileRequest_1_0 { char const* sourcePath; @@ -33,6 +38,18 @@ struct glslang_CompileRequest unsigned debugInfoType; }; -typedef int (*glslang_CompileFunc)(glslang_CompileRequest* request); + +struct glslang_CompileRequest_1_1 +{ + size_t sizeInBytes; ///< Size in bytes of this structure + + glslang_CompileRequest_1_0 request_1_0; + + const char* spirvTargetName; /// A valid TargetName. If null will use universal based on the spirVersion. + glsl_SPIRVVersion spirvVersion; ///< The SPIR-V version. If all are 0 will use the default which is 1.2 currently +}; + +typedef int (*glslang_CompileFunc_1_0)(glslang_CompileRequest_1_0* request); +typedef int (*glslang_CompileFunc_1_1)(glslang_CompileRequest_1_1* request); #endif |
