1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // OutputVulkanGLSL:
7 // Code that outputs shaders that fit GL_KHR_vulkan_glsl.
8 // The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side).
9 // See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt
10 //
11
12 #include "compiler/translator/OutputVulkanGLSL.h"
13
14 #include "compiler/translator/BaseTypes.h"
15 #include "compiler/translator/Symbol.h"
16 #include "compiler/translator/ValidateVaryingLocations.h"
17 #include "compiler/translator/util.h"
18
19 namespace sh
20 {
21
TOutputVulkanGLSL(TInfoSinkBase & objSink,ShArrayIndexClampingStrategy clampingStrategy,ShHashFunction64 hashFunction,NameMap & nameMap,TSymbolTable * symbolTable,sh::GLenum shaderType,int shaderVersion,ShShaderOutput output,bool forceHighp,bool enablePrecision,ShCompileOptions compileOptions)22 TOutputVulkanGLSL::TOutputVulkanGLSL(TInfoSinkBase &objSink,
23 ShArrayIndexClampingStrategy clampingStrategy,
24 ShHashFunction64 hashFunction,
25 NameMap &nameMap,
26 TSymbolTable *symbolTable,
27 sh::GLenum shaderType,
28 int shaderVersion,
29 ShShaderOutput output,
30 bool forceHighp,
31 bool enablePrecision,
32 ShCompileOptions compileOptions)
33 : TOutputGLSL(objSink,
34 clampingStrategy,
35 hashFunction,
36 nameMap,
37 symbolTable,
38 shaderType,
39 shaderVersion,
40 output,
41 compileOptions),
42 mNextUnusedBinding(0),
43 mNextUnusedInputLocation(0),
44 mNextUnusedOutputLocation(0),
45 mForceHighp(forceHighp),
46 mEnablePrecision(enablePrecision)
47 {}
48
writeLayoutQualifier(TIntermTyped * variable)49 void TOutputVulkanGLSL::writeLayoutQualifier(TIntermTyped *variable)
50 {
51 const TType &type = variable->getType();
52
53 bool needsSetBinding =
54 IsSampler(type.getBasicType()) || type.isInterfaceBlock() || IsImage(type.getBasicType());
55 bool needsLocation = type.getQualifier() == EvqAttribute ||
56 type.getQualifier() == EvqVertexIn ||
57 type.getQualifier() == EvqFragmentOut || IsVarying(type.getQualifier());
58
59 if (!NeedsToWriteLayoutQualifier(type) && !needsSetBinding && !needsLocation)
60 {
61 return;
62 }
63
64 TInfoSinkBase &out = objSink();
65 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
66
67 // This isn't super clean, but it gets the job done.
68 // See corresponding code in glslang_wrapper_utils.cpp.
69 TIntermSymbol *symbol = variable->getAsSymbolNode();
70 ASSERT(symbol);
71
72 ImmutableString name = symbol->getName();
73 const char *blockStorage = nullptr;
74 const char *matrixPacking = nullptr;
75
76 // For interface blocks, use the block name instead. When the layout qualifier is being
77 // replaced in the backend, that would be the name that's available.
78 if (type.isInterfaceBlock())
79 {
80 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
81 name = interfaceBlock->name();
82 TLayoutBlockStorage storage = interfaceBlock->blockStorage();
83
84 // Make sure block storage format is specified.
85 if (storage != EbsStd430)
86 {
87 // Change interface block layout qualifiers to std140 for any layout that is not
88 // explicitly set to std430. This is to comply with GL_KHR_vulkan_glsl where shared and
89 // packed are not allowed (and std140 could be used instead) and unspecified layouts can
90 // assume either std140 or std430 (and we choose std140 as std430 is not yet universally
91 // supported).
92 storage = EbsStd140;
93 }
94
95 if (interfaceBlock->blockStorage() != EbsUnspecified)
96 {
97 blockStorage = getBlockStorageString(storage);
98 }
99 }
100
101 // Specify matrix packing if necessary.
102 if (layoutQualifier.matrixPacking != EmpUnspecified)
103 {
104 matrixPacking = getMatrixPackingString(layoutQualifier.matrixPacking);
105 }
106
107 const char *separator = "";
108 out << "layout(";
109
110 // If the resource declaration requires set & binding layout qualifiers, specify arbitrary
111 // ones.
112 if (needsSetBinding)
113 {
114 out << "set=0, binding=" << nextUnusedBinding();
115 separator = ", ";
116 }
117
118 if (needsLocation)
119 {
120 const unsigned int locationCount = CalculateVaryingLocationCount(symbol, getShaderType());
121 uint32_t location = IsShaderIn(type.getQualifier())
122 ? nextUnusedInputLocation(locationCount)
123 : nextUnusedOutputLocation(locationCount);
124
125 out << "location=" << location;
126 separator = ", ";
127 }
128
129 // Output the list of qualifiers already known at this stage, i.e. everything other than
130 // `location` and `set`/`binding`.
131 std::string otherQualifiers = getCommonLayoutQualifiers(variable);
132
133 if (blockStorage)
134 {
135 out << separator << blockStorage;
136 separator = ", ";
137 }
138 if (matrixPacking)
139 {
140 out << separator << matrixPacking;
141 separator = ", ";
142 }
143 if (!otherQualifiers.empty())
144 {
145 out << separator << otherQualifiers;
146 }
147
148 out << ") ";
149 }
150
writeVariableType(const TType & type,const TSymbol * symbol,bool isFunctionArgument)151 void TOutputVulkanGLSL::writeVariableType(const TType &type,
152 const TSymbol *symbol,
153 bool isFunctionArgument)
154 {
155 TType overrideType(type);
156
157 // External textures are treated as 2D textures in the vulkan back-end
158 if (type.getBasicType() == EbtSamplerExternalOES)
159 {
160 overrideType.setBasicType(EbtSampler2D);
161 }
162
163 TOutputGLSL::writeVariableType(overrideType, symbol, isFunctionArgument);
164 }
165
writeStructType(const TStructure * structure)166 void TOutputVulkanGLSL::writeStructType(const TStructure *structure)
167 {
168 if (!structDeclared(structure))
169 {
170 declareStruct(structure);
171 objSink() << ";\n";
172 }
173 }
174
writeVariablePrecision(TPrecision precision)175 bool TOutputVulkanGLSL::writeVariablePrecision(TPrecision precision)
176 {
177 if ((precision == EbpUndefined) || !mEnablePrecision)
178 return false;
179
180 TInfoSinkBase &out = objSink();
181 if (mForceHighp)
182 out << getPrecisionString(EbpHigh);
183 else
184 out << getPrecisionString(precision);
185 return true;
186 }
187
188 } // namespace sh
189