• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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