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, to be fed to glslang to generate
8 // SPIR-V.
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(TCompiler * compiler,TInfoSinkBase & objSink,bool enablePrecision,ShCompileOptions compileOptions)22 TOutputVulkanGLSL::TOutputVulkanGLSL(TCompiler *compiler,
23 TInfoSinkBase &objSink,
24 bool enablePrecision,
25 ShCompileOptions compileOptions)
26 : TOutputGLSL(compiler, objSink, compileOptions),
27 mNextUnusedBinding(0),
28 mNextUnusedInputLocation(0),
29 mNextUnusedOutputLocation(0),
30 mEnablePrecision(enablePrecision)
31 {}
32
writeLayoutQualifier(TIntermSymbol * symbol)33 void TOutputVulkanGLSL::writeLayoutQualifier(TIntermSymbol *symbol)
34 {
35 const TType &type = symbol->getType();
36
37 bool needsSetBinding = IsSampler(type.getBasicType()) ||
38 (type.isInterfaceBlock() && (type.getQualifier() == EvqUniform ||
39 type.getQualifier() == EvqBuffer)) ||
40 IsImage(type.getBasicType()) || IsSubpassInputType(type.getBasicType());
41 bool needsLocation = type.getQualifier() == EvqAttribute ||
42 type.getQualifier() == EvqVertexIn ||
43 type.getQualifier() == EvqFragmentOut || IsVarying(type.getQualifier());
44 bool needsInputAttachmentIndex = IsSubpassInputType(type.getBasicType());
45 bool needsSpecConstId = type.getQualifier() == EvqSpecConst;
46
47 if (!NeedsToWriteLayoutQualifier(type) && !needsSetBinding && !needsLocation &&
48 !needsInputAttachmentIndex && !needsSpecConstId)
49 {
50 return;
51 }
52
53 TInfoSinkBase &out = objSink();
54 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
55
56 // This isn't super clean, but it gets the job done.
57 // See corresponding code in glslang_wrapper_utils.cpp.
58 const char *blockStorage = nullptr;
59 const char *matrixPacking = nullptr;
60
61 if (type.isInterfaceBlock())
62 {
63 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
64 TLayoutBlockStorage storage = interfaceBlock->blockStorage();
65
66 // Make sure block storage format is specified.
67 if (storage != EbsStd430)
68 {
69 // Change interface block layout qualifiers to std140 for any layout that is not
70 // explicitly set to std430. This is to comply with GL_KHR_vulkan_glsl where shared and
71 // packed are not allowed (and std140 could be used instead) and unspecified layouts can
72 // assume either std140 or std430 (and we choose std140 as std430 is not yet universally
73 // supported).
74 storage = EbsStd140;
75 }
76
77 if (interfaceBlock->blockStorage() != EbsUnspecified)
78 {
79 blockStorage = getBlockStorageString(storage);
80 }
81 }
82
83 // Specify matrix packing if necessary.
84 if (layoutQualifier.matrixPacking != EmpUnspecified)
85 {
86 matrixPacking = getMatrixPackingString(layoutQualifier.matrixPacking);
87 }
88 const char *kCommaSeparator = ", ";
89 const char *separator = "";
90 out << "layout(";
91
92 // If the resource declaration is about input attachment, need to specify input_attachment_index
93 if (needsInputAttachmentIndex)
94 {
95 out << "input_attachment_index=" << layoutQualifier.inputAttachmentIndex;
96 separator = kCommaSeparator;
97 }
98
99 // If it's a specialization constant, add that constant_id qualifier.
100 if (needsSpecConstId)
101 {
102 out << separator << "constant_id=" << layoutQualifier.location;
103 }
104
105 // If the resource declaration requires set & binding layout qualifiers, specify arbitrary
106 // ones.
107 if (needsSetBinding)
108 {
109 out << separator << "set=0, binding=" << nextUnusedBinding();
110 separator = kCommaSeparator;
111 }
112
113 if (needsLocation)
114 {
115 uint32_t location = 0;
116 if (layoutQualifier.index <= 0)
117 {
118 // Note: for index == 1 (dual source blending), don't count locations as they are
119 // expected to alias the color output locations. Only one dual-source output is
120 // supported, so location will be always 0.
121 const unsigned int locationCount =
122 CalculateVaryingLocationCount(symbol->getType(), getShaderType());
123 location = IsShaderIn(type.getQualifier()) ? nextUnusedInputLocation(locationCount)
124 : nextUnusedOutputLocation(locationCount);
125 }
126
127 out << separator << "location=" << location;
128 separator = kCommaSeparator;
129 }
130
131 // Output the list of qualifiers already known at this stage, i.e. everything other than
132 // `location` and `set`/`binding`.
133 std::string otherQualifiers = getCommonLayoutQualifiers(symbol);
134
135 if (blockStorage)
136 {
137 out << separator << blockStorage;
138 separator = kCommaSeparator;
139 }
140 if (matrixPacking)
141 {
142 out << separator << matrixPacking;
143 separator = kCommaSeparator;
144 }
145 if (!otherQualifiers.empty())
146 {
147 out << separator << otherQualifiers;
148 }
149
150 out << ") ";
151 }
152
writeVariableType(const TType & type,const TSymbol * symbol,bool isFunctionArgument)153 void TOutputVulkanGLSL::writeVariableType(const TType &type,
154 const TSymbol *symbol,
155 bool isFunctionArgument)
156 {
157 TType overrideType(type);
158
159 // External textures are treated as 2D textures in the vulkan back-end
160 if (type.getBasicType() == EbtSamplerExternalOES)
161 {
162 overrideType.setBasicType(EbtSampler2D);
163 }
164
165 TOutputGLSL::writeVariableType(overrideType, symbol, isFunctionArgument);
166 }
167
writeVariablePrecision(TPrecision precision)168 bool TOutputVulkanGLSL::writeVariablePrecision(TPrecision precision)
169 {
170 if ((precision == EbpUndefined) || !mEnablePrecision)
171 return false;
172
173 TInfoSinkBase &out = objSink();
174 out << getPrecisionString(precision);
175 return true;
176 }
177
178 } // namespace sh
179