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 = CreateBuiltInUnaryFunctionCallNode(
288 "unpackSnorm4x8", flipXY, *symbolTable,
289 GetESSLOrGLSLVersion(symbolTable->getShaderSpec(), 310, 400));
290
291 if (stage == DriverUniformFlip::Fragment)
292 {
293 return new TIntermSwizzle(values, {0, 1});
294 }
295
296 return new TIntermSwizzle(values, {2, 3});
297 }
298
getNegFlipXY(TSymbolTable * symbolTable,DriverUniformFlip stage) const299 TIntermTyped *DriverUniform::getNegFlipXY(TSymbolTable *symbolTable, DriverUniformFlip stage) const
300 {
301 TIntermTyped *flipXY = getFlipXY(symbolTable, stage);
302
303 constexpr std::array<float, 2> kMultiplier = {1, -1};
304 return new TIntermBinary(EOpMul, flipXY, CreateVecNode(kMultiplier.data(), 2, EbpLow));
305 }
306
getDither() const307 TIntermTyped *DriverUniform::getDither() const
308 {
309 return createDriverUniformRef(kDither);
310 }
311
getSwapXY() const312 TIntermTyped *DriverUniform::getSwapXY() const
313 {
314 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
315 TIntermTyped *swapXY = new TIntermBinary(EOpBitwiseAnd, miscRef,
316 CreateUIntNode(vk::kDriverUniformsMiscSwapXYMask));
317
318 TIntermSequence args = {
319 swapXY,
320 };
321 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtBool, EbpUndefined>(),
322 &args);
323 }
324
getAdvancedBlendEquation() const325 TIntermTyped *DriverUniform::getAdvancedBlendEquation() const
326 {
327 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
328 TIntermTyped *equation =
329 new TIntermBinary(EOpBitShiftRight, miscRef,
330 CreateUIntNode(vk::kDriverUniformsMiscAdvancedBlendEquationOffset));
331 equation = new TIntermBinary(EOpBitwiseAnd, equation,
332 CreateUIntNode(vk::kDriverUniformsMiscAdvancedBlendEquationMask));
333
334 return equation;
335 }
336
getNumSamples() const337 TIntermTyped *DriverUniform::getNumSamples() const
338 {
339 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
340 TIntermTyped *sampleCount = new TIntermBinary(
341 EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscSampleCountOffset));
342 sampleCount = new TIntermBinary(EOpBitwiseAnd, sampleCount,
343 CreateUIntNode(vk::kDriverUniformsMiscSampleCountMask));
344
345 return sampleCount;
346 }
347
getClipDistancesEnabled() const348 TIntermTyped *DriverUniform::getClipDistancesEnabled() const
349 {
350 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
351 TIntermTyped *enabledMask = new TIntermBinary(
352 EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscEnabledClipPlanesOffset));
353 enabledMask = new TIntermBinary(EOpBitwiseAnd, enabledMask,
354 CreateUIntNode(vk::kDriverUniformsMiscEnabledClipPlanesMask));
355
356 return enabledMask;
357 }
358
getTransformDepth() const359 TIntermTyped *DriverUniform::getTransformDepth() const
360 {
361 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
362 TIntermTyped *transformDepth = new TIntermBinary(
363 EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscTransformDepthOffset));
364 transformDepth = new TIntermBinary(EOpBitwiseAnd, transformDepth,
365 CreateUIntNode(vk::kDriverUniformsMiscTransformDepthMask));
366
367 TIntermSequence args = {
368 transformDepth,
369 };
370 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtBool, EbpUndefined>(),
371 &args);
372 }
373
getAlphaToCoverage() const374 TIntermTyped *DriverUniform::getAlphaToCoverage() const
375 {
376 TIntermTyped *miscRef = createDriverUniformRef(kMisc);
377 TIntermTyped *alphaToCoverage = new TIntermBinary(
378 EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscAlphaToCoverageOffset));
379 alphaToCoverage = new TIntermBinary(EOpBitwiseAnd, alphaToCoverage,
380 CreateUIntNode(vk::kDriverUniformsMiscAlphaToCoverageMask));
381
382 TIntermSequence args = {
383 alphaToCoverage,
384 };
385 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtBool, EbpUndefined>(),
386 &args);
387 }
388
389 //
390 // Class DriverUniformExtended
391 //
createUniformFields(TSymbolTable * symbolTable)392 TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable)
393 {
394 TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable);
395
396 constexpr size_t kNumGraphicsDriverUniformsExt = 4;
397 constexpr std::array<const char *, kNumGraphicsDriverUniformsExt>
398 kGraphicsDriverUniformNamesExt = {
399 {kXfbBufferOffsets, kXfbVerticesPerInstance, kUnused, kUnused2}};
400
401 const std::array<TType *, kNumGraphicsDriverUniformsExt> kDriverUniformTypesExt = {{
402 // xfbBufferOffsets: uvec4
403 new TType(EbtInt, EbpHigh, EvqGlobal, 4),
404 // xfbVerticesPerInstance: uint
405 new TType(EbtInt, EbpHigh, EvqGlobal),
406 // unused: uvec3
407 new TType(EbtUInt, EbpHigh, EvqGlobal),
408 new TType(EbtUInt, EbpHigh, EvqGlobal, 2),
409 }};
410
411 for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniformsExt; ++uniformIndex)
412 {
413 TField *driverUniformField =
414 new TField(kDriverUniformTypesExt[uniformIndex],
415 ImmutableString(kGraphicsDriverUniformNamesExt[uniformIndex]), TSourceLoc(),
416 SymbolType::AngleInternal);
417 driverFieldList->push_back(driverUniformField);
418 }
419
420 return driverFieldList;
421 }
422
getXfbBufferOffsets() const423 TIntermTyped *DriverUniformExtended::getXfbBufferOffsets() const
424 {
425 return createDriverUniformRef(kXfbBufferOffsets);
426 }
427
getXfbVerticesPerInstance() const428 TIntermTyped *DriverUniformExtended::getXfbVerticesPerInstance() const
429 {
430 return createDriverUniformRef(kXfbVerticesPerInstance);
431 }
432
MakeSwapXMultiplier(TIntermTyped * swapped)433 TIntermTyped *MakeSwapXMultiplier(TIntermTyped *swapped)
434 {
435 // float(!swapped)
436 TIntermSequence args = {
437 new TIntermUnary(EOpLogicalNot, swapped, nullptr),
438 };
439 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtFloat, EbpLow>(), &args);
440 }
441
MakeSwapYMultiplier(TIntermTyped * swapped)442 TIntermTyped *MakeSwapYMultiplier(TIntermTyped *swapped)
443 {
444 // float(swapped)
445 TIntermSequence args = {
446 swapped,
447 };
448 return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtFloat, EbpLow>(), &args);
449 }
450 } // namespace sh
451