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 constexpr ImmutableString kDriverUniformsBlockName = ImmutableString("ANGLEUniformBlock");
27 constexpr ImmutableString kDriverUniformsVarName = ImmutableString("ANGLEUniforms");
28
29 constexpr const char kAcbBufferOffsets[] = "acbBufferOffsets";
30 constexpr const char kDepthRange[] = "depthRange";
31 constexpr const char kRenderArea[] = "renderArea";
32 constexpr const char kFlipXY[] = "flipXY";
33 constexpr const char kDither[] = "dither";
34 constexpr const char kMisc[] = "misc";
35
36 // Extended uniforms
37 constexpr const char kXfbBufferOffsets[] = "xfbBufferOffsets";
38 constexpr const char kXfbVerticesPerInstance[] = "xfbVerticesPerInstance";
39 constexpr const char kUnused[] = "unused";
40 constexpr const char kUnused2[] = "unused2";
41 } // anonymous namespace
42
43 // Class DriverUniform
addComputeDriverUniformsToShader(TIntermBlock * root,TSymbolTable * symbolTable)44 bool DriverUniform::addComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
45 {
46 constexpr size_t kNumComputeDriverUniforms = 1;
47 constexpr std::array<const char *, kNumComputeDriverUniforms> kComputeDriverUniformNames = {
48 {kAcbBufferOffsets}};
49
50 ASSERT(!mDriverUniforms);
51 // This field list mirrors the structure of ComputeDriverUniforms in ContextVk.cpp.
52 TFieldList *driverFieldList = new TFieldList;
53
54 const std::array<TType *, kNumComputeDriverUniforms> kDriverUniformTypes = {{
55 new TType(EbtUInt, EbpHigh, EvqGlobal, 4),
56 }};
57
58 for (size_t uniformIndex = 0; uniformIndex < kNumComputeDriverUniforms; ++uniformIndex)
59 {
60 TField *driverUniformField =
61 new TField(kDriverUniformTypes[uniformIndex],
62 ImmutableString(kComputeDriverUniformNames[uniformIndex]), TSourceLoc(),
63 SymbolType::AngleInternal);
64 driverFieldList->push_back(driverUniformField);
65 }
66
67 // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
68 TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
69 layoutQualifier.blockStorage = EbsStd140;
70 layoutQualifier.pushConstant = true;
71
72 mDriverUniforms = DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
73 layoutQualifier, TMemoryQualifier::Create(), 0,
74 kDriverUniformsBlockName, kDriverUniformsVarName);
75 return mDriverUniforms != nullptr;
76 }
77
createUniformFields(TSymbolTable * symbolTable)78 TFieldList *DriverUniform::createUniformFields(TSymbolTable *symbolTable)
79 {
80 constexpr size_t kNumGraphicsDriverUniforms = 6;
81 constexpr std::array<const char *, kNumGraphicsDriverUniforms> kGraphicsDriverUniformNames = {{
82 kAcbBufferOffsets,
83 kDepthRange,
84 kRenderArea,
85 kFlipXY,
86 kDither,
87 kMisc,
88 }};
89
90 // This field list mirrors the structure of GraphicsDriverUniforms in ContextVk.cpp.
91 TFieldList *driverFieldList = new TFieldList;
92
93 const std::array<TType *, kNumGraphicsDriverUniforms> kDriverUniformTypes = {{
94 // acbBufferOffsets: Packed ubyte8
95 new TType(EbtUInt, EbpHigh, EvqGlobal, 2),
96 // depthRange: Near and far depth
97 new TType(EbtFloat, EbpHigh, EvqGlobal, 2),
98 // renderArea: Packed ushort2
99 new TType(EbtUInt, EbpHigh, EvqGlobal),
100 // flipXY: Packed snorm4
101 new TType(EbtUInt, EbpHigh, EvqGlobal),
102 // dither: ushort
103 new TType(EbtUInt, EbpHigh, EvqGlobal),
104 // misc: Various bits of state
105 new TType(EbtUInt, EbpHigh, EvqGlobal),
106 }};
107
108 for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniforms; ++uniformIndex)
109 {
110 TField *driverUniformField =
111 new TField(kDriverUniformTypes[uniformIndex],
112 ImmutableString(kGraphicsDriverUniformNames[uniformIndex]), TSourceLoc(),
113 SymbolType::AngleInternal);
114 driverFieldList->push_back(driverUniformField);
115 }
116
117 return driverFieldList;
118 }
119
createEmulatedDepthRangeType(TSymbolTable * symbolTable)120 const TType *DriverUniform::createEmulatedDepthRangeType(TSymbolTable *symbolTable)
121 {
122 // If already defined, return it immediately.
123 if (mEmulatedDepthRangeType != nullptr)
124 {
125 return mEmulatedDepthRangeType;
126 }
127
128 // Create the depth range type.
129 TFieldList *depthRangeParamsFields = new TFieldList();
130 TType *floatType = new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1);
131 depthRangeParamsFields->push_back(
132 new TField(floatType, ImmutableString("near"), TSourceLoc(), SymbolType::AngleInternal));
133 depthRangeParamsFields->push_back(
134 new TField(floatType, ImmutableString("far"), TSourceLoc(), SymbolType::AngleInternal));
135 depthRangeParamsFields->push_back(
136 new TField(floatType, ImmutableString("diff"), TSourceLoc(), SymbolType::AngleInternal));
137
138 TStructure *emulatedDepthRangeParams = new TStructure(
139 symbolTable, kEmulatedDepthRangeParams, depthRangeParamsFields, SymbolType::AngleInternal);
140
141 mEmulatedDepthRangeType = new TType(emulatedDepthRangeParams, false);
142
143 return mEmulatedDepthRangeType;
144 }
145
146 // The Add*DriverUniformsToShader operation adds an internal uniform block to a shader. The driver
147 // block is used to implement Vulkan-specific features and workarounds. Returns the driver uniforms
148 // variable.
149 //
150 // There are Graphics and Compute variations as they require different uniforms.
addGraphicsDriverUniformsToShader(TIntermBlock * root,TSymbolTable * symbolTable)151 bool DriverUniform::addGraphicsDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
152 {
153 ASSERT(!mDriverUniforms);
154
155 // Declare the depth range struct type.
156 const TType *emulatedDepthRangeType = createEmulatedDepthRangeType(symbolTable);
157 const TType *emulatedDepthRangeDeclType = new TType(emulatedDepthRangeType->getStruct(), true);
158
159 const TVariable *depthRangeVar =
160 new TVariable(symbolTable->nextUniqueId(), kEmptyImmutableString, SymbolType::Empty,
161 TExtension::UNDEFINED, emulatedDepthRangeDeclType);
162
163 DeclareGlobalVariable(root, depthRangeVar);
164
165 TFieldList *driverFieldList = createUniformFields(symbolTable);
166 if (mMode == DriverUniformMode::InterfaceBlock)
167 {
168 // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
169 TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
170 layoutQualifier.blockStorage = EbsStd140;
171 layoutQualifier.pushConstant = true;
172
173 mDriverUniforms = DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
174 layoutQualifier, TMemoryQualifier::Create(), 0,
175 kDriverUniformsBlockName, kDriverUniformsVarName);
176 }
177 else
178 {
179 // Declare a structure "ANGLEUniformBlock" with instance name "ANGLE_angleUniforms".
180 // This code path is taken only by the direct-to-Metal backend, and the assumptions
181 // about the naming conventions of ANGLE-internal variables run too deeply to rename
182 // this one.
183 auto varName = ImmutableString("ANGLE_angleUniforms");
184 auto result =
185 DeclareStructure(root, symbolTable, driverFieldList, EvqUniform,
186 TMemoryQualifier::Create(), 0, kDriverUniformsBlockName, &varName);
187 mDriverUniforms = result.second;
188 }
189
190 return mDriverUniforms != nullptr;
191 }
192
createDriverUniformRef(const char * fieldName) const193 TIntermTyped *DriverUniform::createDriverUniformRef(const char *fieldName) const
194 {
195 size_t fieldIndex = 0;
196 if (mMode == DriverUniformMode::InterfaceBlock)
197 {
198 fieldIndex =
199 FindFieldIndex(mDriverUniforms->getType().getInterfaceBlock()->fields(), fieldName);
200 }
201 else
202 {
203 fieldIndex = FindFieldIndex(mDriverUniforms->getType().getStruct()->fields(), fieldName);
204 }
205
206 TIntermSymbol *angleUniformsRef = new TIntermSymbol(mDriverUniforms);
207 TConstantUnion *uniformIndex = new TConstantUnion;
208 uniformIndex->setIConst(static_cast<int>(fieldIndex));
209 TIntermConstantUnion *indexRef =
210 new TIntermConstantUnion(uniformIndex, *StaticType::GetBasic<EbtInt, EbpLow>());
211 if (mMode == DriverUniformMode::InterfaceBlock)
212 {
213 return new TIntermBinary(EOpIndexDirectInterfaceBlock, angleUniformsRef, indexRef);
214 }
215 return new TIntermBinary(EOpIndexDirectStruct, angleUniformsRef, indexRef);
216 }
217
getAcbBufferOffsets() const218 TIntermTyped *DriverUniform::getAcbBufferOffsets() const
219 {
220 return createDriverUniformRef(kAcbBufferOffsets);
221 }
222
getDepthRange() const223 TIntermTyped *DriverUniform::getDepthRange() const
224 {
225 ASSERT(mEmulatedDepthRangeType != nullptr);
226
227 TIntermTyped *depthRangeRef = createDriverUniformRef(kDepthRange);
228 TIntermTyped *nearRef = new TIntermSwizzle(depthRangeRef, {0});
229 TIntermTyped *farRef = new TIntermSwizzle(depthRangeRef->deepCopy(), {1});
230 TIntermTyped *diff = new TIntermBinary(EOpSub, farRef, nearRef);
231
232 TIntermSequence args = {
233 nearRef->deepCopy(),
234 farRef->deepCopy(),
235 diff,
236 };
237
238 return TIntermAggregate::CreateConstructor(*mEmulatedDepthRangeType, &args);
239 }
240
getViewportZScale() const241 TIntermTyped *DriverUniform::getViewportZScale() const
242 {
243 ASSERT(mEmulatedDepthRangeType != nullptr);
244
245 TIntermTyped *depthRangeRef = createDriverUniformRef(kDepthRange);
246 TIntermTyped *nearRef = new TIntermSwizzle(depthRangeRef, {0});
247 TIntermTyped *farRef = new TIntermSwizzle(depthRangeRef->deepCopy(), {1});
248
249 TIntermTyped *isNegative = new TIntermBinary(EOpLessThan, farRef, nearRef);
250
251 return new TIntermTernary(isNegative, CreateFloatNode(-1, EbpMedium),
252 CreateFloatNode(1, EbpMedium));
253 }
254
getHalfRenderArea() const255 TIntermTyped *DriverUniform::getHalfRenderArea() const
256 {
257 TIntermTyped *renderAreaRef = createDriverUniformRef(kRenderArea);
258 TIntermTyped *width = new TIntermBinary(EOpBitwiseAnd, renderAreaRef, CreateUIntNode(0xFFFF));
259 TIntermTyped *height =
260 new TIntermBinary(EOpBitShiftRight, renderAreaRef->deepCopy(), CreateUIntNode(16));
261
262 TIntermSequence widthArgs = {
263 width,
264 };
265 TIntermTyped *widthAsFloat =
266 TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtFloat, EbpHigh>(), &widthArgs);
267
268 TIntermSequence heightArgs = {
269 height,
270 };
271 TIntermTyped *heightAsFloat = TIntermAggregate::CreateConstructor(
272 *StaticType::GetBasic<EbtFloat, EbpHigh>(), &heightArgs);
273
274 TIntermSequence args = {
275 widthAsFloat,
276 heightAsFloat,
277 };
278
279 TIntermTyped *renderArea =
280 TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtFloat, EbpHigh, 2>(), &args);
281 return new TIntermBinary(EOpVectorTimesScalar, renderArea, CreateFloatNode(0.5, EbpMedium));
282 }
283
getFlipXY(TSymbolTable * symbolTable,DriverUniformFlip stage) const284 TIntermTyped *DriverUniform::getFlipXY(TSymbolTable *symbolTable, DriverUniformFlip stage) const
285 {
286 TIntermTyped *flipXY = createDriverUniformRef(kFlipXY);
287 TIntermTyped *values =
288 CreateBuiltInUnaryFunctionCallNode("unpackSnorm4x8", flipXY, *symbolTable, 310);
289
290 if (stage == DriverUniformFlip::Fragment)
291 {
292 return new TIntermSwizzle(values, {0, 1});
293 }
294
295 return new TIntermSwizzle(values, {2, 3});
296 }
297
getNegFlipXY(TSymbolTable * symbolTable,DriverUniformFlip stage) const298 TIntermTyped *DriverUniform::getNegFlipXY(TSymbolTable *symbolTable, DriverUniformFlip stage) const
299 {
300 TIntermTyped *flipXY = getFlipXY(symbolTable, stage);
301
302 constexpr std::array<float, 2> kMultiplier = {1, -1};
303 return new TIntermBinary(EOpMul, flipXY, CreateVecNode(kMultiplier.data(), 2, EbpLow));
304 }
305
getDither() const306 TIntermTyped *DriverUniform::getDither() const
307 {
308 return createDriverUniformRef(kDither);
309 }
310
getSwapXY() const311 TIntermTyped *DriverUniform::getSwapXY() const
312 {
313 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
314 TIntermTyped *swapXY = new TIntermBinary(EOpBitwiseAnd, miscRef,
315 CreateUIntNode(vk::kDriverUniformsMiscSwapXYMask));
316
317 TIntermSequence args = {
318 swapXY,
319 };
320 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtBool, EbpUndefined>(),
321 &args);
322 }
323
getAdvancedBlendEquation() const324 TIntermTyped *DriverUniform::getAdvancedBlendEquation() const
325 {
326 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
327 TIntermTyped *equation =
328 new TIntermBinary(EOpBitShiftRight, miscRef,
329 CreateUIntNode(vk::kDriverUniformsMiscAdvancedBlendEquationOffset));
330 equation = new TIntermBinary(EOpBitwiseAnd, equation,
331 CreateUIntNode(vk::kDriverUniformsMiscAdvancedBlendEquationMask));
332
333 return equation;
334 }
335
getNumSamples() const336 TIntermTyped *DriverUniform::getNumSamples() const
337 {
338 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
339 TIntermTyped *sampleCount = new TIntermBinary(
340 EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscSampleCountOffset));
341 sampleCount = new TIntermBinary(EOpBitwiseAnd, sampleCount,
342 CreateUIntNode(vk::kDriverUniformsMiscSampleCountMask));
343
344 return sampleCount;
345 }
346
getClipDistancesEnabled() const347 TIntermTyped *DriverUniform::getClipDistancesEnabled() const
348 {
349 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
350 TIntermTyped *enabledMask = new TIntermBinary(
351 EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscEnabledClipPlanesOffset));
352 enabledMask = new TIntermBinary(EOpBitwiseAnd, enabledMask,
353 CreateUIntNode(vk::kDriverUniformsMiscEnabledClipPlanesMask));
354
355 return enabledMask;
356 }
357
getTransformDepth() const358 TIntermTyped *DriverUniform::getTransformDepth() const
359 {
360 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
361 TIntermTyped *transformDepth = new TIntermBinary(
362 EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscTransformDepthOffset));
363 transformDepth = new TIntermBinary(EOpBitwiseAnd, transformDepth,
364 CreateUIntNode(vk::kDriverUniformsMiscTransformDepthMask));
365
366 TIntermSequence args = {
367 transformDepth,
368 };
369 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtBool, EbpUndefined>(),
370 &args);
371 }
372
getAlphaToCoverage() const373 TIntermTyped *DriverUniform::getAlphaToCoverage() const
374 {
375 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
376 TIntermTyped *alphaToCoverage = new TIntermBinary(
377 EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscAlphaToCoverageOffset));
378 alphaToCoverage = new TIntermBinary(EOpBitwiseAnd, alphaToCoverage,
379 CreateUIntNode(vk::kDriverUniformsMiscAlphaToCoverageMask));
380
381 TIntermSequence args = {
382 alphaToCoverage,
383 };
384 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtBool, EbpUndefined>(),
385 &args);
386 }
387
getLayeredFramebuffer() const388 TIntermTyped *DriverUniform::getLayeredFramebuffer() const
389 {
390 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
391 TIntermTyped *layeredFramebuffer = new TIntermBinary(
392 EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscLayeredFramebufferOffset));
393 layeredFramebuffer =
394 new TIntermBinary(EOpBitwiseAnd, layeredFramebuffer,
395 CreateUIntNode(vk::kDriverUniformsMiscLayeredFramebufferMask));
396
397 TIntermSequence args = {
398 layeredFramebuffer,
399 };
400 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtBool, EbpUndefined>(),
401 &args);
402 }
403
404 //
405 // Class DriverUniformExtended
406 //
createUniformFields(TSymbolTable * symbolTable)407 TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable)
408 {
409 TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable);
410
411 constexpr size_t kNumGraphicsDriverUniformsExt = 4;
412 constexpr std::array<const char *, kNumGraphicsDriverUniformsExt>
413 kGraphicsDriverUniformNamesExt = {
414 {kXfbBufferOffsets, kXfbVerticesPerInstance, kUnused, kUnused2}};
415
416 const std::array<TType *, kNumGraphicsDriverUniformsExt> kDriverUniformTypesExt = {{
417 // xfbBufferOffsets: uvec4
418 new TType(EbtInt, EbpHigh, EvqGlobal, 4),
419 // xfbVerticesPerInstance: uint
420 new TType(EbtInt, EbpHigh, EvqGlobal),
421 // unused: uvec3
422 new TType(EbtUInt, EbpHigh, EvqGlobal),
423 new TType(EbtUInt, EbpHigh, EvqGlobal, 2),
424 }};
425
426 for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniformsExt; ++uniformIndex)
427 {
428 TField *driverUniformField =
429 new TField(kDriverUniformTypesExt[uniformIndex],
430 ImmutableString(kGraphicsDriverUniformNamesExt[uniformIndex]), TSourceLoc(),
431 SymbolType::AngleInternal);
432 driverFieldList->push_back(driverUniformField);
433 }
434
435 return driverFieldList;
436 }
437
getXfbBufferOffsets() const438 TIntermTyped *DriverUniformExtended::getXfbBufferOffsets() const
439 {
440 return createDriverUniformRef(kXfbBufferOffsets);
441 }
442
getXfbVerticesPerInstance() const443 TIntermTyped *DriverUniformExtended::getXfbVerticesPerInstance() const
444 {
445 return createDriverUniformRef(kXfbVerticesPerInstance);
446 }
447
MakeSwapXMultiplier(TIntermTyped * swapped)448 TIntermTyped *MakeSwapXMultiplier(TIntermTyped *swapped)
449 {
450 // float(!swapped)
451 TIntermSequence args = {
452 new TIntermUnary(EOpLogicalNot, swapped, nullptr),
453 };
454 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtFloat, EbpLow>(), &args);
455 }
456
MakeSwapYMultiplier(TIntermTyped * swapped)457 TIntermTyped *MakeSwapYMultiplier(TIntermTyped *swapped)
458 {
459 // float(swapped)
460 TIntermSequence args = {
461 swapped,
462 };
463 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtFloat, EbpLow>(), &args);
464 }
465 } // namespace sh
466