1 //
2 // Copyright 2020 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 // DriverUniform.cpp: Add code to support driver uniforms
7 //
8 
9 #include "compiler/translator/tree_util/DriverUniform.h"
10 
11 #include "compiler/translator/Compiler.h"
12 #include "compiler/translator/IntermNode.h"
13 #include "compiler/translator/StaticType.h"
14 #include "compiler/translator/SymbolTable.h"
15 #include "compiler/translator/tree_util/FindMain.h"
16 #include "compiler/translator/tree_util/IntermNode_util.h"
17 #include "compiler/translator/tree_util/IntermTraverse.h"
18 #include "compiler/translator/util.h"
19 
20 namespace sh
21 {
22 
23 namespace
24 {
25 constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams");
26 
27 constexpr const char kViewport[]               = "viewport";
28 constexpr const char kClipDistancesEnabled[]   = "clipDistancesEnabled";
29 constexpr const char kXfbActiveUnpaused[]      = "xfbActiveUnpaused";
30 constexpr const char kXfbVerticesPerInstance[] = "xfbVerticesPerInstance";
31 constexpr const char kXfbBufferOffsets[]       = "xfbBufferOffsets";
32 constexpr const char kAcbBufferOffsets[]       = "acbBufferOffsets";
33 constexpr const char kDepthRange[]             = "depthRange";
34 constexpr const char kNumSamples[]             = "numSamples";
35 constexpr const char kHalfRenderArea[]         = "halfRenderArea";
36 constexpr const char kFlipXY[]                 = "flipXY";
37 constexpr const char kNegFlipXY[]              = "negFlipXY";
38 constexpr const char kPreRotation[]            = "preRotation";
39 constexpr const char kFragRotation[]           = "fragRotation";
40 constexpr const char kEmulatedInstanceId[]     = "emulatedInstanceID";
41 constexpr const char kCoverageMask[]           = "coverageMask";
42 
43 }  // anonymous namespace
44 
45 // Class DriverUniform
addComputeDriverUniformsToShader(TIntermBlock * root,TSymbolTable * symbolTable)46 bool DriverUniform::addComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
47 {
48     constexpr size_t kNumComputeDriverUniforms                                               = 1;
49     constexpr std::array<const char *, kNumComputeDriverUniforms> kComputeDriverUniformNames = {
50         {kAcbBufferOffsets}};
51 
52     ASSERT(!mDriverUniforms);
53     // This field list mirrors the structure of ComputeDriverUniforms in ContextVk.cpp.
54     TFieldList *driverFieldList = new TFieldList;
55 
56     const std::array<TType *, kNumComputeDriverUniforms> kDriverUniformTypes = {{
57         new TType(EbtUInt, 4),
58     }};
59 
60     for (size_t uniformIndex = 0; uniformIndex < kNumComputeDriverUniforms; ++uniformIndex)
61     {
62         TField *driverUniformField =
63             new TField(kDriverUniformTypes[uniformIndex],
64                        ImmutableString(kComputeDriverUniformNames[uniformIndex]), TSourceLoc(),
65                        SymbolType::AngleInternal);
66         driverFieldList->push_back(driverUniformField);
67     }
68 
69     // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
70     mDriverUniforms = DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
71                                             TLayoutQualifier::Create(), TMemoryQualifier::Create(),
72                                             0, ImmutableString(vk::kDriverUniformsBlockName),
73                                             ImmutableString(vk::kDriverUniformsVarName));
74     return mDriverUniforms != nullptr;
75 }
76 
createUniformFields(TSymbolTable * symbolTable)77 TFieldList *DriverUniform::createUniformFields(TSymbolTable *symbolTable)
78 {
79     constexpr size_t kNumGraphicsDriverUniforms                                                = 8;
80     constexpr std::array<const char *, kNumGraphicsDriverUniforms> kGraphicsDriverUniformNames = {
81         {kViewport, kClipDistancesEnabled, kXfbActiveUnpaused, kXfbVerticesPerInstance, kNumSamples,
82          kXfbBufferOffsets, kAcbBufferOffsets, kDepthRange}};
83 
84     // This field list mirrors the structure of GraphicsDriverUniforms in ContextVk.cpp.
85     TFieldList *driverFieldList = new TFieldList;
86 
87     const std::array<TType *, kNumGraphicsDriverUniforms> kDriverUniformTypes = {{
88         new TType(EbtFloat, 4),
89         new TType(EbtUInt),  // uint clipDistancesEnabled;  // 32 bits for 32 clip distances max
90         new TType(EbtUInt),
91         new TType(EbtInt),
92         new TType(EbtInt),
93         new TType(EbtInt, 4),
94         new TType(EbtUInt, 4),
95         createEmulatedDepthRangeType(symbolTable),
96     }};
97 
98     for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniforms; ++uniformIndex)
99     {
100         TField *driverUniformField =
101             new TField(kDriverUniformTypes[uniformIndex],
102                        ImmutableString(kGraphicsDriverUniformNames[uniformIndex]), TSourceLoc(),
103                        SymbolType::AngleInternal);
104         driverFieldList->push_back(driverUniformField);
105     }
106 
107     return driverFieldList;
108 }
109 
createEmulatedDepthRangeType(TSymbolTable * symbolTable)110 TType *DriverUniform::createEmulatedDepthRangeType(TSymbolTable *symbolTable)
111 {
112     // If already defined, return it immediately.
113     if (mEmulatedDepthRangeType != nullptr)
114     {
115         return mEmulatedDepthRangeType;
116     }
117 
118     // Create the depth range type.
119     TFieldList *depthRangeParamsFields = new TFieldList();
120     depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
121                                                  ImmutableString("near"), TSourceLoc(),
122                                                  SymbolType::AngleInternal));
123     depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
124                                                  ImmutableString("far"), TSourceLoc(),
125                                                  SymbolType::AngleInternal));
126     depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
127                                                  ImmutableString("diff"), TSourceLoc(),
128                                                  SymbolType::AngleInternal));
129     // This additional field might be used by subclass such as TranslatorMetal.
130     depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
131                                                  ImmutableString("reserved"), TSourceLoc(),
132                                                  SymbolType::AngleInternal));
133 
134     TStructure *emulatedDepthRangeParams = new TStructure(
135         symbolTable, kEmulatedDepthRangeParams, depthRangeParamsFields, SymbolType::AngleInternal);
136 
137     mEmulatedDepthRangeType = new TType(emulatedDepthRangeParams, false);
138 
139     // Note: this should really return a const TType *, but one of its uses is with TField who takes
140     // a non-const TType.  See comment on that class.
141     return mEmulatedDepthRangeType;
142 }
143 
144 // The Add*DriverUniformsToShader operation adds an internal uniform block to a shader. The driver
145 // block is used to implement Vulkan-specific features and workarounds. Returns the driver uniforms
146 // variable.
147 //
148 // There are Graphics and Compute variations as they require different uniforms.
addGraphicsDriverUniformsToShader(TIntermBlock * root,TSymbolTable * symbolTable)149 bool DriverUniform::addGraphicsDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
150 {
151     ASSERT(!mDriverUniforms);
152 
153     // Declare the depth range struct type.
154     TType *emulatedDepthRangeType     = createEmulatedDepthRangeType(symbolTable);
155     TType *emulatedDepthRangeDeclType = new TType(emulatedDepthRangeType->getStruct(), true);
156 
157     TVariable *depthRangeVar =
158         new TVariable(symbolTable->nextUniqueId(), kEmptyImmutableString, SymbolType::Empty,
159                       TExtension::UNDEFINED, emulatedDepthRangeDeclType);
160 
161     DeclareGlobalVariable(root, depthRangeVar);
162 
163     TFieldList *driverFieldList = createUniformFields(symbolTable);
164     if (mMode == DriverUniformMode::InterfaceBlock)
165     {
166         // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
167         mDriverUniforms = DeclareInterfaceBlock(
168             root, symbolTable, driverFieldList, EvqUniform, TLayoutQualifier::Create(),
169             TMemoryQualifier::Create(), 0, ImmutableString(vk::kDriverUniformsBlockName),
170             ImmutableString(vk::kDriverUniformsVarName));
171     }
172     else
173     {
174         // Declare a structure "ANGLEUniformBlock" with instance name "ANGLE_angleUniforms".
175         // This code path is taken only by the direct-to-Metal backend, and the assumptions
176         // about the naming conventions of ANGLE-internal variables run too deeply to rename
177         // this one.
178         auto varName    = ImmutableString("ANGLE_angleUniforms");
179         auto result     = DeclareStructure(root, symbolTable, driverFieldList, EvqUniform,
180                                        TMemoryQualifier::Create(), 0,
181                                        ImmutableString(vk::kDriverUniformsBlockName), &varName);
182         mDriverUniforms = result.second;
183     }
184 
185     return mDriverUniforms != nullptr;
186 }
187 
createDriverUniformRef(const char * fieldName) const188 TIntermBinary *DriverUniform::createDriverUniformRef(const char *fieldName) const
189 {
190     size_t fieldIndex = 0;
191     if (mMode == DriverUniformMode::InterfaceBlock)
192     {
193         fieldIndex =
194             FindFieldIndex(mDriverUniforms->getType().getInterfaceBlock()->fields(), fieldName);
195     }
196     else
197     {
198         fieldIndex = FindFieldIndex(mDriverUniforms->getType().getStruct()->fields(), fieldName);
199     }
200 
201     TIntermSymbol *angleUniformsRef = new TIntermSymbol(mDriverUniforms);
202     TConstantUnion *uniformIndex    = new TConstantUnion;
203     uniformIndex->setIConst(static_cast<int>(fieldIndex));
204     TIntermConstantUnion *indexRef =
205         new TIntermConstantUnion(uniformIndex, *StaticType::GetBasic<EbtInt>());
206     if (mMode == DriverUniformMode::InterfaceBlock)
207     {
208         return new TIntermBinary(EOpIndexDirectInterfaceBlock, angleUniformsRef, indexRef);
209     }
210     return new TIntermBinary(EOpIndexDirectStruct, angleUniformsRef, indexRef);
211 }
212 
getViewportRef() const213 TIntermBinary *DriverUniform::getViewportRef() const
214 {
215     return createDriverUniformRef(kViewport);
216 }
217 
getAbcBufferOffsets() const218 TIntermBinary *DriverUniform::getAbcBufferOffsets() const
219 {
220     return createDriverUniformRef(kAcbBufferOffsets);
221 }
222 
getXfbActiveUnpaused() const223 TIntermBinary *DriverUniform::getXfbActiveUnpaused() const
224 {
225     return createDriverUniformRef(kXfbActiveUnpaused);
226 }
227 
getXfbVerticesPerInstance() const228 TIntermBinary *DriverUniform::getXfbVerticesPerInstance() const
229 {
230     return createDriverUniformRef(kXfbVerticesPerInstance);
231 }
232 
getXfbBufferOffsets() const233 TIntermBinary *DriverUniform::getXfbBufferOffsets() const
234 {
235     return createDriverUniformRef(kXfbBufferOffsets);
236 }
237 
getClipDistancesEnabled() const238 TIntermBinary *DriverUniform::getClipDistancesEnabled() const
239 {
240     return createDriverUniformRef(kClipDistancesEnabled);
241 }
242 
getDepthRangeRef() const243 TIntermBinary *DriverUniform::getDepthRangeRef() const
244 {
245     return createDriverUniformRef(kDepthRange);
246 }
247 
getDepthRangeReservedFieldRef() const248 TIntermBinary *DriverUniform::getDepthRangeReservedFieldRef() const
249 {
250     TIntermBinary *depthRange = createDriverUniformRef(kDepthRange);
251 
252     return new TIntermBinary(EOpIndexDirectStruct, depthRange, CreateIndexNode(3));
253 }
254 
getNumSamplesRef() const255 TIntermBinary *DriverUniform::getNumSamplesRef() const
256 {
257     return createDriverUniformRef(kNumSamples);
258 }
259 
260 //
261 // Class DriverUniformExtended
262 //
createUniformFields(TSymbolTable * symbolTable)263 TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable)
264 {
265     TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable);
266 
267     constexpr size_t kNumGraphicsDriverUniformsExt = 7;
268     constexpr std::array<const char *, kNumGraphicsDriverUniformsExt>
269         kGraphicsDriverUniformNamesExt = {{kHalfRenderArea, kFlipXY, kNegFlipXY,
270                                            kEmulatedInstanceId, kCoverageMask, kFragRotation,
271                                            kPreRotation}};
272 
273     const std::array<TType *, kNumGraphicsDriverUniformsExt> kDriverUniformTypesExt = {{
274         new TType(EbtFloat, 2),
275         new TType(EbtFloat, 2),
276         new TType(EbtFloat, 2),
277         new TType(EbtUInt),
278         new TType(EbtUInt),
279         new TType(EbtFloat, 2, 2),
280         new TType(EbtFloat, 2, 2),
281     }};
282 
283     for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniformsExt; ++uniformIndex)
284     {
285         TField *driverUniformField =
286             new TField(kDriverUniformTypesExt[uniformIndex],
287                        ImmutableString(kGraphicsDriverUniformNamesExt[uniformIndex]), TSourceLoc(),
288                        SymbolType::AngleInternal);
289         driverFieldList->push_back(driverUniformField);
290     }
291 
292     return driverFieldList;
293 }
294 
getFlipXYRef() const295 TIntermBinary *DriverUniformExtended::getFlipXYRef() const
296 {
297     return createDriverUniformRef(kFlipXY);
298 }
299 
getNegFlipXYRef() const300 TIntermBinary *DriverUniformExtended::getNegFlipXYRef() const
301 {
302     return createDriverUniformRef(kNegFlipXY);
303 }
304 
getNegFlipYRef() const305 TIntermSwizzle *DriverUniformExtended::getNegFlipYRef() const
306 {
307     // Create a swizzle to "negFlipXY.y"
308     TIntermBinary *negFlipXY    = createDriverUniformRef(kNegFlipXY);
309     TVector<int> swizzleOffsetY = {1};
310     TIntermSwizzle *negFlipY    = new TIntermSwizzle(negFlipXY, swizzleOffsetY);
311     return negFlipY;
312 }
313 
getPreRotationMatrixRef() const314 TIntermBinary *DriverUniformExtended::getPreRotationMatrixRef() const
315 {
316     return createDriverUniformRef(kPreRotation);
317 }
318 
getFragRotationMatrixRef() const319 TIntermBinary *DriverUniformExtended::getFragRotationMatrixRef() const
320 {
321     return createDriverUniformRef(kFragRotation);
322 }
323 
getHalfRenderAreaRef() const324 TIntermBinary *DriverUniformExtended::getHalfRenderAreaRef() const
325 {
326     return createDriverUniformRef(kHalfRenderArea);
327 }
328 
getEmulatedInstanceId() const329 TIntermBinary *DriverUniformExtended::getEmulatedInstanceId() const
330 {
331     return createDriverUniformRef(kEmulatedInstanceId);
332 }
333 
getCoverageMask() const334 TIntermBinary *DriverUniformExtended::getCoverageMask() const
335 {
336     return createDriverUniformRef(kCoverageMask);
337 }
338 
339 }  // namespace sh
340