// // Copyright 2020 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // SpecializationConst.cpp: Add code to generate AST node for various specialization constants. // #include "compiler/translator/tree_util/SpecializationConstant.h" #include "common/PackedEnums.h" #include "common/angleutils.h" #include "compiler/translator/StaticType.h" #include "compiler/translator/SymbolTable.h" #include "compiler/translator/tree_util/IntermNode_util.h" namespace sh { namespace { // Specialization constant names constexpr ImmutableString kLineRasterEmulationSpecConstVarName = ImmutableString("ANGLELineRasterEmulation"); constexpr ImmutableString kSurfaceRotationSpecConstVarName = ImmutableString("ANGLESurfaceRotation"); constexpr ImmutableString kDrawableWidthSpecConstVarName = ImmutableString("ANGLEDrawableWidth"); constexpr ImmutableString kDrawableHeightSpecConstVarName = ImmutableString("ANGLEDrawableHeight"); // When an Android surface is rotated differently than the device's native orientation, ANGLE must // rotate gl_Position in the vertex shader and gl_FragCoord in the fragment shader. The following // are the rotation matrices used. // // This is 2x2 matrix in column major. The first column is for dFdx and second column is for dFdy. using Mat2x2 = std::array; using Mat2x2EnumMap = angle::PackedEnumMap()>; constexpr Mat2x2EnumMap kPreRotationMatrices = { {{vk::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::Rotated90Degrees, {{0.0f, -1.0f, 1.0f, 0.0f}}}, {vk::SurfaceRotation::Rotated180Degrees, {{-1.0f, 0.0f, 0.0f, -1.0f}}}, {vk::SurfaceRotation::Rotated270Degrees, {{0.0f, 1.0f, -1.0f, 0.0f}}}, {vk::SurfaceRotation::FlippedIdentity, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::FlippedRotated90Degrees, {{0.0f, -1.0f, 1.0f, 0.0f}}}, {vk::SurfaceRotation::FlippedRotated180Degrees, {{-1.0f, 0.0f, 0.0f, -1.0f}}}, {vk::SurfaceRotation::FlippedRotated270Degrees, {{0.0f, 1.0f, -1.0f, 0.0f}}}}}; constexpr Mat2x2EnumMap kFragRotationMatrices = { {{vk::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::Rotated90Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}}, {vk::SurfaceRotation::Rotated180Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::Rotated270Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}}, {vk::SurfaceRotation::FlippedIdentity, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::FlippedRotated90Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}}, {vk::SurfaceRotation::FlippedRotated180Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::FlippedRotated270Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}}}}; // TODO: https://issuetracker.google.com/174066134. This is to make sure the specialization constant // code path behaves exactly the same as driver uniform code path. Not sure why this has to be // different from kFragRotationMatrices. constexpr Mat2x2EnumMap kHalfRenderAreaRotationMatrices = { {{vk::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::Rotated90Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}}, {vk::SurfaceRotation::Rotated180Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::Rotated270Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::FlippedIdentity, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::FlippedRotated90Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}}, {vk::SurfaceRotation::FlippedRotated180Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {vk::SurfaceRotation::FlippedRotated270Degrees, {{1.0f, 0.0f, 0.0f, 1.0f}}}}}; // Returns mat2(m0, m1, m2, m3) TIntermAggregate *CreateMat2x2(const Mat2x2EnumMap &matrix, vk::SurfaceRotation rotation) { auto mat2Type = new TType(EbtFloat, 2, 2); TIntermSequence mat2Args; mat2Args.push_back(CreateFloatNode(matrix[rotation][0])); mat2Args.push_back(CreateFloatNode(matrix[rotation][1])); mat2Args.push_back(CreateFloatNode(matrix[rotation][2])); mat2Args.push_back(CreateFloatNode(matrix[rotation][3])); TIntermAggregate *constVarConstructor = TIntermAggregate::CreateConstructor(*mat2Type, &mat2Args); return constVarConstructor; } // Generates an array of vec2 and then use rotation to retrieve the desired flipXY out. TIntermTyped *GenerateMat2x2ArrayWithIndex(const Mat2x2EnumMap &matrix, TIntermSymbol *rotation) { auto mat2Type = new TType(EbtFloat, 2, 2); TType *typeMat2Array = new TType(*mat2Type); typeMat2Array->makeArray(static_cast(vk::SurfaceRotation::EnumCount)); TIntermSequence sequences = { CreateMat2x2(matrix, vk::SurfaceRotation::Identity), CreateMat2x2(matrix, vk::SurfaceRotation::Rotated90Degrees), CreateMat2x2(matrix, vk::SurfaceRotation::Rotated180Degrees), CreateMat2x2(matrix, vk::SurfaceRotation::Rotated270Degrees), CreateMat2x2(matrix, vk::SurfaceRotation::FlippedIdentity), CreateMat2x2(matrix, vk::SurfaceRotation::FlippedRotated90Degrees), CreateMat2x2(matrix, vk::SurfaceRotation::FlippedRotated180Degrees), CreateMat2x2(matrix, vk::SurfaceRotation::FlippedRotated270Degrees)}; TIntermTyped *array = TIntermAggregate::CreateConstructor(*typeMat2Array, &sequences); return new TIntermBinary(EOpIndexIndirect, array, rotation); } using Vec2 = std::array; using Vec2EnumMap = angle::PackedEnumMap()>; constexpr Vec2EnumMap kFlipXYValue = { {{vk::SurfaceRotation::Identity, {{1.0f, 1.0f}}}, {vk::SurfaceRotation::Rotated90Degrees, {{1.0f, 1.0f}}}, {vk::SurfaceRotation::Rotated180Degrees, {{-1.0f, 1.0f}}}, {vk::SurfaceRotation::Rotated270Degrees, {{-1.0f, -1.0f}}}, {vk::SurfaceRotation::FlippedIdentity, {{1.0f, -1.0f}}}, {vk::SurfaceRotation::FlippedRotated90Degrees, {{1.0f, 1.0f}}}, {vk::SurfaceRotation::FlippedRotated180Degrees, {{-1.0f, 1.0f}}}, {vk::SurfaceRotation::FlippedRotated270Degrees, {{-1.0f, -1.0f}}}}}; // Returns [[flipX*m0+flipY*m1] [flipX*m2+flipY*m3]] where [m0 m1] is the first column of // kFragRotation matrix and [m2 m3] is the second column of kFragRotation matrix. constexpr Vec2 CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation rotation) { return Vec2({kFlipXYValue[rotation][0] * kFragRotationMatrices[rotation][0] + kFlipXYValue[rotation][1] * kFragRotationMatrices[rotation][1], kFlipXYValue[rotation][0] * kFragRotationMatrices[rotation][2] + kFlipXYValue[rotation][1] * kFragRotationMatrices[rotation][3]}); } // Returns vec2(vec2Values.x, vec2Values.y*yscale) TIntermAggregate *CreateVec2(Vec2EnumMap vec2Values, float yscale, vk::SurfaceRotation rotation) { auto vec2Type = new TType(EbtFloat, 2); TIntermSequence vec2Args; vec2Args.push_back(CreateFloatNode(vec2Values[rotation][0])); vec2Args.push_back(CreateFloatNode(vec2Values[rotation][1] * yscale)); TIntermAggregate *constVarConstructor = TIntermAggregate::CreateConstructor(*vec2Type, &vec2Args); return constVarConstructor; } // Generates an array of vec2 and then use rotation to retrieve the desired flipXY out. TIntermTyped *CreateVec2ArrayWithIndex(Vec2EnumMap vec2Values, float yscale, TIntermSymbol *rotation) { auto vec2Type = new TType(EbtFloat, 2); TType *typeVec2Array = new TType(*vec2Type); typeVec2Array->makeArray(static_cast(vk::SurfaceRotation::EnumCount)); TIntermSequence sequences = { CreateVec2(vec2Values, yscale, vk::SurfaceRotation::Identity), CreateVec2(vec2Values, yscale, vk::SurfaceRotation::Rotated90Degrees), CreateVec2(vec2Values, yscale, vk::SurfaceRotation::Rotated180Degrees), CreateVec2(vec2Values, yscale, vk::SurfaceRotation::Rotated270Degrees), CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedIdentity), CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedRotated90Degrees), CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedRotated180Degrees), CreateVec2(vec2Values, yscale, vk::SurfaceRotation::FlippedRotated270Degrees)}; TIntermTyped *vec2Array = TIntermAggregate::CreateConstructor(*typeVec2Array, &sequences); return new TIntermBinary(EOpIndexIndirect, vec2Array, rotation); } // Returns [flipX*m0, flipY*m1], where [m0 m1] is the first column of kFragRotation matrix. constexpr Vec2 CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation rotation) { return Vec2({kFlipXYValue[rotation][0] * kFragRotationMatrices[rotation][0], kFlipXYValue[rotation][1] * kFragRotationMatrices[rotation][1]}); } constexpr Vec2EnumMap kRotatedFlipXYForDFdx = { {{vk::SurfaceRotation::Identity, CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::Identity)}, {vk::SurfaceRotation::Rotated90Degrees, CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::Rotated90Degrees)}, {vk::SurfaceRotation::Rotated180Degrees, CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::Rotated180Degrees)}, {vk::SurfaceRotation::Rotated270Degrees, CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::Rotated270Degrees)}, {vk::SurfaceRotation::FlippedIdentity, CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::FlippedIdentity)}, {vk::SurfaceRotation::FlippedRotated90Degrees, CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::FlippedRotated90Degrees)}, {vk::SurfaceRotation::FlippedRotated180Degrees, CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::FlippedRotated180Degrees)}, {vk::SurfaceRotation::FlippedRotated270Degrees, CalcRotatedFlipXYValueForDFdx(vk::SurfaceRotation::FlippedRotated270Degrees)}}}; // Returns [flipX*m2, flipY*m3], where [m2 m3] is the second column of kFragRotation matrix. constexpr Vec2 CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation rotation) { return Vec2({kFlipXYValue[rotation][0] * kFragRotationMatrices[rotation][2], kFlipXYValue[rotation][1] * kFragRotationMatrices[rotation][3]}); } constexpr Vec2EnumMap kRotatedFlipXYForDFdy = { {{vk::SurfaceRotation::Identity, CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::Identity)}, {vk::SurfaceRotation::Rotated90Degrees, CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::Rotated90Degrees)}, {vk::SurfaceRotation::Rotated180Degrees, CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::Rotated180Degrees)}, {vk::SurfaceRotation::Rotated270Degrees, CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::Rotated270Degrees)}, {vk::SurfaceRotation::FlippedIdentity, CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::FlippedIdentity)}, {vk::SurfaceRotation::FlippedRotated90Degrees, CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::FlippedRotated90Degrees)}, {vk::SurfaceRotation::FlippedRotated180Degrees, CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::FlippedRotated180Degrees)}, {vk::SurfaceRotation::FlippedRotated270Degrees, CalcRotatedFlipXYValueForDFdy(vk::SurfaceRotation::FlippedRotated270Degrees)}}}; // Returns an array of float and then use rotation to retrieve the desired float value out. TIntermTyped *CreateFloatArrayWithRotationIndex(const Vec2EnumMap &valuesEnumMap, int subscript, float scale, TIntermSymbol *rotation) { const TType *floatType = StaticType::GetBasic(); TType *typeFloat8 = new TType(*floatType); typeFloat8->makeArray(static_cast(vk::SurfaceRotation::EnumCount)); TIntermSequence sequences = { CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::Identity][subscript] * scale), CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::Rotated90Degrees][subscript] * scale), CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::Rotated180Degrees][subscript] * scale), CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::Rotated270Degrees][subscript] * scale), CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::FlippedIdentity][subscript] * scale), CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::FlippedRotated90Degrees][subscript] * scale), CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::FlippedRotated180Degrees][subscript] * scale), CreateFloatNode(valuesEnumMap[vk::SurfaceRotation::FlippedRotated270Degrees][subscript] * scale)}; TIntermTyped *array = TIntermAggregate::CreateConstructor(*typeFloat8, &sequences); return new TIntermBinary(EOpIndexIndirect, array, rotation); } const TType *MakeSpecConst(const TType &type, vk::SpecializationConstantId id) { // Create a new type with the EvqSpecConst qualifier TType *specConstType = new TType(type); specConstType->setQualifier(EvqSpecConst); // Set the constant_id of the spec const TLayoutQualifier layoutQualifier = TLayoutQualifier::Create(); layoutQualifier.location = static_cast(id); specConstType->setLayoutQualifier(layoutQualifier); return specConstType; } } // anonymous namespace SpecConst::SpecConst(TSymbolTable *symbolTable, ShCompileOptions compileOptions, GLenum shaderType) : mSymbolTable(symbolTable), mCompileOptions(compileOptions), mLineRasterEmulationVar(nullptr), mSurfaceRotationVar(nullptr), mDrawableWidthVar(nullptr), mDrawableHeightVar(nullptr) { if (shaderType == GL_FRAGMENT_SHADER || shaderType == GL_COMPUTE_SHADER) { return; } // Mark SpecConstUsage::Rotation unconditionally. gl_Position is always rotated. if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) != 0 && (mCompileOptions & SH_ADD_PRE_ROTATION) != 0) { mUsageBits.set(vk::SpecConstUsage::Rotation); } } SpecConst::~SpecConst() {} void SpecConst::declareSpecConsts(TIntermBlock *root) { // Add specialization constant declarations. The default value of the specialization // constant is irrelevant, as it will be set when creating the pipeline. // Only emit specialized const declaration if it has been referenced. if (mLineRasterEmulationVar != nullptr) { TIntermDeclaration *decl = new TIntermDeclaration(); decl->appendDeclarator( new TIntermBinary(EOpInitialize, getLineRasterEmulation(), CreateBoolNode(false))); root->insertStatement(0, decl); } if (mSurfaceRotationVar != nullptr) { TIntermDeclaration *decl = new TIntermDeclaration(); decl->appendDeclarator( new TIntermBinary(EOpInitialize, getFlipRotation(), CreateUIntNode(0))); root->insertStatement(0, decl); } if (mDrawableWidthVar != nullptr) { TIntermDeclaration *decl = new TIntermDeclaration(); decl->appendDeclarator( new TIntermBinary(EOpInitialize, getDrawableWidth(), CreateFloatNode(0))); root->insertStatement(0, decl); } if (mDrawableHeightVar != nullptr) { TIntermDeclaration *decl = new TIntermDeclaration(); decl->appendDeclarator( new TIntermBinary(EOpInitialize, getDrawableHeight(), CreateFloatNode(0))); root->insertStatement(1, decl); } } TIntermSymbol *SpecConst::getLineRasterEmulation() { if ((mCompileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION) == 0) { return nullptr; } if (mLineRasterEmulationVar == nullptr) { const TType *type = MakeSpecConst(*StaticType::GetBasic(), vk::SpecializationConstantId::LineRasterEmulation); mLineRasterEmulationVar = new TVariable(mSymbolTable, kLineRasterEmulationSpecConstVarName, type, SymbolType::AngleInternal); mUsageBits.set(vk::SpecConstUsage::LineRasterEmulation); } return new TIntermSymbol(mLineRasterEmulationVar); } TIntermSymbol *SpecConst::getFlipRotation() { if (mSurfaceRotationVar == nullptr) { const TType *type = MakeSpecConst(*StaticType::GetBasic(), vk::SpecializationConstantId::SurfaceRotation); mSurfaceRotationVar = new TVariable(mSymbolTable, kSurfaceRotationSpecConstVarName, type, SymbolType::AngleInternal); } return new TIntermSymbol(mSurfaceRotationVar); } TIntermTyped *SpecConst::getMultiplierXForDFdx() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::YFlip); mUsageBits.set(vk::SpecConstUsage::Rotation); return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdx, 0, 1, getFlipRotation()); } TIntermTyped *SpecConst::getMultiplierYForDFdx() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::YFlip); mUsageBits.set(vk::SpecConstUsage::Rotation); return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdx, 1, 1, getFlipRotation()); } TIntermTyped *SpecConst::getMultiplierXForDFdy() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::YFlip); mUsageBits.set(vk::SpecConstUsage::Rotation); return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdy, 0, 1, getFlipRotation()); } TIntermTyped *SpecConst::getMultiplierYForDFdy() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::YFlip); mUsageBits.set(vk::SpecConstUsage::Rotation); return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdy, 1, 1, getFlipRotation()); } TIntermTyped *SpecConst::getPreRotationMatrix() { if (!(mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT)) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::Rotation); return GenerateMat2x2ArrayWithIndex(kPreRotationMatrices, getFlipRotation()); } TIntermTyped *SpecConst::getFragRotationMatrix() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::Rotation); return GenerateMat2x2ArrayWithIndex(kFragRotationMatrices, getFlipRotation()); } TIntermTyped *SpecConst::getHalfRenderAreaRotationMatrix() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::Rotation); return GenerateMat2x2ArrayWithIndex(kHalfRenderAreaRotationMatrices, getFlipRotation()); } TIntermTyped *SpecConst::getFlipXY() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::YFlip); return CreateVec2ArrayWithIndex(kFlipXYValue, 1.0, getFlipRotation()); } TIntermTyped *SpecConst::getNegFlipXY() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::YFlip); return CreateVec2ArrayWithIndex(kFlipXYValue, -1.0, getFlipRotation()); } TIntermTyped *SpecConst::getFlipY() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::YFlip); return CreateFloatArrayWithRotationIndex(kFlipXYValue, 1, 1, getFlipRotation()); } TIntermTyped *SpecConst::getNegFlipY() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } mUsageBits.set(vk::SpecConstUsage::YFlip); return CreateFloatArrayWithRotationIndex(kFlipXYValue, 1, -1, getFlipRotation()); } TIntermTyped *SpecConst::getFragRotationMultiplyFlipXY() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } constexpr Vec2EnumMap kFragRotationMultiplyFlipXY = { {{vk::SurfaceRotation::Identity, CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::Identity)}, {vk::SurfaceRotation::Rotated90Degrees, CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::Rotated90Degrees)}, {vk::SurfaceRotation::Rotated180Degrees, CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::Rotated180Degrees)}, {vk::SurfaceRotation::Rotated270Degrees, CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::Rotated270Degrees)}, {vk::SurfaceRotation::FlippedIdentity, CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::FlippedIdentity)}, {vk::SurfaceRotation::FlippedRotated90Degrees, CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::FlippedRotated90Degrees)}, {vk::SurfaceRotation::FlippedRotated180Degrees, CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::FlippedRotated180Degrees)}, {vk::SurfaceRotation::FlippedRotated270Degrees, CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::FlippedRotated270Degrees)}}}; mUsageBits.set(vk::SpecConstUsage::YFlip); mUsageBits.set(vk::SpecConstUsage::Rotation); return CreateVec2ArrayWithIndex(kFragRotationMultiplyFlipXY, 1.0, getFlipRotation()); } TIntermSymbol *SpecConst::getDrawableWidth() { if (mDrawableWidthVar == nullptr) { const TType *type = MakeSpecConst(*StaticType::GetBasic(), vk::SpecializationConstantId::DrawableWidth); mDrawableWidthVar = new TVariable(mSymbolTable, kDrawableWidthSpecConstVarName, type, SymbolType::AngleInternal); } return new TIntermSymbol(mDrawableWidthVar); } TIntermSymbol *SpecConst::getDrawableHeight() { if (mDrawableHeightVar == nullptr) { const TType *type = MakeSpecConst(*StaticType::GetBasic(), vk::SpecializationConstantId::DrawableHeight); mDrawableHeightVar = new TVariable(mSymbolTable, kDrawableHeightSpecConstVarName, type, SymbolType::AngleInternal); } return new TIntermSymbol(mDrawableHeightVar); } TIntermBinary *SpecConst::getHalfRenderArea() { if ((mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT) == 0) { return nullptr; } // vec2 drawableSize(drawableWidth, drawableHeight) auto vec2Type = new TType(EbtFloat, 2); TIntermSequence widthHeightArgs; widthHeightArgs.push_back(getDrawableWidth()); widthHeightArgs.push_back(getDrawableHeight()); TIntermAggregate *drawableSize = TIntermAggregate::CreateConstructor(*vec2Type, &widthHeightArgs); // drawableSize * 0.5f TIntermBinary *halfRenderArea = new TIntermBinary(EOpVectorTimesScalar, drawableSize, CreateFloatNode(0.5)); mUsageBits.set(vk::SpecConstUsage::DrawableSize); // drawableSize * 0.5f * halfRenderAreaRotationMatrix (See comment in // kHalfRenderAreaRotationMatrices) TIntermBinary *rotatedHalfRenderArea = new TIntermBinary(EOpMatrixTimesVector, getHalfRenderAreaRotationMatrix(), halfRenderArea); return rotatedHalfRenderArea; } } // namespace sh