• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // SpecializationConst.cpp: Add code to generate AST node for various specialization constants.
7 //
8 
9 #include "compiler/translator/tree_util/SpecializationConstant.h"
10 #include "common/PackedEnums.h"
11 #include "common/angleutils.h"
12 #include "compiler/translator/StaticType.h"
13 #include "compiler/translator/SymbolTable.h"
14 #include "compiler/translator/tree_util/IntermNode_util.h"
15 
16 namespace sh
17 {
18 
19 namespace
20 {
21 // Specialization constant names
22 constexpr ImmutableString kLineRasterEmulationSpecConstVarName =
23     ImmutableString("ANGLELineRasterEmulation");
24 constexpr ImmutableString kSurfaceRotationSpecConstVarName =
25     ImmutableString("ANGLESurfaceRotation");
26 constexpr ImmutableString kDrawableWidthSpecConstVarName  = ImmutableString("ANGLEDrawableWidth");
27 constexpr ImmutableString kDrawableHeightSpecConstVarName = ImmutableString("ANGLEDrawableHeight");
28 
29 // When an Android surface is rotated differently than the device's native orientation, ANGLE must
30 // rotate gl_Position in the vertex shader and gl_FragCoord in the fragment shader.  The following
31 // are the rotation matrices used.
32 //
33 // This is 2x2 matrix in column major. The first column is for dFdx and second column is for dFdy.
34 using Mat2x2 = std::array<float, 4>;
35 using Mat2x2EnumMap =
36     angle::PackedEnumMap<vk::SurfaceRotation, Mat2x2, angle::EnumSize<vk::SurfaceRotation>()>;
37 
38 constexpr Mat2x2EnumMap kPreRotationMatrices = {
39     {{vk::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 1.0f}}},
40      {vk::SurfaceRotation::Rotated90Degrees, {{0.0f, -1.0f, 1.0f, 0.0f}}},
41      {vk::SurfaceRotation::Rotated180Degrees, {{-1.0f, 0.0f, 0.0f, -1.0f}}},
42      {vk::SurfaceRotation::Rotated270Degrees, {{0.0f, 1.0f, -1.0f, 0.0f}}},
43      {vk::SurfaceRotation::FlippedIdentity, {{1.0f, 0.0f, 0.0f, 1.0f}}},
44      {vk::SurfaceRotation::FlippedRotated90Degrees, {{0.0f, -1.0f, 1.0f, 0.0f}}},
45      {vk::SurfaceRotation::FlippedRotated180Degrees, {{-1.0f, 0.0f, 0.0f, -1.0f}}},
46      {vk::SurfaceRotation::FlippedRotated270Degrees, {{0.0f, 1.0f, -1.0f, 0.0f}}}}};
47 
48 constexpr Mat2x2EnumMap kFragRotationMatrices = {
49     {{vk::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 1.0f}}},
50      {vk::SurfaceRotation::Rotated90Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}},
51      {vk::SurfaceRotation::Rotated180Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}},
52      {vk::SurfaceRotation::Rotated270Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}},
53      {vk::SurfaceRotation::FlippedIdentity, {{1.0f, 0.0f, 0.0f, 1.0f}}},
54      {vk::SurfaceRotation::FlippedRotated90Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}},
55      {vk::SurfaceRotation::FlippedRotated180Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}},
56      {vk::SurfaceRotation::FlippedRotated270Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}}}};
57 
58 // TODO: https://issuetracker.google.com/174066134. This is to make sure the specialization constant
59 // code path behaves exactly the same as driver uniform code path. Not sure why this has to be
60 // different from kFragRotationMatrices.
61 constexpr Mat2x2EnumMap kHalfRenderAreaRotationMatrices = {
62     {{vk::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 1.0f}}},
63      {vk::SurfaceRotation::Rotated90Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}},
64      {vk::SurfaceRotation::Rotated180Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}},
65      {vk::SurfaceRotation::Rotated270Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}},
66      {vk::SurfaceRotation::FlippedIdentity, {{1.0f, 0.0f, 0.0f, 1.0f}}},
67      {vk::SurfaceRotation::FlippedRotated90Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}},
68      {vk::SurfaceRotation::FlippedRotated180Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}},
69      {vk::SurfaceRotation::FlippedRotated270Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}}}};
70 
71 // Returns mat2(m0, m1, m2, m3)
CreateMat2x2(const Mat2x2EnumMap & matrix,vk::SurfaceRotation rotation)72 TIntermAggregate *CreateMat2x2(const Mat2x2EnumMap &matrix, vk::SurfaceRotation rotation)
73 {
74     auto mat2Type = new TType(EbtFloat, 2, 2);
75     TIntermSequence mat2Args;
76     mat2Args.push_back(CreateFloatNode(matrix[rotation][0]));
77     mat2Args.push_back(CreateFloatNode(matrix[rotation][1]));
78     mat2Args.push_back(CreateFloatNode(matrix[rotation][2]));
79     mat2Args.push_back(CreateFloatNode(matrix[rotation][3]));
80     TIntermAggregate *constVarConstructor =
81         TIntermAggregate::CreateConstructor(*mat2Type, &mat2Args);
82     return constVarConstructor;
83 }
84 
85 // Generates an array of vec2 and then use rotation to retrieve the desired flipXY out.
GenerateMat2x2ArrayWithIndex(const Mat2x2EnumMap & matrix,TIntermSymbol * rotation)86 TIntermTyped *GenerateMat2x2ArrayWithIndex(const Mat2x2EnumMap &matrix, TIntermSymbol *rotation)
87 {
88     auto mat2Type        = new TType(EbtFloat, 2, 2);
89     TType *typeMat2Array = new TType(*mat2Type);
90     typeMat2Array->makeArray(static_cast<unsigned int>(vk::SurfaceRotation::EnumCount));
91 
92     TIntermSequence sequences = {
93         CreateMat2x2(matrix, vk::SurfaceRotation::Identity),
94         CreateMat2x2(matrix, vk::SurfaceRotation::Rotated90Degrees),
95         CreateMat2x2(matrix, vk::SurfaceRotation::Rotated180Degrees),
96         CreateMat2x2(matrix, vk::SurfaceRotation::Rotated270Degrees),
97         CreateMat2x2(matrix, vk::SurfaceRotation::FlippedIdentity),
98         CreateMat2x2(matrix, vk::SurfaceRotation::FlippedRotated90Degrees),
99         CreateMat2x2(matrix, vk::SurfaceRotation::FlippedRotated180Degrees),
100         CreateMat2x2(matrix, vk::SurfaceRotation::FlippedRotated270Degrees)};
101     TIntermTyped *array = TIntermAggregate::CreateConstructor(*typeMat2Array, &sequences);
102     return new TIntermBinary(EOpIndexIndirect, array, rotation);
103 }
104 
105 using Vec2 = std::array<float, 2>;
106 using Vec2EnumMap =
107     angle::PackedEnumMap<vk::SurfaceRotation, Vec2, angle::EnumSize<vk::SurfaceRotation>()>;
108 constexpr Vec2EnumMap kFlipXYValue = {
109     {{vk::SurfaceRotation::Identity, {{1.0f, 1.0f}}},
110      {vk::SurfaceRotation::Rotated90Degrees, {{1.0f, 1.0f}}},
111      {vk::SurfaceRotation::Rotated180Degrees, {{-1.0f, 1.0f}}},
112      {vk::SurfaceRotation::Rotated270Degrees, {{-1.0f, -1.0f}}},
113      {vk::SurfaceRotation::FlippedIdentity, {{1.0f, -1.0f}}},
114      {vk::SurfaceRotation::FlippedRotated90Degrees, {{1.0f, 1.0f}}},
115      {vk::SurfaceRotation::FlippedRotated180Degrees, {{-1.0f, 1.0f}}},
116      {vk::SurfaceRotation::FlippedRotated270Degrees, {{-1.0f, -1.0f}}}}};
117 
118 // Returns [[flipX*m0+flipY*m1]  [flipX*m2+flipY*m3]] where [m0 m1] is the first column of
119 // kFragRotation matrix and [m2 m3] is the second column of kFragRotation matrix.
CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation rotation)120 constexpr Vec2 CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation rotation)
121 {
122     return Vec2({kFlipXYValue[rotation][0] * kFragRotationMatrices[rotation][0] +
123                      kFlipXYValue[rotation][1] * kFragRotationMatrices[rotation][1],
124                  kFlipXYValue[rotation][0] * kFragRotationMatrices[rotation][2] +
125                      kFlipXYValue[rotation][1] * kFragRotationMatrices[rotation][3]});
126 }
127 
128 // Returns vec2(vec2Values.x, vec2Values.y*yscale)
CreateVec2(Vec2EnumMap vec2Values,float yscale,vk::SurfaceRotation rotation)129 TIntermAggregate *CreateVec2(Vec2EnumMap vec2Values, float yscale, vk::SurfaceRotation rotation)
130 {
131     auto vec2Type = new TType(EbtFloat, 2);
132     TIntermSequence vec2Args;
133     vec2Args.push_back(CreateFloatNode(vec2Values[rotation][0]));
134     vec2Args.push_back(CreateFloatNode(vec2Values[rotation][1] * yscale));
135     TIntermAggregate *constVarConstructor =
136         TIntermAggregate::CreateConstructor(*vec2Type, &vec2Args);
137     return constVarConstructor;
138 }
139 
140 // Generates an array of vec2 and then use rotation to retrieve the desired flipXY out.
CreateVec2ArrayWithIndex(Vec2EnumMap vec2Values,float yscale,TIntermSymbol * rotation)141 TIntermTyped *CreateVec2ArrayWithIndex(Vec2EnumMap vec2Values,
142                                        float yscale,
143                                        TIntermSymbol *rotation)
144 {
145     auto vec2Type        = new TType(EbtFloat, 2);
146     TType *typeVec2Array = new TType(*vec2Type);
147     typeVec2Array->makeArray(static_cast<unsigned int>(vk::SurfaceRotation::EnumCount));
148 
149     TIntermSequence sequences = {
150         CreateVec2(vec2Values, yscale, vk::SurfaceRotation::Identity),
151         CreateVec2(vec2Values, yscale, vk::SurfaceRotation::Rotated90Degrees),
152         CreateVec2(vec2Values, yscale, vk::SurfaceRotation::Rotated180Degrees),
153         CreateVec2(vec2Values, yscale, vk::SurfaceRotation::Rotated270Degrees),
154         CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedIdentity),
155         CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedRotated90Degrees),
156         CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedRotated180Degrees),
157         CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedRotated270Degrees)};
158     TIntermTyped *vec2Array = TIntermAggregate::CreateConstructor(*typeVec2Array, &sequences);
159     return new TIntermBinary(EOpIndexIndirect, vec2Array, rotation);
160 }
161 
162 // Returns [flipX*m0, flipY*m1], where [m0 m1] is the first column of kFragRotation matrix.
CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation rotation)163 constexpr Vec2 CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation rotation)
164 {
165     return Vec2({kFlipXYValue[rotation][0] * kFragRotationMatrices[rotation][0],
166                  kFlipXYValue[rotation][1] * kFragRotationMatrices[rotation][1]});
167 }
168 constexpr Vec2EnumMap kRotatedFlipXYForDFdx = {
169     {{vk::SurfaceRotation::Identity, CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::Identity)},
170      {vk::SurfaceRotation::Rotated90Degrees,
171       CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::Rotated90Degrees)},
172      {vk::SurfaceRotation::Rotated180Degrees,
173       CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::Rotated180Degrees)},
174      {vk::SurfaceRotation::Rotated270Degrees,
175       CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::Rotated270Degrees)},
176      {vk::SurfaceRotation::FlippedIdentity,
177       CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::FlippedIdentity)},
178      {vk::SurfaceRotation::FlippedRotated90Degrees,
179       CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::FlippedRotated90Degrees)},
180      {vk::SurfaceRotation::FlippedRotated180Degrees,
181       CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::FlippedRotated180Degrees)},
182      {vk::SurfaceRotation::FlippedRotated270Degrees,
183       CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::FlippedRotated270Degrees)}}};
184 
185 // Returns [flipX*m2, flipY*m3], where [m2 m3] is the second column of kFragRotation matrix.
CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation rotation)186 constexpr Vec2 CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation rotation)
187 {
188     return Vec2({kFlipXYValue[rotation][0] * kFragRotationMatrices[rotation][2],
189                  kFlipXYValue[rotation][1] * kFragRotationMatrices[rotation][3]});
190 }
191 constexpr Vec2EnumMap kRotatedFlipXYForDFdy = {
192     {{vk::SurfaceRotation::Identity, CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::Identity)},
193      {vk::SurfaceRotation::Rotated90Degrees,
194       CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::Rotated90Degrees)},
195      {vk::SurfaceRotation::Rotated180Degrees,
196       CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::Rotated180Degrees)},
197      {vk::SurfaceRotation::Rotated270Degrees,
198       CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::Rotated270Degrees)},
199      {vk::SurfaceRotation::FlippedIdentity,
200       CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::FlippedIdentity)},
201      {vk::SurfaceRotation::FlippedRotated90Degrees,
202       CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::FlippedRotated90Degrees)},
203      {vk::SurfaceRotation::FlippedRotated180Degrees,
204       CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::FlippedRotated180Degrees)},
205      {vk::SurfaceRotation::FlippedRotated270Degrees,
206       CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::FlippedRotated270Degrees)}}};
207 
208 // Returns an array of float and then use rotation to retrieve the desired float value out.
CreateFloatArrayWithRotationIndex(const Vec2EnumMap & valuesEnumMap,int subscript,float scale,TIntermSymbol * rotation)209 TIntermTyped *CreateFloatArrayWithRotationIndex(const Vec2EnumMap &valuesEnumMap,
210                                                 int subscript,
211                                                 float scale,
212                                                 TIntermSymbol *rotation)
213 {
214     const TType *floatType = StaticType::GetBasic<EbtFloat>();
215     TType *typeFloat8      = new TType(*floatType);
216     typeFloat8->makeArray(static_cast<unsigned int>(vk::SurfaceRotation::EnumCount));
217 
218     TIntermSequence sequences = {
219         CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::Identity][subscript] * scale),
220         CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::Rotated90Degrees][subscript] * scale),
221         CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::Rotated180Degrees][subscript] * scale),
222         CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::Rotated270Degrees][subscript] * scale),
223         CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::FlippedIdentity][subscript] * scale),
224         CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::FlippedRotated90Degrees][subscript] *
225                         scale),
226         CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::FlippedRotated180Degrees][subscript] *
227                         scale),
228         CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::FlippedRotated270Degrees][subscript] *
229                         scale)};
230     TIntermTyped *array = TIntermAggregate::CreateConstructor(*typeFloat8, &sequences);
231 
232     return new TIntermBinary(EOpIndexIndirect, array, rotation);
233 }
234 
MakeSpecConst(const TType & type,vk::SpecializationConstantId id)235 const TType *MakeSpecConst(const TType &type, vk::SpecializationConstantId id)
236 {
237     // Create a new type with the EvqSpecConst qualifier
238     TType *specConstType = new TType(type);
239     specConstType->setQualifier(EvqSpecConst);
240 
241     // Set the constant_id of the spec const
242     TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
243     layoutQualifier.location         = static_cast<int>(id);
244     specConstType->setLayoutQualifier(layoutQualifier);
245 
246     return specConstType;
247 }
248 }  // anonymous namespace
249 
SpecConst(TSymbolTable * symbolTable,ShCompileOptions compileOptions,GLenum shaderType)250 SpecConst::SpecConst(TSymbolTable *symbolTable, ShCompileOptions compileOptions, GLenum shaderType)
251     : mSymbolTable(symbolTable),
252       mCompileOptions(compileOptions),
253       mLineRasterEmulationVar(nullptr),
254       mSurfaceRotationVar(nullptr),
255       mDrawableWidthVar(nullptr),
256       mDrawableHeightVar(nullptr)
257 {
258     if (shaderType == GL_FRAGMENT_SHADER || shaderType == GL_COMPUTE_SHADER)
259     {
260         return;
261     }
262 
263     // Mark SpecConstUsage::Rotation unconditionally.  gl_Position is always rotated.
264     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) != 0 &&
265         (mCompileOptions & SH_ADD_PRE_ROTATION) != 0)
266     {
267         mUsageBits.set(vk::SpecConstUsage::Rotation);
268     }
269 }
270 
~SpecConst()271 SpecConst::~SpecConst() {}
272 
declareSpecConsts(TIntermBlock * root)273 void SpecConst::declareSpecConsts(TIntermBlock *root)
274 {
275     // Add specialization constant declarations.  The default value of the specialization
276     // constant is irrelevant, as it will be set when creating the pipeline.
277     // Only emit specialized const declaration if it has been referenced.
278     if (mLineRasterEmulationVar != nullptr)
279     {
280         TIntermDeclaration *decl = new TIntermDeclaration();
281         decl->appendDeclarator(
282             new TIntermBinary(EOpInitialize, getLineRasterEmulation(), CreateBoolNode(false)));
283 
284         root->insertStatement(0, decl);
285     }
286 
287     if (mSurfaceRotationVar != nullptr)
288     {
289         TIntermDeclaration *decl = new TIntermDeclaration();
290         decl->appendDeclarator(
291             new TIntermBinary(EOpInitialize, getFlipRotation(), CreateUIntNode(0)));
292 
293         root->insertStatement(0, decl);
294     }
295 
296     if (mDrawableWidthVar != nullptr)
297     {
298         TIntermDeclaration *decl = new TIntermDeclaration();
299         decl->appendDeclarator(
300             new TIntermBinary(EOpInitialize, getDrawableWidth(), CreateFloatNode(0)));
301         root->insertStatement(0, decl);
302     }
303 
304     if (mDrawableHeightVar != nullptr)
305     {
306         TIntermDeclaration *decl = new TIntermDeclaration();
307         decl->appendDeclarator(
308             new TIntermBinary(EOpInitialize, getDrawableHeight(), CreateFloatNode(0)));
309         root->insertStatement(1, decl);
310     }
311 }
312 
getLineRasterEmulation()313 TIntermSymbol *SpecConst::getLineRasterEmulation()
314 {
315     if ((mCompileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION) == 0)
316     {
317         return nullptr;
318     }
319     if (mLineRasterEmulationVar == nullptr)
320     {
321         const TType *type = MakeSpecConst(*StaticType::GetBasic<EbtBool>(),
322                                           vk::SpecializationConstantId::LineRasterEmulation);
323 
324         mLineRasterEmulationVar = new TVariable(mSymbolTable, kLineRasterEmulationSpecConstVarName,
325                                                 type, SymbolType::AngleInternal);
326         mUsageBits.set(vk::SpecConstUsage::LineRasterEmulation);
327     }
328     return new TIntermSymbol(mLineRasterEmulationVar);
329 }
330 
getFlipRotation()331 TIntermSymbol *SpecConst::getFlipRotation()
332 {
333     if (mSurfaceRotationVar == nullptr)
334     {
335         const TType *type = MakeSpecConst(*StaticType::GetBasic<EbtUInt>(),
336                                           vk::SpecializationConstantId::SurfaceRotation);
337 
338         mSurfaceRotationVar = new TVariable(mSymbolTable, kSurfaceRotationSpecConstVarName, type,
339                                             SymbolType::AngleInternal);
340     }
341     return new TIntermSymbol(mSurfaceRotationVar);
342 }
343 
getMultiplierXForDFdx()344 TIntermTyped *SpecConst::getMultiplierXForDFdx()
345 {
346     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
347     {
348         return nullptr;
349     }
350     mUsageBits.set(vk::SpecConstUsage::YFlip);
351     mUsageBits.set(vk::SpecConstUsage::Rotation);
352     return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdx, 0, 1, getFlipRotation());
353 }
354 
getMultiplierYForDFdx()355 TIntermTyped *SpecConst::getMultiplierYForDFdx()
356 {
357     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
358     {
359         return nullptr;
360     }
361     mUsageBits.set(vk::SpecConstUsage::YFlip);
362     mUsageBits.set(vk::SpecConstUsage::Rotation);
363     return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdx, 1, 1, getFlipRotation());
364 }
365 
getMultiplierXForDFdy()366 TIntermTyped *SpecConst::getMultiplierXForDFdy()
367 {
368     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
369     {
370         return nullptr;
371     }
372     mUsageBits.set(vk::SpecConstUsage::YFlip);
373     mUsageBits.set(vk::SpecConstUsage::Rotation);
374     return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdy, 0, 1, getFlipRotation());
375 }
376 
getMultiplierYForDFdy()377 TIntermTyped *SpecConst::getMultiplierYForDFdy()
378 {
379     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
380     {
381         return nullptr;
382     }
383     mUsageBits.set(vk::SpecConstUsage::YFlip);
384     mUsageBits.set(vk::SpecConstUsage::Rotation);
385     return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdy, 1, 1, getFlipRotation());
386 }
387 
getPreRotationMatrix()388 TIntermTyped *SpecConst::getPreRotationMatrix()
389 {
390     if (!(mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT))
391     {
392         return nullptr;
393     }
394     mUsageBits.set(vk::SpecConstUsage::Rotation);
395     return GenerateMat2x2ArrayWithIndex(kPreRotationMatrices, getFlipRotation());
396 }
397 
getFragRotationMatrix()398 TIntermTyped *SpecConst::getFragRotationMatrix()
399 {
400     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
401     {
402         return nullptr;
403     }
404     mUsageBits.set(vk::SpecConstUsage::Rotation);
405     return GenerateMat2x2ArrayWithIndex(kFragRotationMatrices, getFlipRotation());
406 }
407 
getHalfRenderAreaRotationMatrix()408 TIntermTyped *SpecConst::getHalfRenderAreaRotationMatrix()
409 {
410     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
411     {
412         return nullptr;
413     }
414     mUsageBits.set(vk::SpecConstUsage::Rotation);
415     return GenerateMat2x2ArrayWithIndex(kHalfRenderAreaRotationMatrices, getFlipRotation());
416 }
417 
getFlipXY()418 TIntermTyped *SpecConst::getFlipXY()
419 {
420     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
421     {
422         return nullptr;
423     }
424     mUsageBits.set(vk::SpecConstUsage::YFlip);
425     return CreateVec2ArrayWithIndex(kFlipXYValue, 1.0, getFlipRotation());
426 }
427 
getNegFlipXY()428 TIntermTyped *SpecConst::getNegFlipXY()
429 {
430     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
431     {
432         return nullptr;
433     }
434     mUsageBits.set(vk::SpecConstUsage::YFlip);
435     return CreateVec2ArrayWithIndex(kFlipXYValue, -1.0, getFlipRotation());
436 }
437 
getFlipY()438 TIntermTyped *SpecConst::getFlipY()
439 {
440     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
441     {
442         return nullptr;
443     }
444     mUsageBits.set(vk::SpecConstUsage::YFlip);
445     return CreateFloatArrayWithRotationIndex(kFlipXYValue, 1, 1, getFlipRotation());
446 }
447 
getNegFlipY()448 TIntermTyped *SpecConst::getNegFlipY()
449 {
450     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
451     {
452         return nullptr;
453     }
454     mUsageBits.set(vk::SpecConstUsage::YFlip);
455     return CreateFloatArrayWithRotationIndex(kFlipXYValue, 1, -1, getFlipRotation());
456 }
457 
getFragRotationMultiplyFlipXY()458 TIntermTyped *SpecConst::getFragRotationMultiplyFlipXY()
459 {
460     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
461     {
462         return nullptr;
463     }
464 
465     constexpr Vec2EnumMap kFragRotationMultiplyFlipXY = {
466         {{vk::SurfaceRotation::Identity,
467           CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::Identity)},
468          {vk::SurfaceRotation::Rotated90Degrees,
469           CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::Rotated90Degrees)},
470          {vk::SurfaceRotation::Rotated180Degrees,
471           CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::Rotated180Degrees)},
472          {vk::SurfaceRotation::Rotated270Degrees,
473           CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::Rotated270Degrees)},
474          {vk::SurfaceRotation::FlippedIdentity,
475           CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::FlippedIdentity)},
476          {vk::SurfaceRotation::FlippedRotated90Degrees,
477           CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::FlippedRotated90Degrees)},
478          {vk::SurfaceRotation::FlippedRotated180Degrees,
479           CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::FlippedRotated180Degrees)},
480          {vk::SurfaceRotation::FlippedRotated270Degrees,
481           CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::FlippedRotated270Degrees)}}};
482 
483     mUsageBits.set(vk::SpecConstUsage::YFlip);
484     mUsageBits.set(vk::SpecConstUsage::Rotation);
485     return CreateVec2ArrayWithIndex(kFragRotationMultiplyFlipXY, 1.0, getFlipRotation());
486 }
487 
getDrawableWidth()488 TIntermSymbol *SpecConst::getDrawableWidth()
489 {
490     if (mDrawableWidthVar == nullptr)
491     {
492         const TType *type = MakeSpecConst(*StaticType::GetBasic<EbtFloat>(),
493                                           vk::SpecializationConstantId::DrawableWidth);
494 
495         mDrawableWidthVar = new TVariable(mSymbolTable, kDrawableWidthSpecConstVarName, type,
496                                           SymbolType::AngleInternal);
497     }
498     return new TIntermSymbol(mDrawableWidthVar);
499 }
500 
getDrawableHeight()501 TIntermSymbol *SpecConst::getDrawableHeight()
502 {
503     if (mDrawableHeightVar == nullptr)
504     {
505         const TType *type = MakeSpecConst(*StaticType::GetBasic<EbtFloat>(),
506                                           vk::SpecializationConstantId::DrawableHeight);
507 
508         mDrawableHeightVar = new TVariable(mSymbolTable, kDrawableHeightSpecConstVarName, type,
509                                            SymbolType::AngleInternal);
510     }
511     return new TIntermSymbol(mDrawableHeightVar);
512 }
513 
getHalfRenderArea()514 TIntermBinary *SpecConst::getHalfRenderArea()
515 {
516     if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0)
517     {
518         return nullptr;
519     }
520 
521     // vec2 drawableSize(drawableWidth, drawableHeight)
522     auto vec2Type = new TType(EbtFloat, 2);
523     TIntermSequence widthHeightArgs;
524     widthHeightArgs.push_back(getDrawableWidth());
525     widthHeightArgs.push_back(getDrawableHeight());
526     TIntermAggregate *drawableSize =
527         TIntermAggregate::CreateConstructor(*vec2Type, &widthHeightArgs);
528 
529     // drawableSize * 0.5f
530     TIntermBinary *halfRenderArea =
531         new TIntermBinary(EOpVectorTimesScalar, drawableSize, CreateFloatNode(0.5));
532     mUsageBits.set(vk::SpecConstUsage::DrawableSize);
533 
534     // drawableSize * 0.5f * halfRenderAreaRotationMatrix (See comment in
535     // kHalfRenderAreaRotationMatrices)
536     TIntermBinary *rotatedHalfRenderArea =
537         new TIntermBinary(EOpMatrixTimesVector, getHalfRenderAreaRotationMatrix(), halfRenderArea);
538 
539     return rotatedHalfRenderArea;
540 }
541 }  // namespace sh
542