diff --git a/.appveyor.yml b/.appveyor.yml index 64e7ae64af..7350bc8f5e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -25,6 +25,7 @@ matrix: # scripts that run after cloning repository install: - git clone https://github.com/google/googletest.git External/googletest + - update_glslang_sources.py build: parallel: true # enable MSBuild parallel builds diff --git a/.gitignore b/.gitignore index 3e6cc14df3..a1fe3944b1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ TAGS build/ Test/localResults/ External/googletest +External/spirv-tools diff --git a/.travis.yml b/.travis.yml index c58bdc0d0b..7065ee27a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,6 +55,7 @@ install: before_script: - git clone --depth=1 https://github.com/google/googletest.git External/googletest + - update_glslang_sources.py script: - mkdir build && cd build diff --git a/README.md b/README.md index 193e38da87..139e176850 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,14 @@ cd git clone https://github.com/google/googletest.git External/googletest ``` +If you wish to assure that SPIR-V generated from HLSL is legal for Vulkan, +or wish to invoke -Os to reduce SPIR-V size from HLSL or GLSL, install +spirv-tools with this: + +```bash +./update_glslang_sources.py +``` + #### 3) Configure Assume the source directory is `$SOURCE_DIR` and diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 54dc61f356..a0a1c83459 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -52,6 +52,16 @@ namespace spv { #endif } +#ifdef ENABLE_OPT + #include "spirv-tools/optimizer.hpp" + #include "message.h" + #include "SPVRemapper.h" +#endif + +#ifdef ENABLE_OPT +using namespace spvtools; +#endif + // Glslang includes #include "../glslang/MachineIndependent/localintermediate.h" #include "../glslang/MachineIndependent/SymbolTable.h" @@ -5960,6 +5970,12 @@ void OutputSpvHex(const std::vector& spirv, const char* baseName, out.close(); } +#ifdef ENABLE_OPT +void errHandler(const std::string& str) { + std::cerr << str << std::endl; +} +#endif + // // Set up the glslang traversal // @@ -5988,6 +6004,49 @@ void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vectoroptimizeSize) && + !options->disableOptimizer) { + spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2; + + spvtools::Optimizer optimizer(target_env); + optimizer.SetMessageConsumer([](spv_message_level_t level, + const char* source, + const spv_position_t& position, + const char* message) { + std::cerr << StringifyMessage(level, source, position, message) + << std::endl; + }); + + optimizer.RegisterPass(CreateInlineExhaustivePass()); + optimizer.RegisterPass(CreateLocalAccessChainConvertPass()); + optimizer.RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()); + optimizer.RegisterPass(CreateLocalSingleStoreElimPass()); + optimizer.RegisterPass(CreateInsertExtractElimPass()); + optimizer.RegisterPass(CreateAggressiveDCEPass()); + optimizer.RegisterPass(CreateDeadBranchElimPass()); + optimizer.RegisterPass(CreateBlockMergePass()); + optimizer.RegisterPass(CreateLocalMultiStoreElimPass()); + optimizer.RegisterPass(CreateInsertExtractElimPass()); + optimizer.RegisterPass(CreateAggressiveDCEPass()); + // TODO(greg-lunarg): Add this when AMD driver issues are resolved + // if (options->optimizeSize) + // optimizer.RegisterPass(CreateCommonUniformElimPass()); + + if (!optimizer.Run(spirv.data(), spirv.size(), &spirv)) + return; + + // Remove dead module-level objects: functions, types, vars + // TODO(greg-lunarg): Switch to spirv-opt versions when available + spv::spirvbin_t Remapper(0); + Remapper.registerErrorHandler(errHandler); + Remapper.remap(spirv, spv::spirvbin_t::DCE_ALL); + } +#endif + glslang::GetThreadPoolAllocator().pop(); } diff --git a/SPIRV/GlslangToSpv.h b/SPIRV/GlslangToSpv.h index 0dad4d219f..0398501f59 100644 --- a/SPIRV/GlslangToSpv.h +++ b/SPIRV/GlslangToSpv.h @@ -48,8 +48,11 @@ namespace glslang { struct SpvOptions { - SpvOptions() : generateDebugInfo(false) { } + SpvOptions() : generateDebugInfo(false), disableOptimizer(true), + optimizeSize(false) { } bool generateDebugInfo; + bool disableOptimizer; + bool optimizeSize; }; void GetSpirvVersion(std::string&); diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 2c46cc07fa..d2587c1e46 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -95,6 +95,8 @@ enum TOptions { EOptionAutoMapLocations = (1 << 25), EOptionDebug = (1 << 26), EOptionStdin = (1 << 27), + EOptionOptimizeDisable = (1 << 28), + EOptionOptimizeSize = (1 << 29), }; // @@ -528,6 +530,18 @@ void ProcessArguments(std::vector>& workItem case 'I': IncludeDirectoryList.push_back(getStringOperand("-I include path")); break; + case 'O': + if (argv[0][2] == 'd') + Options |= EOptionOptimizeDisable; + else if (argv[0][2] == 's') +#ifdef ENABLE_OPT + Options |= EOptionOptimizeSize; +#else + Error("-Os not available; optimizer not linked"); +#endif + else + Error("unknown -O option"); + break; case 'S': if (argc <= 1) Error("no specified for -S"); @@ -882,6 +896,8 @@ void CompileAndLinkShaderUnits(std::vector compUnits) glslang::SpvOptions spvOptions; if (Options & EOptionDebug) spvOptions.generateDebugInfo = true; + spvOptions.disableOptimizer = Options & EOptionOptimizeDisable; + spvOptions.optimizeSize = Options & EOptionOptimizeSize; glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger, &spvOptions); // Dump the spv to a file or stdout, etc., but only if not doing @@ -1201,6 +1217,8 @@ void usage() " -H print human readable form of SPIR-V; turns on -V\n" " -I add dir to the include search path; includer's directory\n" " is searched first, followed by left-to-right order of -I\n" + " -Od disables optimization. May cause illegal SPIR-V for HLSL.\n" + " -Os optimizes SPIR-V to minimize size.\n" " -S uses specified stage rather than parsing the file extension\n" " choices for are vert, tesc, tese, geom, frag, or comp\n" " -U undefine a pre-processor macro\n" diff --git a/Test/baseLegalResults/hlsl.aliasOpaque.frag.out b/Test/baseLegalResults/hlsl.aliasOpaque.frag.out new file mode 100644 index 0000000000..c288bd1b34 --- /dev/null +++ b/Test/baseLegalResults/hlsl.aliasOpaque.frag.out @@ -0,0 +1,46 @@ +hlsl.aliasOpaque.frag +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 61 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 46 + ExecutionMode 4 OriginUpperLeft + Source HLSL 500 + Name 4 "main" + Name 36 "gss" + Name 37 "gtex" + Name 46 "@entryPointOutput" + Decorate 36(gss) DescriptorSet 0 + Decorate 37(gtex) DescriptorSet 0 + Decorate 46(@entryPointOutput) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeSampler + 7: TypePointer UniformConstant 6 + 8: TypeFloat 32 + 10: TypeImage 8(float) 2D sampled format:Unknown + 11: TypePointer UniformConstant 10 + 12: TypeVector 8(float) 4 + 25: TypeSampledImage 10 + 27: TypeVector 8(float) 2 + 28: 8(float) Constant 1045220557 + 29: 8(float) Constant 1050253722 + 30: 27(fvec2) ConstantComposite 28 29 + 36(gss): 7(ptr) Variable UniformConstant + 37(gtex): 11(ptr) Variable UniformConstant + 39: 8(float) Constant 1077936128 + 45: TypePointer Output 12(fvec4) +46(@entryPointOutput): 45(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 56: 10 Load 37(gtex) + 57: 6 Load 36(gss) + 58: 25 SampledImage 56 57 + 59: 12(fvec4) ImageSampleImplicitLod 58 30 + 60: 12(fvec4) VectorTimesScalar 59 39 + Store 46(@entryPointOutput) 60 + Return + FunctionEnd diff --git a/Test/baseLegalResults/hlsl.flattenOpaque.frag.out b/Test/baseLegalResults/hlsl.flattenOpaque.frag.out new file mode 100644 index 0000000000..eddb07c3ad --- /dev/null +++ b/Test/baseLegalResults/hlsl.flattenOpaque.frag.out @@ -0,0 +1,65 @@ +hlsl.flattenOpaque.frag +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 118 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 83 + ExecutionMode 4 OriginUpperLeft + Source HLSL 500 + Name 4 "main" + Name 37 "tex" + Name 68 "s.s2D" + Name 73 "s2.s2D" + Name 74 "s2.tex" + Name 83 "@entryPointOutput" + Decorate 37(tex) DescriptorSet 0 + Decorate 68(s.s2D) DescriptorSet 0 + Decorate 73(s2.s2D) DescriptorSet 0 + Decorate 74(s2.tex) DescriptorSet 0 + Decorate 83(@entryPointOutput) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeSampler + 7: TypePointer UniformConstant 6 + 8: TypeFloat 32 + 9: TypeVector 8(float) 4 + 14: TypeVector 8(float) 2 + 21: TypeImage 8(float) 2D sampled format:Unknown + 22: TypePointer UniformConstant 21 + 37(tex): 22(ptr) Variable UniformConstant + 40: TypeSampledImage 21 + 42: 8(float) Constant 1045220557 + 43: 8(float) Constant 1050253722 + 44: 14(fvec2) ConstantComposite 42 43 + 68(s.s2D): 7(ptr) Variable UniformConstant + 73(s2.s2D): 7(ptr) Variable UniformConstant + 74(s2.tex): 22(ptr) Variable UniformConstant + 82: TypePointer Output 9(fvec4) +83(@entryPointOutput): 82(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 97: 21 Load 37(tex) + 98: 6 Load 68(s.s2D) + 99: 40 SampledImage 97 98 + 100: 9(fvec4) ImageSampleImplicitLod 99 44 + 102: 21 Load 37(tex) + 103: 6 Load 68(s.s2D) + 104: 40 SampledImage 102 103 + 106: 9(fvec4) ImageSampleImplicitLod 104 44 + 91: 9(fvec4) FAdd 100 106 + 108: 21 Load 74(s2.tex) + 109: 6 Load 73(s2.s2D) + 110: 40 SampledImage 108 109 + 111: 9(fvec4) ImageSampleImplicitLod 110 44 + 93: 9(fvec4) FAdd 91 111 + 113: 21 Load 74(s2.tex) + 114: 6 Load 73(s2.s2D) + 115: 40 SampledImage 113 114 + 117: 9(fvec4) ImageSampleImplicitLod 115 44 + 95: 9(fvec4) FAdd 93 117 + Store 83(@entryPointOutput) 95 + Return + FunctionEnd diff --git a/Test/baseLegalResults/hlsl.flattenOpaqueInit.vert.out b/Test/baseLegalResults/hlsl.flattenOpaqueInit.vert.out new file mode 100644 index 0000000000..da7c3ab0cf --- /dev/null +++ b/Test/baseLegalResults/hlsl.flattenOpaqueInit.vert.out @@ -0,0 +1,70 @@ +hlsl.flattenOpaqueInit.vert +WARNING: 0:20: '=' : cannot do member-wise aliasing for opaque members with this initializer + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 76 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Vertex 4 "main" 58 + Source HLSL 500 + Name 4 "main" + Name 17 "FxaaTex" + MemberName 17(FxaaTex) 0 "smpl" + MemberName 17(FxaaTex) 1 "tex" + Name 36 "g_tInputTexture_sampler" + Name 37 "g_tInputTexture" + Name 39 "t" + Name 43 "flattenTemp" + Name 45 "tex2.smpl" + Name 50 "tex2.tex" + Name 58 "@entryPointOutput" + Decorate 36(g_tInputTexture_sampler) DescriptorSet 0 + Decorate 37(g_tInputTexture) DescriptorSet 0 + Decorate 58(@entryPointOutput) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeSampler + 7: TypePointer UniformConstant 6 + 8: TypeFloat 32 + 9: TypeImage 8(float) 2D sampled format:Unknown + 10: TypePointer UniformConstant 9 + 11: TypeVector 8(float) 4 + 17(FxaaTex): TypeStruct 6 9 + 26: TypeSampledImage 9 + 28: TypeVector 8(float) 2 + 29: 8(float) Constant 1050253722 + 30: 8(float) Constant 1053609165 + 31: 28(fvec2) ConstantComposite 29 30 + 32: 8(float) Constant 0 +36(g_tInputTexture_sampler): 7(ptr) Variable UniformConstant +37(g_tInputTexture): 10(ptr) Variable UniformConstant + 38: TypePointer UniformConstant 17(FxaaTex) + 39(t): 38(ptr) Variable UniformConstant + 43(flattenTemp): 38(ptr) Variable UniformConstant + 45(tex2.smpl): 7(ptr) Variable UniformConstant + 46: TypeInt 32 1 + 47: 46(int) Constant 0 + 50(tex2.tex): 10(ptr) Variable UniformConstant + 51: 46(int) Constant 1 + 57: TypePointer Output 11(fvec4) +58(@entryPointOutput): 57(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 70: 17(FxaaTex) Load 39(t) + Store 43(flattenTemp) 70 + 63: 7(ptr) AccessChain 43(flattenTemp) 47 + 64: 6 Load 63 + Store 45(tex2.smpl) 64 + 65: 10(ptr) AccessChain 43(flattenTemp) 51 + 66: 9 Load 65 + Store 50(tex2.tex) 66 + 72: 9 Load 37(g_tInputTexture) + 73: 6 Load 36(g_tInputTexture_sampler) + 74: 26 SampledImage 72 73 + 75: 11(fvec4) ImageSampleExplicitLod 74 31 Lod 32 + Store 58(@entryPointOutput) 75 + Return + FunctionEnd diff --git a/Test/baseLegalResults/hlsl.flattenOpaqueInitMix.vert.out b/Test/baseLegalResults/hlsl.flattenOpaqueInitMix.vert.out new file mode 100644 index 0000000000..101c0366d6 --- /dev/null +++ b/Test/baseLegalResults/hlsl.flattenOpaqueInitMix.vert.out @@ -0,0 +1,43 @@ +hlsl.flattenOpaqueInitMix.vert +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 60 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Vertex 4 "main" 44 + Source HLSL 500 + Name 4 "main" + Name 36 "g_tInputTexture_sampler" + Name 37 "g_tInputTexture" + Name 44 "@entryPointOutput" + Decorate 36(g_tInputTexture_sampler) DescriptorSet 0 + Decorate 37(g_tInputTexture) DescriptorSet 0 + Decorate 44(@entryPointOutput) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeSampler + 7: TypePointer UniformConstant 6 + 8: TypeFloat 32 + 9: TypeImage 8(float) 2D sampled format:Unknown + 10: TypePointer UniformConstant 9 + 12: TypeVector 8(float) 4 + 24: TypeSampledImage 9 + 28: TypeVector 8(float) 2 + 30: 8(float) Constant 0 + 35: 8(float) Constant 1056964608 +36(g_tInputTexture_sampler): 7(ptr) Variable UniformConstant +37(g_tInputTexture): 10(ptr) Variable UniformConstant + 43: TypePointer Output 12(fvec4) +44(@entryPointOutput): 43(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 53: 9 Load 37(g_tInputTexture) + 54: 6 Load 36(g_tInputTexture_sampler) + 55: 24 SampledImage 53 54 + 58: 28(fvec2) CompositeConstruct 35 35 + 59: 12(fvec4) ImageSampleExplicitLod 55 58 Lod 30 + Store 44(@entryPointOutput) 59 + Return + FunctionEnd diff --git a/Test/runtests b/Test/runtests index 5e873f503e..acba825d78 100755 --- a/Test/runtests +++ b/Test/runtests @@ -32,11 +32,11 @@ diff -b $BASEDIR/badMacroArgs.frag.out $TARGETDIR/badMacroArgs.frag.out || HASER echo Running reflection... $EXE -l -q -C reflection.vert > $TARGETDIR/reflection.vert.out diff -b $BASEDIR/reflection.vert.out $TARGETDIR/reflection.vert.out || HASERROR=1 -$EXE -D -e flizv -l -q -C -V hlsl.reflection.vert > $TARGETDIR/hlsl.reflection.vert.out +$EXE -D -e flizv -l -q -C -V -Od hlsl.reflection.vert > $TARGETDIR/hlsl.reflection.vert.out diff -b $BASEDIR/hlsl.reflection.vert.out $TARGETDIR/hlsl.reflection.vert.out || HASERROR=1 -$EXE -D -e main -l -q -C -V hlsl.reflection.binding.frag > $TARGETDIR/hlsl.reflection.binding.frag.out +$EXE -D -e main -l -q -C -V -Od hlsl.reflection.binding.frag > $TARGETDIR/hlsl.reflection.binding.frag.out diff -b $BASEDIR/hlsl.reflection.binding.frag.out $TARGETDIR/hlsl.reflection.binding.frag.out || HASERROR=1 -$EXE -D -e main -l -q --hlsl-iomap --auto-map-bindings --stb 10 --sbb 20 --ssb 30 --suavb 40 --scb 50 -D -V -e main hlsl.automap.frag > $TARGETDIR/hlsl.automap.frag.out +$EXE -D -e main -l -q --hlsl-iomap --auto-map-bindings --stb 10 --sbb 20 --ssb 30 --suavb 40 --scb 50 -D -V -e main -Od hlsl.automap.frag > $TARGETDIR/hlsl.automap.frag.out diff -b $BASEDIR/hlsl.automap.frag.out $TARGETDIR/hlsl.automap.frag.out || HASERROR=1 # @@ -56,14 +56,14 @@ fi # entry point renaming tests # echo Running entry-point renaming tests -$EXE -i -H -V -D -e main_in_spv --ku --source-entrypoint main hlsl.entry.rename.frag > $TARGETDIR/hlsl.entry.rename.frag.out +$EXE -i -H -V -D -e main_in_spv --ku --source-entrypoint main -Od hlsl.entry.rename.frag > $TARGETDIR/hlsl.entry.rename.frag.out diff -b $BASEDIR/hlsl.entry.rename.frag.out $TARGETDIR/hlsl.entry.rename.frag.out || HASERROR=1 # # Testing ill-defined uncalled function # echo Running ill-defined uncalled function -$EXE -D -e main -H hlsl.deadFunctionMissingBody.vert > $TARGETDIR/hlsl.deadFunctionMissingBody.vert.out +$EXE -D -e main -H -Od hlsl.deadFunctionMissingBody.vert > $TARGETDIR/hlsl.deadFunctionMissingBody.vert.out diff -b $BASEDIR/hlsl.deadFunctionMissingBody.vert.out $TARGETDIR/hlsl.deadFunctionMissingBody.vert.out || HASERROR=1 if [ $HASERROR -eq 0 ] @@ -88,20 +88,20 @@ $EXE -i --hlsl-offsets -H spv.hlslOffsets.vert > $TARGETDIR/spv.hlslOffsets.vert diff -b $BASEDIR/spv.hlslOffsets.vert.out $TARGETDIR/spv.hlslOffsets.vert.out || HASERROR=1 echo Running hlsl offsets -$EXE -i --hlsl-offsets -D -e main -H hlsl.hlslOffset.vert > $TARGETDIR/hlsl.hlslOffset.vert.out +$EXE -i --hlsl-offsets -D -e main -H -Od hlsl.hlslOffset.vert > $TARGETDIR/hlsl.hlslOffset.vert.out diff -b $BASEDIR/hlsl.hlslOffset.vert.out $TARGETDIR/hlsl.hlslOffset.vert.out || HASERROR=1 # # Testing --resource-set-binding # echo Configuring HLSL descriptor set and binding number manually -$EXE -V -D -e main -H hlsl.multiDescriptorSet.frag --rsb frag t0 0 0 t1 1 0 s0 0 1 s1 1 1 b0 2 0 b1 2 1 b2 2 2 > $TARGETDIR/hlsl.multiDescriptorSet.frag.out +$EXE -V -D -e main -H -Od hlsl.multiDescriptorSet.frag --rsb frag t0 0 0 t1 1 0 s0 0 1 s1 1 1 b0 2 0 b1 2 1 b2 2 2 > $TARGETDIR/hlsl.multiDescriptorSet.frag.out diff -b $BASEDIR/hlsl.multiDescriptorSet.frag.out $TARGETDIR/hlsl.multiDescriptorSet.frag.out || HASERROR=1 -$EXE -V -D -e main -H hlsl.explicitDescriptorSet.frag --hlsl-iomap --amb --ssb 10 --stb 20 --rsb 4 > $TARGETDIR/hlsl.explicitDescriptorSet.frag.out +$EXE -V -D -e main -H -Od hlsl.explicitDescriptorSet.frag --hlsl-iomap --amb --ssb 10 --stb 20 --rsb 4 > $TARGETDIR/hlsl.explicitDescriptorSet.frag.out diff -b $BASEDIR/hlsl.explicitDescriptorSet.frag.out $TARGETDIR/hlsl.explicitDescriptorSet.frag.out || HASERROR=1 -$EXE -V -D -e main -H hlsl.explicitDescriptorSet.frag --hlsl-iomap --amb --ssb 10 --stb 20 --rsb frag 3 > $TARGETDIR/hlsl.explicitDescriptorSet-2.frag.out +$EXE -V -D -e main -H -Od hlsl.explicitDescriptorSet.frag --hlsl-iomap --amb --ssb 10 --stb 20 --rsb frag 3 > $TARGETDIR/hlsl.explicitDescriptorSet-2.frag.out diff -b $BASEDIR/hlsl.explicitDescriptorSet-2.frag.out $TARGETDIR/hlsl.explicitDescriptorSet-2.frag.out || HASERROR=1 # @@ -123,20 +123,20 @@ $EXE -g --relaxed-errors --suppress-warnings --aml --hlsl-offsets --nsf \ -G -H spv.debugInfo.frag --rsb frag 3 > $TARGETDIR/spv.debugInfo.frag.out diff -b $BASEDIR/spv.debugInfo.frag.out $TARGETDIR/spv.debugInfo.frag.out || HASERROR=1 $EXE -g -D -e newMain -g --amb --aml --fua --hlsl-iomap --nsf --sib 1 --ssb 2 --sbb 3 --stb 4 --suavb 5 --sub 6 \ - --sep origMain -H spv.hlslDebugInfo.vert --rsb vert t0 0 0 > $TARGETDIR/spv.hlslDebugInfo.frag.out + --sep origMain -H -Od spv.hlslDebugInfo.vert --rsb vert t0 0 0 > $TARGETDIR/spv.hlslDebugInfo.frag.out diff -b $BASEDIR/spv.hlslDebugInfo.frag.out $TARGETDIR/spv.hlslDebugInfo.frag.out || HASERROR=1 # # Testing Includer # echo Testing Includer -$EXE -D -e main -H ../Test/hlsl.include.vert > $TARGETDIR/hlsl.include.vert.out +$EXE -D -e main -H -Od ../Test/hlsl.include.vert > $TARGETDIR/hlsl.include.vert.out diff -b $BASEDIR/hlsl.include.vert.out $TARGETDIR/hlsl.include.vert.out || HASERROR=1 -$EXE -D -e main -H hlsl.includeNegative.vert > $TARGETDIR/hlsl.includeNegative.vert.out +$EXE -D -e main -H -Od hlsl.includeNegative.vert > $TARGETDIR/hlsl.includeNegative.vert.out diff -b $BASEDIR/hlsl.includeNegative.vert.out $TARGETDIR/hlsl.includeNegative.vert.out || HASERROR=1 $EXE -l -i include.vert > $TARGETDIR/include.vert.out diff -b $BASEDIR/include.vert.out $TARGETDIR/include.vert.out || HASERROR=1 -$EXE -D -e main -H -Iinc1/path1 -Iinc1/path2 hlsl.dashI.vert > $TARGETDIR/hlsl.dashI.vert.out +$EXE -D -e main -H -Od -Iinc1/path1 -Iinc1/path2 hlsl.dashI.vert > $TARGETDIR/hlsl.dashI.vert.out diff -b $BASEDIR/hlsl.dashI.vert.out $TARGETDIR/hlsl.dashI.vert.out || HASERROR=1 # @@ -145,7 +145,7 @@ diff -b $BASEDIR/hlsl.dashI.vert.out $TARGETDIR/hlsl.dashI.vert.out || HASERROR= echo "Testing -D and -U" $EXE -DUNDEFED -UIN_SHADER -DFOO=200 -i -l -UUNDEFED -DMUL=FOO*2 glsl.-D-U.frag > $TARGETDIR/glsl.-D-U.frag.out diff -b $BASEDIR/glsl.-D-U.frag.out $TARGETDIR/glsl.-D-U.frag.out || HASERROR=1 -$EXE -D -e main -V -i -DUNDEFED -UIN_SHADER -DFOO=200 -UUNDEFED hlsl.-D-U.frag > $TARGETDIR/hlsl.-D-U.frag.out +$EXE -D -e main -V -i -DUNDEFED -UIN_SHADER -DFOO=200 -UUNDEFED -Od hlsl.-D-U.frag > $TARGETDIR/hlsl.-D-U.frag.out diff -b $BASEDIR/hlsl.-D-U.frag.out $TARGETDIR/hlsl.-D-U.frag.out || HASERROR=1 # diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 14a7890a2c..51c2a4b976 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -59,9 +59,10 @@ std::string FileNameAsCustomTestSuffix( using HlslCompileTest = GlslangTest<::testing::TestWithParam>; using HlslCompileAndFlattenTest = GlslangTest<::testing::TestWithParam>; +using HlslLegalizeTest = GlslangTest<::testing::TestWithParam>; -// Compiling HLSL to SPIR-V under Vulkan semantics. Expected to successfully -// generate both AST and SPIR-V. +// Compiling HLSL to pre-legalized SPIR-V under Vulkan semantics. Expected +// to successfully generate both AST and SPIR-V. TEST_P(HlslCompileTest, FromFile) { loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, @@ -76,6 +77,16 @@ TEST_P(HlslCompileAndFlattenTest, FromFile) Target::BothASTAndSpv, GetParam().entryPoint); } +// Compiling HLSL to legal SPIR-V under Vulkan semantics. Expected to +// successfully generate SPIR-V. +TEST_P(HlslLegalizeTest, FromFile) +{ + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, + Source::HLSL, Semantics::Vulkan, + Target::Spv, GetParam().entryPoint, + "/baseLegalResults/", false); +} + // clang-format off INSTANTIATE_TEST_CASE_P( ToSpirv, HlslCompileTest, @@ -353,7 +364,20 @@ INSTANTIATE_TEST_CASE_P( }), FileNameAsCustomTestSuffix ); +// clang-format on +// clang-format off +INSTANTIATE_TEST_CASE_P( + ToSpirv, HlslLegalizeTest, + ::testing::ValuesIn(std::vector{ + {"hlsl.aliasOpaque.frag", "main"}, + {"hlsl.flattenOpaque.frag", "main"}, + {"hlsl.flattenOpaqueInit.vert", "main"}, + {"hlsl.flattenOpaqueInitMix.vert", "main"} + }), + FileNameAsCustomTestSuffix +); // clang-format on + } // anonymous namespace } // namespace glslangtest diff --git a/gtests/TestFixture.h b/gtests/TestFixture.h index a503b5fb22..2dac99bca2 100644 --- a/gtests/TestFixture.h +++ b/gtests/TestFixture.h @@ -198,7 +198,8 @@ class GlslangTest : public GT { const std::string shaderName, const std::string& code, const std::string& entryPointName, EShMessages controls, bool flattenUniformArrays = false, - EShTextureSamplerTransformMode texSampTransMode = EShTexSampTransKeep) + EShTextureSamplerTransformMode texSampTransMode = EShTexSampTransKeep, + bool disableOptimizer = true) { const EShLanguage kind = GetShaderStage(GetSuffix(shaderName)); @@ -217,8 +218,10 @@ class GlslangTest : public GT { if (success && (controls & EShMsgSpvRules)) { std::vector spirv_binary; + glslang::SpvOptions options; + options.disableOptimizer = disableOptimizer; glslang::GlslangToSpv(*program.getIntermediate(kind), - spirv_binary, &logger); + spirv_binary, &logger, &options); std::ostringstream disassembly_stream; spv::Parameterize(); @@ -381,18 +384,20 @@ class GlslangTest : public GT { Source source, Semantics semantics, Target target, - const std::string& entryPointName="") + const std::string& entryPointName="", + const std::string& baseDir="/baseResults/", + const bool disableOptimizer = true) { const std::string inputFname = testDir + "/" + testName; const std::string expectedOutputFname = - testDir + "/baseResults/" + testName + ".out"; + testDir + baseDir + testName + ".out"; std::string input, expectedOutput; tryLoadFile(inputFname, "input", &input); tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); const EShMessages controls = DeriveOptions(source, semantics, target); - GlslangResult result = compileAndLink(testName, input, entryPointName, controls); + GlslangResult result = compileAndLink(testName, input, entryPointName, controls, false, EShTexSampTransKeep, disableOptimizer); // Generate the hybrid output in the way of glslangValidator. std::ostringstream stream; diff --git a/known_good.json b/known_good.json new file mode 100644 index 0000000000..4e7d321a90 --- /dev/null +++ b/known_good.json @@ -0,0 +1,18 @@ +{ + "commits" : [ + { + "name" : "spirv-tools", + "site" : "github", + "subrepo" : "KhronosGroup/SPIRV-Tools", + "subdir" : "External/spirv-tools", + "commit" : "cf85ad1429de560eb1569cf6b36ba5a4ae5ff4be" + }, + { + "name" : "spirv-tools/external/spirv-headers", + "site" : "github", + "subrepo" : "KhronosGroup/SPIRV-Headers", + "subdir" : "External/spirv-tools/external/spirv-headers", + "commit" : "2bb92e6fe2c6aa410152fc6c63443f452acb1a65" + } + ] +} diff --git a/update_glslang_sources.py b/update_glslang_sources.py new file mode 100755 index 0000000000..b2988f92f2 --- /dev/null +++ b/update_glslang_sources.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python + +# Copyright 2017 The Glslang Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Get source files for Glslang and its dependencies from public repositories. +""" + +from __future__ import print_function + +import argparse +import json +import distutils.dir_util +import os.path +import subprocess +import sys + +KNOWN_GOOD_FILE = 'known_good.json' + +# Maps a site name to its hostname. +SITE_TO_HOST = { 'github' : 'github.com' } + +VERBOSE = True + + +def command_output(cmd, directory, fail_ok=False): + """Runs a command in a directory and returns its standard output stream. + + Captures the standard error stream. + + Raises a RuntimeError if the command fails to launch or otherwise fails. + """ + if VERBOSE: + print('In {d}: {cmd}'.format(d=directory, cmd=cmd)) + p = subprocess.Popen(cmd, + cwd=directory, + stdout=subprocess.PIPE) + (stdout, _) = p.communicate() + if p.returncode != 0 and not fail_ok: + raise RuntimeError('Failed to run {} in {}'.format(cmd, directory)) + if VERBOSE: + print(stdout) + return stdout + + +def command_retval(cmd, directory): + """Runs a command in a directory and returns its return value. + + Captures the standard error stream. + """ + p = subprocess.Popen(cmd, + cwd=directory, + stdout=subprocess.PIPE) + (stdout, _) = p.communicate() + return p.returncode + + +class GoodCommit(object): + """Represents a good commit for a repository.""" + + def __init__(self, json): + """Initializes this good commit object. + + Args: + 'json': A fully populated JSON object describing the commit. + """ + self._json = json + self.name = json['name'] + self.site = json['site'] + self.subrepo = json['subrepo'] + self.subdir = json['subdir'] if ('subdir' in json) else '.' + self.commit = json['commit'] + + def GetUrl(self, style='https'): + """Returns the URL for the repository.""" + host = SITE_TO_HOST[self.site] + sep = '/' if (style is 'https') else ':' + return '{style}://{host}{sep}{subrepo}'.format( + style=style, + host=host, + sep=sep, + subrepo=self.subrepo) + + def AddRemote(self): + """Add the remote 'known-good' if it does not exist.""" + print('Ignore "fatal" errors for missing known-good remote:') + if command_retval(['git', 'remote', 'show', 'known-good'], self.subdir) != 0: + command_output(['git', 'remote', 'add', 'known-good', self.GetUrl()], self.subdir) + + def HasCommit(self): + """Check if the repository contains the known-good commit.""" + return 0 == subprocess.call(['git', 'rev-parse', '--verify', '--quiet', + self.commit + "^{commit}"], + cwd=self.subdir) + + def Clone(self): + distutils.dir_util.mkpath(self.subdir) + command_output(['git', 'clone', self.GetUrl(), '.'], self.subdir) + + def Fetch(self): + command_output(['git', 'fetch', 'known-good'], self.subdir) + + def Checkout(self): + if not os.path.exists(os.path.join(self.subdir,'.git')): + self.Clone() + self.AddRemote() + if not self.HasCommit(): + self.Fetch() + command_output(['git', 'checkout', self.commit], self.subdir) + + +def GetGoodCommits(): + """Returns the latest list of GoodCommit objects.""" + with open(KNOWN_GOOD_FILE) as known_good: + return [GoodCommit(c) for c in json.loads(known_good.read())['commits']] + + +def main(): + parser = argparse.ArgumentParser(description='Get Glslang source dependencies at a known-good commit') + parser.add_argument('--dir', dest='dir', default='.', + help="Set target directory for Glslang source root. Default is \'.\'.") + + args = parser.parse_args() + + commits = GetGoodCommits() + + distutils.dir_util.mkpath(args.dir) + print('Change directory to {d}'.format(d=args.dir)) + os.chdir(args.dir) + + # Create the subdirectories in sorted order so that parent git repositories + # are created first. + for c in sorted(commits, cmp=lambda x,y: cmp(x.subdir, y.subdir)): + print('Get {n}\n'.format(n=c.name)) + c.Checkout() + sys.exit(0) + + +if __name__ == '__main__': + main()