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