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