Enable HLSL legalization

Also added known-good mechanism to fetch latest validated spirv-tools.
Also added -Od and -Os to disable optimizer and optimize for size.

Fetching spirv-tools is optional for both glsl and hlsl. Legalization
of hlsl is done by default if spirv-opt is present at cmake time.
Optimization for glsl is currently done through the option -Os.

Legalization testing is currently only done on four existing shaders.
A separate baseLegalResults directory holds those results. All previous
testing is done with the optimizer disabled.
This commit is contained in:
GregF 2017-09-21 18:40:22 -06:00
parent 44dd6a00c3
commit cd1f169c6a
16 changed files with 536 additions and 23 deletions

View File

@ -25,6 +25,7 @@ matrix:
# scripts that run after cloning repository # scripts that run after cloning repository
install: install:
- git clone https://github.com/google/googletest.git External/googletest - git clone https://github.com/google/googletest.git External/googletest
- update_glslang_sources.py
build: build:
parallel: true # enable MSBuild parallel builds parallel: true # enable MSBuild parallel builds

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ TAGS
build/ build/
Test/localResults/ Test/localResults/
External/googletest External/googletest
External/spirv-tools

View File

@ -55,6 +55,7 @@ install:
before_script: before_script:
- git clone --depth=1 https://github.com/google/googletest.git External/googletest - git clone --depth=1 https://github.com/google/googletest.git External/googletest
- update_glslang_sources.py
script: script:
- mkdir build && cd build - mkdir build && cd build

View File

@ -74,6 +74,14 @@ cd <the directory glslang was cloned to, "External" will be a subdirectory>
git clone https://github.com/google/googletest.git External/googletest 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 #### 3) Configure
Assume the source directory is `$SOURCE_DIR` and Assume the source directory is `$SOURCE_DIR` and

View File

@ -52,6 +52,16 @@ namespace spv {
#endif #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 // Glslang includes
#include "../glslang/MachineIndependent/localintermediate.h" #include "../glslang/MachineIndependent/localintermediate.h"
#include "../glslang/MachineIndependent/SymbolTable.h" #include "../glslang/MachineIndependent/SymbolTable.h"
@ -5960,6 +5970,12 @@ void OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName,
out.close(); out.close();
} }
#ifdef ENABLE_OPT
void errHandler(const std::string& str) {
std::cerr << str << std::endl;
}
#endif
// //
// Set up the glslang traversal // Set up the glslang traversal
// //
@ -5988,6 +6004,49 @@ void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsign
it.finishSpv(); it.finishSpv();
it.dumpSpv(spirv); it.dumpSpv(spirv);
#ifdef ENABLE_OPT
// If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan
// eg. forward and remove memory writes of opaque types.
if ((intermediate.getSource() == EShSourceHlsl ||
options->optimizeSize) &&
!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(); glslang::GetThreadPoolAllocator().pop();
} }

View File

@ -48,8 +48,11 @@
namespace glslang { namespace glslang {
struct SpvOptions { struct SpvOptions {
SpvOptions() : generateDebugInfo(false) { } SpvOptions() : generateDebugInfo(false), disableOptimizer(true),
optimizeSize(false) { }
bool generateDebugInfo; bool generateDebugInfo;
bool disableOptimizer;
bool optimizeSize;
}; };
void GetSpirvVersion(std::string&); void GetSpirvVersion(std::string&);

View File

@ -95,6 +95,8 @@ enum TOptions {
EOptionAutoMapLocations = (1 << 25), EOptionAutoMapLocations = (1 << 25),
EOptionDebug = (1 << 26), EOptionDebug = (1 << 26),
EOptionStdin = (1 << 27), EOptionStdin = (1 << 27),
EOptionOptimizeDisable = (1 << 28),
EOptionOptimizeSize = (1 << 29),
}; };
// //
@ -528,6 +530,18 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
case 'I': case 'I':
IncludeDirectoryList.push_back(getStringOperand("-I<dir> include path")); IncludeDirectoryList.push_back(getStringOperand("-I<dir> include path"));
break; 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': case 'S':
if (argc <= 1) if (argc <= 1)
Error("no <stage> specified for -S"); Error("no <stage> specified for -S");
@ -882,6 +896,8 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
glslang::SpvOptions spvOptions; glslang::SpvOptions spvOptions;
if (Options & EOptionDebug) if (Options & EOptionDebug)
spvOptions.generateDebugInfo = true; spvOptions.generateDebugInfo = true;
spvOptions.disableOptimizer = Options & EOptionOptimizeDisable;
spvOptions.optimizeSize = Options & EOptionOptimizeSize;
glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger, &spvOptions); glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger, &spvOptions);
// Dump the spv to a file or stdout, etc., but only if not doing // 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" " -H print human readable form of SPIR-V; turns on -V\n"
" -I<dir> add dir to the include search path; includer's directory\n" " -I<dir> add dir to the include search path; includer's directory\n"
" is searched first, followed by left-to-right order of -I\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 <stage> uses specified stage rather than parsing the file extension\n" " -S <stage> uses specified stage rather than parsing the file extension\n"
" choices for <stage> are vert, tesc, tese, geom, frag, or comp\n" " choices for <stage> are vert, tesc, tese, geom, frag, or comp\n"
" -U<macro> undefine a pre-processor macro\n" " -U<macro> undefine a pre-processor macro\n"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -32,11 +32,11 @@ diff -b $BASEDIR/badMacroArgs.frag.out $TARGETDIR/badMacroArgs.frag.out || HASER
echo Running reflection... echo Running reflection...
$EXE -l -q -C reflection.vert > $TARGETDIR/reflection.vert.out $EXE -l -q -C reflection.vert > $TARGETDIR/reflection.vert.out
diff -b $BASEDIR/reflection.vert.out $TARGETDIR/reflection.vert.out || HASERROR=1 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 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 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 diff -b $BASEDIR/hlsl.automap.frag.out $TARGETDIR/hlsl.automap.frag.out || HASERROR=1
# #
@ -56,14 +56,14 @@ fi
# entry point renaming tests # entry point renaming tests
# #
echo Running 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 diff -b $BASEDIR/hlsl.entry.rename.frag.out $TARGETDIR/hlsl.entry.rename.frag.out || HASERROR=1
# #
# Testing ill-defined uncalled function # Testing ill-defined uncalled function
# #
echo Running 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 diff -b $BASEDIR/hlsl.deadFunctionMissingBody.vert.out $TARGETDIR/hlsl.deadFunctionMissingBody.vert.out || HASERROR=1
if [ $HASERROR -eq 0 ] 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 diff -b $BASEDIR/spv.hlslOffsets.vert.out $TARGETDIR/spv.hlslOffsets.vert.out || HASERROR=1
echo Running hlsl offsets 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 diff -b $BASEDIR/hlsl.hlslOffset.vert.out $TARGETDIR/hlsl.hlslOffset.vert.out || HASERROR=1
# #
# Testing --resource-set-binding # Testing --resource-set-binding
# #
echo Configuring HLSL descriptor set and binding number manually 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 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 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 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 -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 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 \ $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 diff -b $BASEDIR/spv.hlslDebugInfo.frag.out $TARGETDIR/spv.hlslDebugInfo.frag.out || HASERROR=1
# #
# Testing Includer # Testing Includer
# #
echo 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 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 diff -b $BASEDIR/hlsl.includeNegative.vert.out $TARGETDIR/hlsl.includeNegative.vert.out || HASERROR=1
$EXE -l -i include.vert > $TARGETDIR/include.vert.out $EXE -l -i include.vert > $TARGETDIR/include.vert.out
diff -b $BASEDIR/include.vert.out $TARGETDIR/include.vert.out || HASERROR=1 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 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" 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 $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 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 -b $BASEDIR/hlsl.-D-U.frag.out $TARGETDIR/hlsl.-D-U.frag.out || HASERROR=1
# #

View File

@ -59,9 +59,10 @@ std::string FileNameAsCustomTestSuffix(
using HlslCompileTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>; using HlslCompileTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>;
using HlslCompileAndFlattenTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>; using HlslCompileAndFlattenTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>;
using HlslLegalizeTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>;
// Compiling HLSL to SPIR-V under Vulkan semantics. Expected to successfully // Compiling HLSL to pre-legalized SPIR-V under Vulkan semantics. Expected
// generate both AST and SPIR-V. // to successfully generate both AST and SPIR-V.
TEST_P(HlslCompileTest, FromFile) TEST_P(HlslCompileTest, FromFile)
{ {
loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam().fileName,
@ -76,6 +77,16 @@ TEST_P(HlslCompileAndFlattenTest, FromFile)
Target::BothASTAndSpv, GetParam().entryPoint); 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 // clang-format off
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
ToSpirv, HlslCompileTest, ToSpirv, HlslCompileTest,
@ -353,7 +364,20 @@ INSTANTIATE_TEST_CASE_P(
}), }),
FileNameAsCustomTestSuffix FileNameAsCustomTestSuffix
); );
// clang-format on // clang-format on
// clang-format off
INSTANTIATE_TEST_CASE_P(
ToSpirv, HlslLegalizeTest,
::testing::ValuesIn(std::vector<FileNameEntryPointPair>{
{"hlsl.aliasOpaque.frag", "main"},
{"hlsl.flattenOpaque.frag", "main"},
{"hlsl.flattenOpaqueInit.vert", "main"},
{"hlsl.flattenOpaqueInitMix.vert", "main"}
}),
FileNameAsCustomTestSuffix
);
// clang-format on
} // anonymous namespace } // anonymous namespace
} // namespace glslangtest } // namespace glslangtest

View File

@ -198,7 +198,8 @@ public:
const std::string shaderName, const std::string& code, const std::string shaderName, const std::string& code,
const std::string& entryPointName, EShMessages controls, const std::string& entryPointName, EShMessages controls,
bool flattenUniformArrays = false, bool flattenUniformArrays = false,
EShTextureSamplerTransformMode texSampTransMode = EShTexSampTransKeep) EShTextureSamplerTransformMode texSampTransMode = EShTexSampTransKeep,
bool disableOptimizer = true)
{ {
const EShLanguage kind = GetShaderStage(GetSuffix(shaderName)); const EShLanguage kind = GetShaderStage(GetSuffix(shaderName));
@ -217,8 +218,10 @@ public:
if (success && (controls & EShMsgSpvRules)) { if (success && (controls & EShMsgSpvRules)) {
std::vector<uint32_t> spirv_binary; std::vector<uint32_t> spirv_binary;
glslang::SpvOptions options;
options.disableOptimizer = disableOptimizer;
glslang::GlslangToSpv(*program.getIntermediate(kind), glslang::GlslangToSpv(*program.getIntermediate(kind),
spirv_binary, &logger); spirv_binary, &logger, &options);
std::ostringstream disassembly_stream; std::ostringstream disassembly_stream;
spv::Parameterize(); spv::Parameterize();
@ -381,18 +384,20 @@ public:
Source source, Source source,
Semantics semantics, Semantics semantics,
Target target, 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 inputFname = testDir + "/" + testName;
const std::string expectedOutputFname = const std::string expectedOutputFname =
testDir + "/baseResults/" + testName + ".out"; testDir + baseDir + testName + ".out";
std::string input, expectedOutput; std::string input, expectedOutput;
tryLoadFile(inputFname, "input", &input); tryLoadFile(inputFname, "input", &input);
tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
const EShMessages controls = DeriveOptions(source, semantics, target); 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. // Generate the hybrid output in the way of glslangValidator.
std::ostringstream stream; std::ostringstream stream;

18
known_good.json Normal file
View File

@ -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"
}
]
}

151
update_glslang_sources.py Executable file
View File

@ -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()