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 kUnused[] = "_unused";
30 constexpr const char kAdvancedBlendEquation[] = "advancedBlendEquation";
31 constexpr const char kXfbVerticesPerInstance[] = "xfbVerticesPerInstance";
32 constexpr const char kXfbBufferOffsets[] = "xfbBufferOffsets";
33 constexpr const char kAcbBufferOffsets[] = "acbBufferOffsets";
34 constexpr const char kDepthRange[] = "depthRange";
35 constexpr const char kNumSamples[] = "numSamples";
36 constexpr const char kHalfRenderArea[] = "halfRenderArea";
37 constexpr const char kFlipXY[] = "flipXY";
38 constexpr const char kNegFlipXY[] = "negFlipXY";
39 constexpr const char kPreRotation[] = "preRotation";
40 constexpr const char kFragRotation[] = "fragRotation";
41 constexpr const char kDither[] = "dither";
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, EbpHigh, EvqGlobal, 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 TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
71 layoutQualifier.blockStorage = EbsStd140;
72
73 mDriverUniforms = DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
74 layoutQualifier, TMemoryQualifier::Create(), 0,
75 ImmutableString(vk::kDriverUniformsBlockName),
76 ImmutableString(vk::kDriverUniformsVarName));
77 return mDriverUniforms != nullptr;
78 }
79
createUniformFields(TSymbolTable * symbolTable)80 TFieldList *DriverUniform::createUniformFields(TSymbolTable *symbolTable)
81 {
82 constexpr size_t kNumGraphicsDriverUniforms = 8;
83 constexpr std::array<const char *, kNumGraphicsDriverUniforms> kGraphicsDriverUniformNames = {
84 {kViewport, kClipDistancesEnabled, kAdvancedBlendEquation, kXfbVerticesPerInstance,
85 kNumSamples, kXfbBufferOffsets, kAcbBufferOffsets, kDepthRange}};
86
87 // This field list mirrors the structure of GraphicsDriverUniforms in ContextVk.cpp.
88 TFieldList *driverFieldList = new TFieldList;
89
90 const std::array<TType *, kNumGraphicsDriverUniforms> kDriverUniformTypes = {{
91 new TType(EbtFloat, EbpHigh, EvqGlobal, 4),
92 new TType(EbtUInt, EbpHigh,
93 EvqGlobal), // uint clipDistancesEnabled; // 32 bits for 32 clip distances max
94 new TType(
95 EbtUInt, EbpLow,
96 EvqGlobal), // uint advancedBlendEquation;
97 // Up to BlendEquationType::HslLuminosity-BlendEquationType::Multiply+1
98 new TType(EbtInt, EbpHigh, EvqGlobal),
99 new TType(EbtInt, EbpLow, EvqGlobal), // uint numSamples; // Up to 16
100 new TType(EbtInt, EbpHigh, EvqGlobal, 4),
101 new TType(EbtUInt, EbpHigh, EvqGlobal, 4),
102 createEmulatedDepthRangeType(symbolTable),
103 }};
104
105 for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniforms; ++uniformIndex)
106 {
107 TField *driverUniformField =
108 new TField(kDriverUniformTypes[uniformIndex],
109 ImmutableString(kGraphicsDriverUniformNames[uniformIndex]), TSourceLoc(),
110 SymbolType::AngleInternal);
111 driverFieldList->push_back(driverUniformField);
112 }
113
114 return driverFieldList;
115 }
116
createEmulatedDepthRangeType(TSymbolTable * symbolTable)117 TType *DriverUniform::createEmulatedDepthRangeType(TSymbolTable *symbolTable)
118 {
119 // If already defined, return it immediately.
120 if (mEmulatedDepthRangeType != nullptr)
121 {
122 return mEmulatedDepthRangeType;
123 }
124
125 // Create the depth range type.
126 TFieldList *depthRangeParamsFields = new TFieldList();
127 TType *floatType = new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1);
128 depthRangeParamsFields->push_back(
129 new TField(floatType, ImmutableString("near"), TSourceLoc(), SymbolType::AngleInternal));
130 depthRangeParamsFields->push_back(
131 new TField(floatType, ImmutableString("far"), TSourceLoc(), SymbolType::AngleInternal));
132 depthRangeParamsFields->push_back(
133 new TField(floatType, ImmutableString("diff"), TSourceLoc(), SymbolType::AngleInternal));
134 // This additional field might be used by subclass such as TranslatorMetal.
135 depthRangeParamsFields->push_back(new TField(floatType, ImmutableString("reserved"),
136 TSourceLoc(), SymbolType::AngleInternal));
137
138 TStructure *emulatedDepthRangeParams = new TStructure(
139 symbolTable, kEmulatedDepthRangeParams, depthRangeParamsFields, SymbolType::AngleInternal);
140
141 mEmulatedDepthRangeType = new TType(emulatedDepthRangeParams, false);
142
143 // Note: this should really return a const TType *, but one of its uses is with TField who takes
144 // a non-const TType. See comment on that class.
145 return mEmulatedDepthRangeType;
146 }
147
148 // The Add*DriverUniformsToShader operation adds an internal uniform block to a shader. The driver
149 // block is used to implement Vulkan-specific features and workarounds. Returns the driver uniforms
150 // variable.
151 //
152 // There are Graphics and Compute variations as they require different uniforms.
addGraphicsDriverUniformsToShader(TIntermBlock * root,TSymbolTable * symbolTable)153 bool DriverUniform::addGraphicsDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
154 {
155 ASSERT(!mDriverUniforms);
156
157 // Declare the depth range struct type.
158 TType *emulatedDepthRangeType = createEmulatedDepthRangeType(symbolTable);
159 TType *emulatedDepthRangeDeclType = new TType(emulatedDepthRangeType->getStruct(), true);
160
161 TVariable *depthRangeVar =
162 new TVariable(symbolTable->nextUniqueId(), kEmptyImmutableString, SymbolType::Empty,
163 TExtension::UNDEFINED, emulatedDepthRangeDeclType);
164
165 DeclareGlobalVariable(root, depthRangeVar);
166
167 TFieldList *driverFieldList = createUniformFields(symbolTable);
168 if (mMode == DriverUniformMode::InterfaceBlock)
169 {
170 // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
171 TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
172 layoutQualifier.blockStorage = EbsStd140;
173
174 mDriverUniforms = DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
175 layoutQualifier, TMemoryQualifier::Create(), 0,
176 ImmutableString(vk::kDriverUniformsBlockName),
177 ImmutableString(vk::kDriverUniformsVarName));
178 }
179 else
180 {
181 // Declare a structure "ANGLEUniformBlock" with instance name "ANGLE_angleUniforms".
182 // This code path is taken only by the direct-to-Metal backend, and the assumptions
183 // about the naming conventions of ANGLE-internal variables run too deeply to rename
184 // this one.
185 auto varName = ImmutableString("ANGLE_angleUniforms");
186 auto result = DeclareStructure(root, symbolTable, driverFieldList, EvqUniform,
187 TMemoryQualifier::Create(), 0,
188 ImmutableString(vk::kDriverUniformsBlockName), &varName);
189 mDriverUniforms = result.second;
190 }
191
192 return mDriverUniforms != nullptr;
193 }
194
createDriverUniformRef(const char * fieldName) const195 TIntermTyped *DriverUniform::createDriverUniformRef(const char *fieldName) const
196 {
197 size_t fieldIndex = 0;
198 if (mMode == DriverUniformMode::InterfaceBlock)
199 {
200 fieldIndex =
201 FindFieldIndex(mDriverUniforms->getType().getInterfaceBlock()->fields(), fieldName);
202 }
203 else
204 {
205 fieldIndex = FindFieldIndex(mDriverUniforms->getType().getStruct()->fields(), fieldName);
206 }
207
208 TIntermSymbol *angleUniformsRef = new TIntermSymbol(mDriverUniforms);
209 TConstantUnion *uniformIndex = new TConstantUnion;
210 uniformIndex->setIConst(static_cast<int>(fieldIndex));
211 TIntermConstantUnion *indexRef =
212 new TIntermConstantUnion(uniformIndex, *StaticType::GetBasic<EbtInt, EbpLow>());
213 if (mMode == DriverUniformMode::InterfaceBlock)
214 {
215 return new TIntermBinary(EOpIndexDirectInterfaceBlock, angleUniformsRef, indexRef);
216 }
217 return new TIntermBinary(EOpIndexDirectStruct, angleUniformsRef, indexRef);
218 }
219
getViewportRef() const220 TIntermTyped *DriverUniform::getViewportRef() const
221 {
222 return createDriverUniformRef(kViewport);
223 }
224
getAbcBufferOffsets() const225 TIntermTyped *DriverUniform::getAbcBufferOffsets() const
226 {
227 return createDriverUniformRef(kAcbBufferOffsets);
228 }
229
getXfbVerticesPerInstance() const230 TIntermTyped *DriverUniform::getXfbVerticesPerInstance() const
231 {
232 return createDriverUniformRef(kXfbVerticesPerInstance);
233 }
234
getXfbBufferOffsets() const235 TIntermTyped *DriverUniform::getXfbBufferOffsets() const
236 {
237 return createDriverUniformRef(kXfbBufferOffsets);
238 }
239
getClipDistancesEnabled() const240 TIntermTyped *DriverUniform::getClipDistancesEnabled() const
241 {
242 return createDriverUniformRef(kClipDistancesEnabled);
243 }
244
getDepthRangeRef() const245 TIntermTyped *DriverUniform::getDepthRangeRef() const
246 {
247 return createDriverUniformRef(kDepthRange);
248 }
249
getDepthRangeReservedFieldRef() const250 TIntermTyped *DriverUniform::getDepthRangeReservedFieldRef() const
251 {
252 TIntermTyped *depthRange = createDriverUniformRef(kDepthRange);
253
254 return new TIntermBinary(EOpIndexDirectStruct, depthRange, CreateIndexNode(3));
255 }
256
getNumSamplesRef() const257 TIntermTyped *DriverUniform::getNumSamplesRef() const
258 {
259 return createDriverUniformRef(kNumSamples);
260 }
261
getAdvancedBlendEquationRef() const262 TIntermTyped *DriverUniform::getAdvancedBlendEquationRef() const
263 {
264 return createDriverUniformRef(kAdvancedBlendEquation);
265 }
266
267 //
268 // Class DriverUniformExtended
269 //
createUniformFields(TSymbolTable * symbolTable)270 TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable)
271 {
272 TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable);
273
274 constexpr size_t kNumGraphicsDriverUniformsExt = 7;
275 constexpr std::array<const char *, kNumGraphicsDriverUniformsExt>
276 kGraphicsDriverUniformNamesExt = {
277 {kHalfRenderArea, kFlipXY, kNegFlipXY, kDither, kUnused, kFragRotation, kPreRotation}};
278
279 const std::array<TType *, kNumGraphicsDriverUniformsExt> kDriverUniformTypesExt = {{
280 new TType(EbtFloat, EbpHigh, EvqGlobal, 2),
281 new TType(EbtFloat, EbpLow, EvqGlobal, 2),
282 new TType(EbtFloat, EbpLow, EvqGlobal, 2),
283 new TType(EbtUInt, EbpHigh, EvqGlobal),
284 new TType(EbtUInt, EbpHigh, EvqGlobal),
285 new TType(EbtFloat, EbpLow, EvqGlobal, 2, 2),
286 new TType(EbtFloat, EbpLow, EvqGlobal, 2, 2),
287 }};
288
289 for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniformsExt; ++uniformIndex)
290 {
291 TField *driverUniformField =
292 new TField(kDriverUniformTypesExt[uniformIndex],
293 ImmutableString(kGraphicsDriverUniformNamesExt[uniformIndex]), TSourceLoc(),
294 SymbolType::AngleInternal);
295 driverFieldList->push_back(driverUniformField);
296 }
297
298 return driverFieldList;
299 }
300
getFlipXYRef() const301 TIntermTyped *DriverUniformExtended::getFlipXYRef() const
302 {
303 return createDriverUniformRef(kFlipXY);
304 }
305
getNegFlipXYRef() const306 TIntermTyped *DriverUniformExtended::getNegFlipXYRef() const
307 {
308 return createDriverUniformRef(kNegFlipXY);
309 }
310
getNegFlipYRef() const311 TIntermTyped *DriverUniformExtended::getNegFlipYRef() const
312 {
313 // Create a swizzle to "negFlipXY.y"
314 TIntermTyped *negFlipXY = createDriverUniformRef(kNegFlipXY);
315 TVector<int> swizzleOffsetY = {1};
316 TIntermSwizzle *negFlipY = new TIntermSwizzle(negFlipXY, swizzleOffsetY);
317 return negFlipY;
318 }
319
getPreRotationMatrixRef() const320 TIntermTyped *DriverUniformExtended::getPreRotationMatrixRef() const
321 {
322 return createDriverUniformRef(kPreRotation);
323 }
324
getFragRotationMatrixRef() const325 TIntermTyped *DriverUniformExtended::getFragRotationMatrixRef() const
326 {
327 return createDriverUniformRef(kFragRotation);
328 }
329
getHalfRenderAreaRef() const330 TIntermTyped *DriverUniformExtended::getHalfRenderAreaRef() const
331 {
332 return createDriverUniformRef(kHalfRenderArea);
333 }
334
getDitherRef() const335 TIntermTyped *DriverUniformExtended::getDitherRef() const
336 {
337 return createDriverUniformRef(kDither);
338 }
339
340 } // namespace sh
341