Commit dfd9bdfd by Shahbaz Youssefi Committed by Commit Bot

Reland "Vulkan: Generate gl_Position pre-rotation in SPIR-V"

This reverts commit 3d39b7c5. Reason for revert: Fixed interaction with the `forceDriverUniformOverSpecConst` workaround. Original change's description: > Revert "Vulkan: Generate gl_Position pre-rotation in SPIR-V" > > This reverts commit 0f86b196. > > Reason for revert: > Breaks pre-rotation for all apps, so they are displayed in portrait instead of landscape. > > Original change's description: > > Vulkan: Generate gl_Position pre-rotation in SPIR-V > > > > Instead of having the translator output pre-rotation code in the vertex > > stage based on a specialization constant, this change makes the SPIR-V > > transformer perform pre-rotation of gl_Position on the last geometry > > stage. > > > > An alternative solution would be to generate pre-rotation code in the > > translator in every geometry stage, each controlled by a separate > > specialization constant. This change avoids unnecessary modifications > > to earlier stages. The generated shaders are also smaller, as they > > don't contain a mat2[8] pre-rotation constant matrix. The SPIR-V > > transformer knows the pre-rotation at transformation time, so it can > > simply use swizzles to achieve the same results. > > > > This also ties in with upcoming changes which move gl_Position.z > > correction to the last geometry shader stage, which is trivially done > > piggy-backing on the infrastructure in this change. > > > > Bug: angleproject:5478 > > Change-Id: I9d5d9d19f3ccda665f5504368ce5ddfa5f383faf > > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2598584 > > Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> > > Reviewed-by: Charlie Lao <cclao@google.com> > > Reviewed-by: Jamie Madill <jmadill@chromium.org> > > TBR=syoussefi@chromium.org,jmadill@chromium.org,cclao@google.com > > Change-Id: I81f237fa6b10c7d59831363bee8999e7ad2f09be > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: angleproject:5478 > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2633694 > Reviewed-by: Tim Van Patten <timvp@google.com> > Commit-Queue: Tim Van Patten <timvp@google.com> TBR=timvp@google.com,syoussefi@chromium.org,jmadill@chromium.org,cclao@google.com Bug: angleproject:5478 Change-Id: I7c5eaeef03d9520abd36a1c4a766b6abbf4fdb45 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2633709Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 60015ff6
...@@ -306,39 +306,6 @@ ANGLE_NO_DISCARD bool AppendVertexShaderDepthCorrectionToMain(TCompiler *compile ...@@ -306,39 +306,6 @@ ANGLE_NO_DISCARD bool AppendVertexShaderDepthCorrectionToMain(TCompiler *compile
return RunAtTheEndOfShader(compiler, root, assignment, symbolTable); return RunAtTheEndOfShader(compiler, root, assignment, symbolTable);
} }
// This operation performs Android pre-rotation and y-flip. For Android (and potentially other
// platforms), the device may rotate, such that the orientation of the application is rotated
// relative to the native orientation of the device. This is corrected in part by multiplying
// gl_Position by a mat2.
// The equations reduce to an expression:
//
// gl_Position.xy = gl_Position.xy * preRotation
ANGLE_NO_DISCARD bool AppendPreRotation(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable,
SpecConst *specConst,
const DriverUniform *driverUniforms)
{
TIntermTyped *preRotationRef = specConst->getPreRotationMatrix();
if (!preRotationRef)
{
preRotationRef = driverUniforms->getPreRotationMatrixRef();
}
TIntermSymbol *glPos = new TIntermSymbol(BuiltInVariable::gl_Position());
TVector<int> swizzleOffsetXY = {0, 1};
TIntermSwizzle *glPosXY = new TIntermSwizzle(glPos, swizzleOffsetXY);
// Create the expression "(gl_Position.xy * preRotation)"
TIntermBinary *zRotated = new TIntermBinary(EOpMatrixTimesVector, preRotationRef, glPosXY);
// Create the assignment "gl_Position.xy = (gl_Position.xy * preRotation)"
TIntermBinary *assignment =
new TIntermBinary(TOperator::EOpAssign, glPosXY->deepCopy(), zRotated);
// Append the assignment as a statement at the end of the shader.
return RunAtTheEndOfShader(compiler, root, assignment, symbolTable);
}
ANGLE_NO_DISCARD bool AppendTransformFeedbackOutputToMain(TCompiler *compiler, ANGLE_NO_DISCARD bool AppendTransformFeedbackOutputToMain(TCompiler *compiler,
TIntermBlock *root, TIntermBlock *root,
TSymbolTable *symbolTable) TSymbolTable *symbolTable)
...@@ -1154,11 +1121,6 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -1154,11 +1121,6 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
{ {
return false; return false;
} }
if ((compileOptions & SH_ADD_PRE_ROTATION) != 0 &&
!AppendPreRotation(this, root, &getSymbolTable(), specConst, driverUniforms))
{
return false;
}
break; break;
} }
......
...@@ -36,7 +36,6 @@ constexpr const char kNumSamples[] = "numSamples"; ...@@ -36,7 +36,6 @@ constexpr const char kNumSamples[] = "numSamples";
constexpr const char kHalfRenderArea[] = "halfRenderArea"; constexpr const char kHalfRenderArea[] = "halfRenderArea";
constexpr const char kFlipXY[] = "flipXY"; constexpr const char kFlipXY[] = "flipXY";
constexpr const char kNegFlipXY[] = "negFlipXY"; constexpr const char kNegFlipXY[] = "negFlipXY";
constexpr const char kPreRotation[] = "preRotation";
constexpr const char kFragRotation[] = "fragRotation"; constexpr const char kFragRotation[] = "fragRotation";
} // anonymous namespace } // anonymous namespace
...@@ -218,10 +217,9 @@ TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable ...@@ -218,10 +217,9 @@ TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable
{ {
TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable); TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable);
constexpr size_t kNumGraphicsDriverUniformsExt = 5; constexpr size_t kNumGraphicsDriverUniformsExt = 4;
constexpr std::array<const char *, kNumGraphicsDriverUniformsExt> constexpr std::array<const char *, kNumGraphicsDriverUniformsExt>
kGraphicsDriverUniformNamesExt = { kGraphicsDriverUniformNamesExt = {{kHalfRenderArea, kFlipXY, kNegFlipXY, kFragRotation}};
{kHalfRenderArea, kFlipXY, kNegFlipXY, kPreRotation, kFragRotation}};
const std::array<TType *, kNumGraphicsDriverUniformsExt> kDriverUniformTypesExt = {{ const std::array<TType *, kNumGraphicsDriverUniformsExt> kDriverUniformTypesExt = {{
new TType(EbtFloat, 2), new TType(EbtFloat, 2),
...@@ -229,7 +227,6 @@ TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable ...@@ -229,7 +227,6 @@ TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable
new TType(EbtFloat, 2), new TType(EbtFloat, 2),
// NOTE: There's a vec2 gap here that can be used in the future // NOTE: There's a vec2 gap here that can be used in the future
new TType(EbtFloat, 2, 2), new TType(EbtFloat, 2, 2),
new TType(EbtFloat, 2, 2),
}}; }};
for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniformsExt; ++uniformIndex) for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniformsExt; ++uniformIndex)
...@@ -268,11 +265,6 @@ TIntermBinary *DriverUniformExtended::getFragRotationMatrixRef() const ...@@ -268,11 +265,6 @@ TIntermBinary *DriverUniformExtended::getFragRotationMatrixRef() const
return createDriverUniformRef(kFragRotation); return createDriverUniformRef(kFragRotation);
} }
TIntermBinary *DriverUniformExtended::getPreRotationMatrixRef() const
{
return createDriverUniformRef(kPreRotation);
}
TIntermBinary *DriverUniformExtended::getHalfRenderAreaRef() const TIntermBinary *DriverUniformExtended::getHalfRenderAreaRef() const
{ {
return createDriverUniformRef(kHalfRenderArea); return createDriverUniformRef(kHalfRenderArea);
......
...@@ -44,7 +44,6 @@ class DriverUniform ...@@ -44,7 +44,6 @@ class DriverUniform
virtual TIntermBinary *getFlipXYRef() const { return nullptr; } virtual TIntermBinary *getFlipXYRef() const { return nullptr; }
virtual TIntermBinary *getNegFlipXYRef() const { return nullptr; } virtual TIntermBinary *getNegFlipXYRef() const { return nullptr; }
virtual TIntermBinary *getFragRotationMatrixRef() const { return nullptr; } virtual TIntermBinary *getFragRotationMatrixRef() const { return nullptr; }
virtual TIntermBinary *getPreRotationMatrixRef() const { return nullptr; }
virtual TIntermBinary *getHalfRenderAreaRef() const { return nullptr; } virtual TIntermBinary *getHalfRenderAreaRef() const { return nullptr; }
virtual TIntermSwizzle *getNegFlipYRef() const { return nullptr; } virtual TIntermSwizzle *getNegFlipYRef() const { return nullptr; }
...@@ -65,7 +64,6 @@ class DriverUniformExtended : public DriverUniform ...@@ -65,7 +64,6 @@ class DriverUniformExtended : public DriverUniform
TIntermBinary *getFlipXYRef() const override; TIntermBinary *getFlipXYRef() const override;
TIntermBinary *getNegFlipXYRef() const override; TIntermBinary *getNegFlipXYRef() const override;
TIntermBinary *getFragRotationMatrixRef() const override; TIntermBinary *getFragRotationMatrixRef() const override;
TIntermBinary *getPreRotationMatrixRef() const override;
TIntermBinary *getHalfRenderAreaRef() const override; TIntermBinary *getHalfRenderAreaRef() const override;
TIntermSwizzle *getNegFlipYRef() const override; TIntermSwizzle *getNegFlipYRef() const override;
......
...@@ -35,16 +35,6 @@ using Mat2x2 = std::array<float, 4>; ...@@ -35,16 +35,6 @@ using Mat2x2 = std::array<float, 4>;
using Mat2x2EnumMap = using Mat2x2EnumMap =
angle::PackedEnumMap<vk::SurfaceRotation, Mat2x2, angle::EnumSize<vk::SurfaceRotation>()>; angle::PackedEnumMap<vk::SurfaceRotation, Mat2x2, angle::EnumSize<vk::SurfaceRotation>()>;
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 = { constexpr Mat2x2EnumMap kFragRotationMatrices = {
{{vk::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 1.0f}}}, {{vk::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 1.0f}}},
{vk::SurfaceRotation::Rotated90Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}}, {vk::SurfaceRotation::Rotated90Degrees, {{0.0f, 1.0f, 1.0f, 0.0f}}},
...@@ -238,7 +228,14 @@ TIntermTyped *CreateFloatArrayWithRotationIndex(const Vec2EnumMap &valuesEnumMap ...@@ -238,7 +228,14 @@ TIntermTyped *CreateFloatArrayWithRotationIndex(const Vec2EnumMap &valuesEnumMap
SpecConst::SpecConst(TSymbolTable *symbolTable, ShCompileOptions compileOptions) SpecConst::SpecConst(TSymbolTable *symbolTable, ShCompileOptions compileOptions)
: mSymbolTable(symbolTable), mCompileOptions(compileOptions) : mSymbolTable(symbolTable), mCompileOptions(compileOptions)
{} {
// 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() {} SpecConst::~SpecConst() {}
...@@ -337,16 +334,6 @@ TIntermTyped *SpecConst::getMultiplierYForDFdy() ...@@ -337,16 +334,6 @@ TIntermTyped *SpecConst::getMultiplierYForDFdy()
return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdy, 1, 1, getFlipRotation()); 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() TIntermTyped *SpecConst::getFragRotationMatrix()
{ {
if (!(mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT)) if (!(mCompileOptions & SH_USE_SPECIALIZATION_CONSTANT))
......
...@@ -34,7 +34,6 @@ class SpecConst ...@@ -34,7 +34,6 @@ class SpecConst
TIntermTyped *getMultiplierYForDFdx(); TIntermTyped *getMultiplierYForDFdx();
TIntermTyped *getMultiplierXForDFdy(); TIntermTyped *getMultiplierXForDFdy();
TIntermTyped *getMultiplierYForDFdy(); TIntermTyped *getMultiplierYForDFdy();
TIntermTyped *getPreRotationMatrix();
TIntermTyped *getFragRotationMatrix(); TIntermTyped *getFragRotationMatrix();
TIntermTyped *getFlipXY(); TIntermTyped *getFlipXY();
TIntermTyped *getNegFlipXY(); TIntermTyped *getNegFlipXY();
......
...@@ -133,6 +133,11 @@ void GlslangWarmup() ...@@ -133,6 +133,11 @@ void GlslangWarmup()
ASSERT(result); ASSERT(result);
} }
bool IsRotationIdentity(SurfaceRotation rotation)
{
return rotation == SurfaceRotation::Identity || rotation == SurfaceRotation::FlippedIdentity;
}
// Test if there are non-zero indices in the uniform name, returning false in that case. This // Test if there are non-zero indices in the uniform name, returning false in that case. This
// happens for multi-dimensional arrays, where a uniform is created for every possible index of the // happens for multi-dimensional arrays, where a uniform is created for every possible index of the
// array (except for the innermost dimension). When assigning decorations (set/binding/etc), only // array (except for the innermost dimension). When assigning decorations (set/binding/etc), only
...@@ -1162,15 +1167,21 @@ class SpirvTransformerBase : angle::NonCopyable ...@@ -1162,15 +1167,21 @@ class SpirvTransformerBase : angle::NonCopyable
uint32_t getNewId(); uint32_t getNewId();
// Instruction generators: // Instruction generators:
void writeAccessChain(uint32_t id, uint32_t typeId, uint32_t baseId, uint32_t indexId);
void writeCopyObject(uint32_t id, uint32_t typeId, uint32_t operandId); void writeCopyObject(uint32_t id, uint32_t typeId, uint32_t operandId);
void writeCompositeConstruct(uint32_t id, void writeCompositeConstruct(uint32_t id,
uint32_t typeId, uint32_t typeId,
const angle::FixedVector<uint32_t, 4> &constituents); const angle::FixedVector<uint32_t, 4> &constituents);
void writeCompositeExtract(uint32_t id, uint32_t typeId, uint32_t compositeId, uint32_t field); void writeCompositeExtract(uint32_t id, uint32_t typeId, uint32_t compositeId, uint32_t field);
void writeLoad(uint32_t id, uint32_t typeId, uint32_t tempVarId); void writeConstant(uint32_t id, uint32_t typeId, uint32_t value);
void writeFNegate(uint32_t id, uint32_t typeId, uint32_t operand);
void writeLoad(uint32_t id, uint32_t typeId, uint32_t pointerId);
void writeMemberDecorate(uint32_t typeId, uint32_t member, uint32_t decoration, uint32_t value); void writeMemberDecorate(uint32_t typeId, uint32_t member, uint32_t decoration, uint32_t value);
void writeStore(uint32_t pointerId, uint32_t objectId); void writeStore(uint32_t pointerId, uint32_t objectId);
void writeTypeFloat(uint32_t id, uint32_t width);
void writeTypeInt(uint32_t id, uint32_t width, uint32_t signedness);
void writeTypePointer(uint32_t id, uint32_t storageClass, uint32_t typeId); void writeTypePointer(uint32_t id, uint32_t storageClass, uint32_t typeId);
void writeTypeVector(uint32_t id, uint32_t componentTypeId, uint32_t componentCount);
void writeVariable(uint32_t id, uint32_t typeId, uint32_t storageClass); void writeVariable(uint32_t id, uint32_t typeId, uint32_t storageClass);
void writeVectorShuffle(uint32_t id, void writeVectorShuffle(uint32_t id,
uint32_t typeId, uint32_t typeId,
...@@ -1247,6 +1258,31 @@ uint32_t SpirvTransformerBase::getNewId() ...@@ -1247,6 +1258,31 @@ uint32_t SpirvTransformerBase::getNewId()
return (*mSpirvBlobOut)[kHeaderIndexIndexBound]++; return (*mSpirvBlobOut)[kHeaderIndexIndexBound]++;
} }
void SpirvTransformerBase::writeAccessChain(uint32_t id,
uint32_t typeId,
uint32_t baseId,
uint32_t indexId)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpAccessChain
constexpr size_t kTypeIdIndex = 1;
constexpr size_t kIdIndex = 2;
constexpr size_t kBaseIdIndex = 3;
constexpr size_t kIndexIdIndex = 4;
constexpr size_t kAccessChainInstructionLength = 5;
std::array<uint32_t, kAccessChainInstructionLength> accessChain = {};
// Fill the fields.
SetSpirvInstructionOp(accessChain.data(), spv::OpAccessChain);
SetSpirvInstructionLength(accessChain.data(), kAccessChainInstructionLength);
accessChain[kTypeIdIndex] = typeId;
accessChain[kIdIndex] = id;
accessChain[kBaseIdIndex] = baseId;
accessChain[kIndexIdIndex] = indexId;
copyInstruction(accessChain.data(), kAccessChainInstructionLength);
}
void SpirvTransformerBase::writeCopyObject(uint32_t id, uint32_t typeId, uint32_t operandId) void SpirvTransformerBase::writeCopyObject(uint32_t id, uint32_t typeId, uint32_t operandId)
{ {
// SPIR-V 1.0 Section 3.32 Instructions, OpCopyObject // SPIR-V 1.0 Section 3.32 Instructions, OpCopyObject
...@@ -1325,11 +1361,51 @@ void SpirvTransformerBase::writeCompositeExtract(uint32_t id, ...@@ -1325,11 +1361,51 @@ void SpirvTransformerBase::writeCompositeExtract(uint32_t id,
copyInstruction(compositeExtract.data(), kCompositeExtractInstructionLength); copyInstruction(compositeExtract.data(), kCompositeExtractInstructionLength);
} }
void SpirvTransformerBase::writeLoad(uint32_t pointerId, uint32_t typeId, uint32_t resultId) void SpirvTransformerBase::writeConstant(uint32_t id, uint32_t typeId, uint32_t value)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpConstant
constexpr size_t kTypeIdIndex = 1;
constexpr size_t kIdIndex = 2;
constexpr size_t kValueIndex = 3;
constexpr size_t kConstantInstructionLength = 4;
std::array<uint32_t, kConstantInstructionLength> constant = {};
// Fill the fields.
SetSpirvInstructionOp(constant.data(), spv::OpConstant);
SetSpirvInstructionLength(constant.data(), kConstantInstructionLength);
constant[kTypeIdIndex] = typeId;
constant[kIdIndex] = id;
constant[kValueIndex] = value;
copyInstruction(constant.data(), kConstantInstructionLength);
}
void SpirvTransformerBase::writeFNegate(uint32_t id, uint32_t typeId, uint32_t operand)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpFNegate
constexpr size_t kTypeIdIndex = 1;
constexpr size_t kIdIndex = 2;
constexpr size_t kOperandIndex = 3;
constexpr size_t kFNegateInstructionLength = 4;
std::array<uint32_t, kFNegateInstructionLength> fNegate = {};
// Fill the fields.
SetSpirvInstructionOp(fNegate.data(), spv::OpFNegate);
SetSpirvInstructionLength(fNegate.data(), kFNegateInstructionLength);
fNegate[kTypeIdIndex] = typeId;
fNegate[kIdIndex] = id;
fNegate[kOperandIndex] = operand;
copyInstruction(fNegate.data(), kFNegateInstructionLength);
}
void SpirvTransformerBase::writeLoad(uint32_t id, uint32_t typeId, uint32_t pointerId)
{ {
// SPIR-V 1.0 Section 3.32 Instructions, OpLoad // SPIR-V 1.0 Section 3.32 Instructions, OpLoad
constexpr size_t kResultTypeIndex = 1; constexpr size_t kTypeIndex = 1;
constexpr size_t kResultIdIndex = 2; constexpr size_t kIdIndex = 2;
constexpr size_t kPointerIdIndex = 3; constexpr size_t kPointerIdIndex = 3;
constexpr size_t kOpLoadInstructionLength = 4; constexpr size_t kOpLoadInstructionLength = 4;
...@@ -1337,9 +1413,9 @@ void SpirvTransformerBase::writeLoad(uint32_t pointerId, uint32_t typeId, uint32 ...@@ -1337,9 +1413,9 @@ void SpirvTransformerBase::writeLoad(uint32_t pointerId, uint32_t typeId, uint32
SetSpirvInstructionOp(load.data(), spv::OpLoad); SetSpirvInstructionOp(load.data(), spv::OpLoad);
SetSpirvInstructionLength(load.data(), kOpLoadInstructionLength); SetSpirvInstructionLength(load.data(), kOpLoadInstructionLength);
load[kResultTypeIndex] = typeId; load[kTypeIndex] = typeId;
load[kResultIdIndex] = resultId; load[kIdIndex] = id;
load[kPointerIdIndex] = pointerId; load[kPointerIdIndex] = pointerId;
copyInstruction(load.data(), kOpLoadInstructionLength); copyInstruction(load.data(), kOpLoadInstructionLength);
} }
...@@ -1384,6 +1460,44 @@ void SpirvTransformerBase::writeStore(uint32_t pointerId, uint32_t objectId) ...@@ -1384,6 +1460,44 @@ void SpirvTransformerBase::writeStore(uint32_t pointerId, uint32_t objectId)
copyInstruction(store.data(), kStoreInstructionLength); copyInstruction(store.data(), kStoreInstructionLength);
} }
void SpirvTransformerBase::writeTypeFloat(uint32_t id, uint32_t width)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpTypeFloat
constexpr size_t kIdIndex = 1;
constexpr size_t kWidthIndex = 2;
constexpr size_t kTypeFloatInstructionLength = 3;
std::array<uint32_t, kTypeFloatInstructionLength> typeFloat = {};
// Fill the fields.
SetSpirvInstructionOp(typeFloat.data(), spv::OpTypeFloat);
SetSpirvInstructionLength(typeFloat.data(), kTypeFloatInstructionLength);
typeFloat[kIdIndex] = id;
typeFloat[kWidthIndex] = width;
copyInstruction(typeFloat.data(), kTypeFloatInstructionLength);
}
void SpirvTransformerBase::writeTypeInt(uint32_t id, uint32_t width, uint32_t signedness)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpTypeInt
constexpr size_t kIdIndex = 1;
constexpr size_t kWidthIndex = 2;
constexpr size_t kSignednessIndex = 3;
constexpr size_t kTypeIntInstructionLength = 4;
std::array<uint32_t, kTypeIntInstructionLength> typeInt = {};
// Fill the fields.
SetSpirvInstructionOp(typeInt.data(), spv::OpTypeInt);
SetSpirvInstructionLength(typeInt.data(), kTypeIntInstructionLength);
typeInt[kIdIndex] = id;
typeInt[kWidthIndex] = width;
typeInt[kSignednessIndex] = signedness;
copyInstruction(typeInt.data(), kTypeIntInstructionLength);
}
void SpirvTransformerBase::writeTypePointer(uint32_t id, uint32_t storageClass, uint32_t typeId) void SpirvTransformerBase::writeTypePointer(uint32_t id, uint32_t storageClass, uint32_t typeId)
{ {
// SPIR-V 1.0 Section 3.32 Instructions, OpTypePointer // SPIR-V 1.0 Section 3.32 Instructions, OpTypePointer
...@@ -1404,6 +1518,28 @@ void SpirvTransformerBase::writeTypePointer(uint32_t id, uint32_t storageClass, ...@@ -1404,6 +1518,28 @@ void SpirvTransformerBase::writeTypePointer(uint32_t id, uint32_t storageClass,
copyInstruction(typePointer.data(), kTypePointerInstructionLength); copyInstruction(typePointer.data(), kTypePointerInstructionLength);
} }
void SpirvTransformerBase::writeTypeVector(uint32_t id,
uint32_t componentTypeId,
uint32_t componentCount)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpTypeVector
constexpr size_t kIdIndex = 1;
constexpr size_t kComponentTypeIdIndex = 2;
constexpr size_t kComponentCountIndex = 3;
constexpr size_t kTypeVectorInstructionLength = 4;
std::array<uint32_t, kTypeVectorInstructionLength> typeVector = {};
// Fill the fields.
SetSpirvInstructionOp(typeVector.data(), spv::OpTypeVector);
SetSpirvInstructionLength(typeVector.data(), kTypeVectorInstructionLength);
typeVector[kIdIndex] = id;
typeVector[kComponentTypeIdIndex] = componentTypeId;
typeVector[kComponentCountIndex] = componentCount;
copyInstruction(typeVector.data(), kTypeVectorInstructionLength);
}
void SpirvTransformerBase::writeVariable(uint32_t id, uint32_t typeId, uint32_t storageClass) void SpirvTransformerBase::writeVariable(uint32_t id, uint32_t typeId, uint32_t storageClass)
{ {
// SPIR-V 1.0 Section 3.32 Instructions, OpVariable // SPIR-V 1.0 Section 3.32 Instructions, OpVariable
...@@ -1490,7 +1626,10 @@ class SpirvTransformer final : public SpirvTransformerBase ...@@ -1490,7 +1626,10 @@ class SpirvTransformer final : public SpirvTransformerBase
void visitMemberName(const uint32_t *instruction); void visitMemberName(const uint32_t *instruction);
void visitTypeHelper(const uint32_t *instruction, size_t idIndex, size_t typeIdIndex); void visitTypeHelper(const uint32_t *instruction, size_t idIndex, size_t typeIdIndex);
void visitTypeArray(const uint32_t *instruction); void visitTypeArray(const uint32_t *instruction);
void visitTypeFloat(const uint32_t *instruction);
void visitTypeInt(const uint32_t *instruction);
void visitTypePointer(const uint32_t *instruction); void visitTypePointer(const uint32_t *instruction);
void visitTypeVector(const uint32_t *instruction);
void visitVariable(const uint32_t *instruction); void visitVariable(const uint32_t *instruction);
// Instructions that potentially need transformation. They return true if the instruction is // Instructions that potentially need transformation. They return true if the instruction is
...@@ -1509,8 +1648,10 @@ class SpirvTransformer final : public SpirvTransformerBase ...@@ -1509,8 +1648,10 @@ class SpirvTransformer final : public SpirvTransformerBase
bool transformExecutionMode(const uint32_t *instruction, size_t wordCount); bool transformExecutionMode(const uint32_t *instruction, size_t wordCount);
// Helpers: // Helpers:
void writePendingDeclarations();
void writeInputPreamble(); void writeInputPreamble();
void writeOutputPrologue(); void writeOutputPrologue();
void preRotateXY(uint32_t xId, uint32_t yId, uint32_t *rotatedXIdOut, uint32_t *rotatedYIdOut);
// Special flags: // Special flags:
GlslangSpirvOptions mOptions; GlslangSpirvOptions mOptions;
...@@ -1559,6 +1700,26 @@ class SpirvTransformer final : public SpirvTransformerBase ...@@ -1559,6 +1700,26 @@ class SpirvTransformer final : public SpirvTransformerBase
}; };
PerVertexData mOutputPerVertex; PerVertexData mOutputPerVertex;
PerVertexData mInputPerVertex; PerVertexData mInputPerVertex;
// A handful of ids that are used to generate gl_Position transformation code (for pre-rotation
// or depth correction). These IDs are used to load/store gl_Position and apply modifications
// and swizzles.
//
// - mFloatId: id of OpTypeFloat 32
// - mVec4Id: id of OpTypeVector %mFloatID 4
// - mVec4OutTypePointerId: id of OpTypePointer Output %mVec4ID
// - mIntId: id of OpTypeInt 32 1
// - mInt0Id: id of OpConstant %mIntID 0
// - mOutputPerVertexTypePointerId: id of OpTypePointer Output %mOutputPerVertex.typeId
// - mOutputPerVertexId: id of OpVariable %mOutputPerVertexTypePointerId Output
//
uint32_t mFloatId = 0;
uint32_t mVec4Id = 0;
uint32_t mVec4OutTypePointerId = 0;
uint32_t mIntId = 0;
uint32_t mInt0Id = 0;
uint32_t mOutputPerVertexTypePointerId = 0;
uint32_t mOutputPerVertexId = 0;
}; };
bool SpirvTransformer::transform() bool SpirvTransformer::transform()
...@@ -1625,9 +1786,18 @@ void SpirvTransformer::resolveVariableIds() ...@@ -1625,9 +1786,18 @@ void SpirvTransformer::resolveVariableIds()
case spv::OpTypeArray: case spv::OpTypeArray:
visitTypeArray(instruction); visitTypeArray(instruction);
break; break;
case spv::OpTypeFloat:
visitTypeFloat(instruction);
break;
case spv::OpTypeInt:
visitTypeInt(instruction);
break;
case spv::OpTypePointer: case spv::OpTypePointer:
visitTypePointer(instruction); visitTypePointer(instruction);
break; break;
case spv::OpTypeVector:
visitTypeVector(instruction);
break;
case spv::OpVariable: case spv::OpVariable:
visitVariable(instruction); visitVariable(instruction);
break; break;
...@@ -1657,8 +1827,17 @@ void SpirvTransformer::transformInstruction() ...@@ -1657,8 +1827,17 @@ void SpirvTransformer::transformInstruction()
constexpr size_t kFunctionIdIndex = 2; constexpr size_t kFunctionIdIndex = 2;
mOpFunctionId = instruction[kFunctionIdIndex]; mOpFunctionId = instruction[kFunctionIdIndex];
// SPIR-V is structured in sections. Function declarations come last. Only Op*Access* // SPIR-V is structured in sections. Function declarations come last. Only a few
// opcodes inside functions need to be inspected. // instructions such as Op*Access* or OpEmitVertex opcodes inside functions need to be
// inspected.
//
// If this is the first OpFunction instruction, this is also where the declaration section
// finishes, so we need to declare anything that we need but didn't find there already right
// now.
if (!mIsInFunctionSection)
{
writePendingDeclarations();
}
mIsInFunctionSection = true; mIsInFunctionSection = true;
// Only write function variables for the EntryPoint function for non-compute shaders // Only write function variables for the EntryPoint function for non-compute shaders
...@@ -1758,9 +1937,55 @@ void SpirvTransformer::transformInstruction() ...@@ -1758,9 +1937,55 @@ void SpirvTransformer::transformInstruction()
mCurrentWord += wordCount; mCurrentWord += wordCount;
} }
// Called by transformInstruction to insert necessary instructions for casting varying // Called at the end of the declarations section. Any declarations that are necessary but weren't
// present in the original shader need to be done here.
void SpirvTransformer::writePendingDeclarations()
{
// Currently, only pre-rotation requires declarations that may not necessarily be in the shader.
if (IsRotationIdentity(mOptions.preRotation))
{
return;
}
if (mFloatId == 0)
{
mFloatId = getNewId();
writeTypeFloat(mFloatId, 32);
}
if (mVec4Id == 0)
{
mVec4Id = getNewId();
writeTypeVector(mVec4Id, mFloatId, 4);
}
if (mVec4OutTypePointerId == 0)
{
mVec4OutTypePointerId = getNewId();
writeTypePointer(mVec4OutTypePointerId, spv::StorageClassOutput, mVec4Id);
}
if (mIntId == 0)
{
mIntId = getNewId();
writeTypeInt(mIntId, 32, 1);
}
ASSERT(mInt0Id == 0);
mInt0Id = getNewId();
writeConstant(mInt0Id, mIntId, 0);
}
// Called by transformInstruction to insert necessary instructions for casting varyings.
void SpirvTransformer::writeInputPreamble() void SpirvTransformer::writeInputPreamble()
{ {
if (mOptions.shaderType == gl::ShaderType::Vertex ||
mOptions.shaderType == gl::ShaderType::Compute)
{
return;
}
// Copy from corrected varyings to temp global variables with original precision.
for (uint32_t id = 0; id < mVariableInfoById.size(); id++) for (uint32_t id = 0; id < mVariableInfoById.size(); id++)
{ {
const ShaderInterfaceVariableInfo *info = mVariableInfoById[id]; const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
...@@ -1776,7 +2001,7 @@ void SpirvTransformer::writeInputPreamble() ...@@ -1776,7 +2001,7 @@ void SpirvTransformer::writeInputPreamble()
uint32_t tempVarType = mTypePointerTransformedId[mFixedVaryingTypeId[id]].typeID; uint32_t tempVarType = mTypePointerTransformedId[mFixedVaryingTypeId[id]].typeID;
ASSERT(tempVarType != 0); ASSERT(tempVarType != 0);
writeLoad(mFixedVaryingId[id], tempVarType, tempVar); writeLoad(tempVar, tempVarType, mFixedVaryingId[id]);
// Build OpStore instruction to cast the mediump value to highp for use in // Build OpStore instruction to cast the mediump value to highp for use in
// the function // the function
...@@ -1785,9 +2010,17 @@ void SpirvTransformer::writeInputPreamble() ...@@ -1785,9 +2010,17 @@ void SpirvTransformer::writeInputPreamble()
} }
} }
// Called by transformInstruction to insert necessary instructions for casting varying // Called by transformInstruction to insert necessary instructions for casting varyings and
// modifying gl_Position.
void SpirvTransformer::writeOutputPrologue() void SpirvTransformer::writeOutputPrologue()
{ {
if (mOptions.shaderType == gl::ShaderType::Fragment ||
mOptions.shaderType == gl::ShaderType::Compute)
{
return;
}
// Copy from temp global variables with original precision to corrected varyings.
for (uint32_t id = 0; id < mVariableInfoById.size(); id++) for (uint32_t id = 0; id < mVariableInfoById.size(); id++)
{ {
const ShaderInterfaceVariableInfo *info = mVariableInfoById[id]; const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
...@@ -1801,12 +2034,105 @@ void SpirvTransformer::writeOutputPrologue() ...@@ -1801,12 +2034,105 @@ void SpirvTransformer::writeOutputPrologue()
uint32_t tempVarType = mTypePointerTransformedId[mFixedVaryingTypeId[id]].typeID; uint32_t tempVarType = mTypePointerTransformedId[mFixedVaryingTypeId[id]].typeID;
ASSERT(tempVarType != 0); ASSERT(tempVarType != 0);
writeLoad(id, tempVarType, tempVar); writeLoad(tempVar, tempVarType, id);
// Build OpStore instruction to cast the highp value to mediump for output // Build OpStore instruction to cast the highp value to mediump for output
writeStore(mFixedVaryingId[id], tempVar); writeStore(mFixedVaryingId[id], tempVar);
} }
} }
// Transform gl_Position to account for prerotation if necessary.
if (mOutputPerVertexId == 0 || IsRotationIdentity(mOptions.preRotation))
{
return;
}
// Generate the following SPIR-V for prerotation:
//
// // Create an access chain to output gl_PerVertex.gl_Position, which is always at index 0.
// %PositionPointer = OpAccessChain %mVec4OutTypePointerId %mOutputPerVertexId %mInt0Id
// // Load gl_Position
// %Position = OpLoad %mVec4Id %PositionPointer
// // Create gl_Position.x and gl_Position.y for transformation, as well as gl_Position.z
// // and gl_Position.w for later.
// %x = OpCompositeExtract %mFloatId %Position 0
// %y = OpCompositeExtract %mFloatId %Position 1
// %z = OpCompositeExtract %mFloatId %Position 2
// %w = OpCompositeExtract %mFloatId %Position 3
// // Transform %x and %y based on pre-rotation. This could include swapping the two ids
// // (in the transformer, no need to generate SPIR-V instructions for that), and/or
// // negating either component. To negate a component, the following instruction is used:
// (optional:) %negated = OpFNegate %mFloatId %component
// // Create the rotated gl_Position from the rotated x and y components.
// %RotatedPosition = OpCompositeConstruct %mVec4Id %rotatedX %rotatedY %z %w
// // Store the results back in gl_Position
// OpStore %PositionPointer %RotatedPosition
//
const uint32_t positionPointerId = getNewId();
const uint32_t positionId = getNewId();
const uint32_t xId = getNewId();
const uint32_t yId = getNewId();
const uint32_t zId = getNewId();
const uint32_t wId = getNewId();
const uint32_t rotatedPositionId = getNewId();
writeAccessChain(positionPointerId, mVec4OutTypePointerId, mOutputPerVertexId, mInt0Id);
writeLoad(positionId, mVec4Id, positionPointerId);
writeCompositeExtract(xId, mFloatId, positionId, 0);
writeCompositeExtract(yId, mFloatId, positionId, 1);
writeCompositeExtract(zId, mFloatId, positionId, 2);
writeCompositeExtract(wId, mFloatId, positionId, 3);
uint32_t rotatedXId = 0;
uint32_t rotatedYId = 0;
preRotateXY(xId, yId, &rotatedXId, &rotatedYId);
writeCompositeConstruct(rotatedPositionId, mVec4Id, {rotatedXId, rotatedYId, zId, wId});
writeStore(positionPointerId, rotatedPositionId);
}
void SpirvTransformer::preRotateXY(uint32_t xId,
uint32_t yId,
uint32_t *rotatedXIdOut,
uint32_t *rotatedYIdOut)
{
switch (mOptions.preRotation)
{
case SurfaceRotation::Identity:
case SurfaceRotation::FlippedIdentity:
// [ 1 0] [x]
// [ 0 1] * [y]
*rotatedXIdOut = xId;
*rotatedYIdOut = yId;
break;
case SurfaceRotation::Rotated90Degrees:
case SurfaceRotation::FlippedRotated90Degrees:
// [ 0 1] [x]
// [-1 0] * [y]
*rotatedXIdOut = yId;
*rotatedYIdOut = getNewId();
writeFNegate(*rotatedYIdOut, mFloatId, xId);
break;
case SurfaceRotation::Rotated180Degrees:
case SurfaceRotation::FlippedRotated180Degrees:
// [-1 0] [x]
// [ 0 -1] * [y]
*rotatedXIdOut = getNewId();
*rotatedYIdOut = getNewId();
writeFNegate(*rotatedXIdOut, mFloatId, xId);
writeFNegate(*rotatedYIdOut, mFloatId, yId);
break;
case SurfaceRotation::Rotated270Degrees:
case SurfaceRotation::FlippedRotated270Degrees:
// [ 0 -1] [x]
// [ 1 0] * [y]
*rotatedXIdOut = getNewId();
*rotatedYIdOut = xId;
writeFNegate(*rotatedXIdOut, mFloatId, yId);
break;
default:
UNREACHABLE();
}
} }
void SpirvTransformer::visitDecorate(const uint32_t *instruction) void SpirvTransformer::visitDecorate(const uint32_t *instruction)
...@@ -1945,6 +2271,42 @@ void SpirvTransformer::visitTypeArray(const uint32_t *instruction) ...@@ -1945,6 +2271,42 @@ void SpirvTransformer::visitTypeArray(const uint32_t *instruction)
visitTypeHelper(instruction, kIdIndex, kElementTypeIdIndex); visitTypeHelper(instruction, kIdIndex, kElementTypeIdIndex);
} }
void SpirvTransformer::visitTypeFloat(const uint32_t *instruction)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpTypeFloat
constexpr size_t kIdIndex = 1;
constexpr size_t kWidthIndex = 2;
const uint32_t id = instruction[kIdIndex];
const uint32_t width = instruction[kWidthIndex];
// Only interested in OpTypeFloat 32.
if (width == 32)
{
ASSERT(mFloatId == 0);
mFloatId = id;
}
}
void SpirvTransformer::visitTypeInt(const uint32_t *instruction)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpTypeInt
constexpr size_t kIdIndex = 1;
constexpr size_t kWidthIndex = 2;
constexpr size_t kSignednessIndex = 3;
const uint32_t id = instruction[kIdIndex];
const uint32_t width = instruction[kWidthIndex];
const uint32_t signedness = instruction[kSignednessIndex];
// Only interested in OpTypeInt 32 1.
if (width == 32 && signedness == 1)
{
ASSERT(mIntId == 0);
mIntId = id;
}
}
void SpirvTransformer::visitTypePointer(const uint32_t *instruction) void SpirvTransformer::visitTypePointer(const uint32_t *instruction)
{ {
// SPIR-V 1.0 Section 3.32 Instructions, OpTypePointer // SPIR-V 1.0 Section 3.32 Instructions, OpTypePointer
...@@ -1954,6 +2316,7 @@ void SpirvTransformer::visitTypePointer(const uint32_t *instruction) ...@@ -1954,6 +2316,7 @@ void SpirvTransformer::visitTypePointer(const uint32_t *instruction)
visitTypeHelper(instruction, kIdIndex, kTypeIdIndex); visitTypeHelper(instruction, kIdIndex, kTypeIdIndex);
const uint32_t id = instruction[kIdIndex];
const uint32_t typeId = instruction[kTypeIdIndex]; const uint32_t typeId = instruction[kTypeIdIndex];
const uint32_t storageClass = instruction[kStorageClassIndex]; const uint32_t storageClass = instruction[kStorageClassIndex];
...@@ -1967,6 +2330,38 @@ void SpirvTransformer::visitTypePointer(const uint32_t *instruction) ...@@ -1967,6 +2330,38 @@ void SpirvTransformer::visitTypePointer(const uint32_t *instruction)
{ {
std::swap(mOutputPerVertex.typeId, mInputPerVertex.typeId); std::swap(mOutputPerVertex.typeId, mInputPerVertex.typeId);
} }
// Remember type pointer of output gl_PerVertex for gl_Position transformations.
if (storageClass == spv::StorageClassOutput)
{
mOutputPerVertexTypePointerId = id;
}
}
// If OpTypePointer Output %mVec4ID was encountered, remember that. Otherwise we'll have to
// generate one.
if (typeId == mVec4Id && storageClass == spv::StorageClassOutput)
{
mVec4OutTypePointerId = id;
}
}
void SpirvTransformer::visitTypeVector(const uint32_t *instruction)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpTypeVector
constexpr size_t kIdIndex = 1;
constexpr size_t kComponentIdIndex = 2;
constexpr size_t kComponentCountIndex = 3;
const uint32_t id = instruction[kIdIndex];
const uint32_t componentId = instruction[kComponentIdIndex];
const uint32_t componentCount = instruction[kComponentCountIndex];
// Only interested in OpTypeVector %mFloatId 4
if (componentId == mFloatId && componentCount == 4)
{
ASSERT(mVec4Id == 0);
mVec4Id = id;
} }
} }
...@@ -2023,6 +2418,15 @@ void SpirvTransformer::visitVariable(const uint32_t *instruction) ...@@ -2023,6 +2418,15 @@ void SpirvTransformer::visitVariable(const uint32_t *instruction)
return; return;
} }
if (typeId == mOutputPerVertexTypePointerId)
{
// If this is the output gl_PerVertex variable, remember its id for gl_Position
// transformations.
ASSERT(storageClass == spv::StorageClassOutput && isIOBlock &&
strcmp(name, "gl_PerVertex") == 0);
mOutputPerVertexId = id;
}
// Every shader interface variable should have an associated data. // Every shader interface variable should have an associated data.
const ShaderInterfaceVariableInfo &info = mVariableInfoMap.get(mOptions.shaderType, name); const ShaderInterfaceVariableInfo &info = mVariableInfoMap.get(mOptions.shaderType, name);
...@@ -2554,11 +2958,10 @@ bool SpirvTransformer::transformVariable(const uint32_t *instruction, size_t wor ...@@ -2554,11 +2958,10 @@ bool SpirvTransformer::transformVariable(const uint32_t *instruction, size_t wor
return false; return false;
} }
if (mOptions.isTransformFeedbackStage && storageClass == spv::StorageClassUniform) if (mOptions.shaderType == gl::ShaderType::Vertex && storageClass == spv::StorageClassUniform)
{ {
// Exceptionally, the ANGLEXfbN variables are unconditionally generated and may be inactive. // Exceptionally, the ANGLEXfbN variables are unconditionally generated and may be inactive.
// Remove these variables in that case. // Remove these variables in that case.
ASSERT(mOptions.shaderType == gl::ShaderType::Vertex);
ASSERT(info == &mVariableInfoMap.get(mOptions.shaderType, GetXfbBufferName(0)) || ASSERT(info == &mVariableInfoMap.get(mOptions.shaderType, GetXfbBufferName(0)) ||
info == &mVariableInfoMap.get(mOptions.shaderType, GetXfbBufferName(1)) || info == &mVariableInfoMap.get(mOptions.shaderType, GetXfbBufferName(1)) ||
info == &mVariableInfoMap.get(mOptions.shaderType, GetXfbBufferName(2)) || info == &mVariableInfoMap.get(mOptions.shaderType, GetXfbBufferName(2)) ||
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <functional> #include <functional>
#include "libANGLE/renderer/ProgramImpl.h" #include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/renderer_utils.h"
namespace rx namespace rx
{ {
...@@ -55,6 +56,7 @@ struct GlslangSourceOptions ...@@ -55,6 +56,7 @@ struct GlslangSourceOptions
struct GlslangSpirvOptions struct GlslangSpirvOptions
{ {
gl::ShaderType shaderType = gl::ShaderType::InvalidEnum; gl::ShaderType shaderType = gl::ShaderType::InvalidEnum;
SurfaceRotation preRotation = SurfaceRotation::Identity;
bool removeEarlyFragmentTestsOptimization = false; bool removeEarlyFragmentTestsOptimization = false;
bool removeDebugInfo = false; bool removeDebugInfo = false;
bool isTransformFeedbackStage = false; bool isTransformFeedbackStage = false;
......
...@@ -95,9 +95,6 @@ struct GraphicsDriverUniformsExtended ...@@ -95,9 +95,6 @@ struct GraphicsDriverUniformsExtended
std::array<float, 2> negFlipXY; std::array<float, 2> negFlipXY;
std::array<int32_t, 2> padding; std::array<int32_t, 2> padding;
// Used to pre-rotate gl_Position for swapchain images on Android (a mat2, which is padded to
// the size of two vec4's).
std::array<float, 8> preRotation;
// Used to pre-rotate gl_FragCoord for swapchain images on Android (a mat2, which is padded to // Used to pre-rotate gl_FragCoord for swapchain images on Android (a mat2, which is padded to
// the size of two vec4's). // the size of two vec4's).
std::array<float, 8> fragRotation; std::array<float, 8> fragRotation;
...@@ -191,34 +188,15 @@ bool IsRenderPassStartedAndUsesImage(const vk::CommandBufferHelper &renderPassCo ...@@ -191,34 +188,15 @@ bool IsRenderPassStartedAndUsesImage(const vk::CommandBufferHelper &renderPassCo
} }
// When an Android surface is rotated differently than the device's native orientation, ANGLE must // 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 // rotate gl_Position in the last pre-rasterization shader and gl_FragCoord in the fragment shader.
// are the rotation matrices used. // Rotation of gl_Position is done in SPIR-V. The following are the rotation matrices for the
// fragment shader.
// //
// Note: these are mat2's that are appropriately padded (4 floats per row). // Note: these are mat2's that are appropriately padded (4 floats per row).
using PreRotationMatrixValues = std::array<float, 8>; using PreRotationMatrixValues = std::array<float, 8>;
constexpr angle::PackedEnumMap<rx::SurfaceRotation, constexpr angle::PackedEnumMap<rx::SurfaceRotation,
PreRotationMatrixValues, PreRotationMatrixValues,
angle::EnumSize<rx::SurfaceRotation>()> angle::EnumSize<rx::SurfaceRotation>()>
kPreRotationMatrices = {
{{rx::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::Rotated90Degrees,
{{0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::Rotated180Degrees,
{{-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::Rotated270Degrees,
{{0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::FlippedIdentity,
{{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::FlippedRotated90Degrees,
{{0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::FlippedRotated180Degrees,
{{-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::FlippedRotated270Degrees,
{{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}}}};
constexpr angle::PackedEnumMap<rx::SurfaceRotation,
PreRotationMatrixValues,
angle::EnumSize<rx::SurfaceRotation>()>
kFragRotationMatrices = { kFragRotationMatrices = {
{{rx::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}}, {{rx::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::Rotated90Degrees, {rx::SurfaceRotation::Rotated90Degrees,
...@@ -3215,9 +3193,15 @@ void ContextVk::updateGraphicsPipelineDescWithSpecConstUsageBits(SpecConstUsageB ...@@ -3215,9 +3193,15 @@ void ContextVk::updateGraphicsPipelineDescWithSpecConstUsageBits(SpecConstUsageB
bool yFlipped = bool yFlipped =
isViewportFlipEnabledForDrawFBO() && usageBits.test(sh::vk::SpecConstUsage::YFlip); isViewportFlipEnabledForDrawFBO() && usageBits.test(sh::vk::SpecConstUsage::YFlip);
// usageBits are only set when specialization constants are used. With gl_Position pre-rotation
// handled by the SPIR-V transformer, we need to have this information even when the driver
// uniform path is taken to pre-rotate everything else.
const bool programUsesRotation = usageBits.test(sh::vk::SpecConstUsage::Rotation) ||
getFeatures().forceDriverUniformOverSpecConst.enabled;
// If program is not using rotation at all, we force it to use the Identity or FlippedIdentity // If program is not using rotation at all, we force it to use the Identity or FlippedIdentity
// slot to improve the program cache hit rate // slot to improve the program cache hit rate
if (!usageBits.test(sh::vk::SpecConstUsage::Rotation)) if (!programUsesRotation)
{ {
rotationAndFlip = yFlipped ? SurfaceRotation::FlippedIdentity : SurfaceRotation::Identity; rotationAndFlip = yFlipped ? SurfaceRotation::FlippedIdentity : SurfaceRotation::Identity;
} }
...@@ -3842,9 +3826,6 @@ angle::Result ContextVk::handleDirtyGraphicsDriverUniforms(const gl::Context *co ...@@ -3842,9 +3826,6 @@ angle::Result ContextVk::handleDirtyGraphicsDriverUniforms(const gl::Context *co
driverUniformsExt->halfRenderArea = {halfRenderAreaWidth, halfRenderAreaHeight}; driverUniformsExt->halfRenderArea = {halfRenderAreaWidth, halfRenderAreaHeight};
driverUniformsExt->flipXY = {flipX, flipY}; driverUniformsExt->flipXY = {flipX, flipY};
driverUniformsExt->negFlipXY = {flipX, -flipY}; driverUniformsExt->negFlipXY = {flipX, -flipY};
memcpy(&driverUniformsExt->preRotation,
&kPreRotationMatrices[mCurrentRotationDrawFramebuffer],
sizeof(PreRotationMatrixValues));
memcpy(&driverUniformsExt->fragRotation, memcpy(&driverUniformsExt->fragRotation,
&kFragRotationMatrices[mCurrentRotationDrawFramebuffer], &kFragRotationMatrices[mCurrentRotationDrawFramebuffer],
sizeof(PreRotationMatrixValues)); sizeof(PreRotationMatrixValues));
......
...@@ -28,12 +28,15 @@ bool ValidateTransformedSpirV(ContextVk *contextVk, ...@@ -28,12 +28,15 @@ bool ValidateTransformedSpirV(ContextVk *contextVk,
const ShaderInterfaceVariableInfoMap &variableInfoMap, const ShaderInterfaceVariableInfoMap &variableInfoMap,
const gl::ShaderMap<SpirvBlob> &spirvBlobs) const gl::ShaderMap<SpirvBlob> &spirvBlobs)
{ {
const gl::ShaderType lastPreFragmentStage = gl::GetLastPreFragmentStage(linkedShaderStages);
for (gl::ShaderType shaderType : linkedShaderStages) for (gl::ShaderType shaderType : linkedShaderStages)
{ {
GlslangSpirvOptions options; GlslangSpirvOptions options;
options.shaderType = shaderType; options.shaderType = shaderType;
options.preRotation = SurfaceRotation::FlippedRotated90Degrees;
options.removeDebugInfo = true; options.removeDebugInfo = true;
options.isTransformFeedbackStage = shaderType == gl::ShaderType::Vertex; options.isTransformFeedbackStage = shaderType == lastPreFragmentStage;
SpirvBlob transformed; SpirvBlob transformed;
if (GlslangWrapperVk::TransformSpirV(contextVk, options, variableInfoMap, if (GlslangWrapperVk::TransformSpirV(contextVk, options, variableInfoMap,
...@@ -117,6 +120,7 @@ ProgramInfo::~ProgramInfo() = default; ...@@ -117,6 +120,7 @@ ProgramInfo::~ProgramInfo() = default;
angle::Result ProgramInfo::initProgram(ContextVk *contextVk, angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool isLastPreFragmentStage,
const ShaderInfo &shaderInfo, const ShaderInfo &shaderInfo,
ProgramTransformOptions optionBits, ProgramTransformOptions optionBits,
const ShaderInterfaceVariableInfoMap &variableInfoMap) const ShaderInterfaceVariableInfoMap &variableInfoMap)
...@@ -131,7 +135,12 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk, ...@@ -131,7 +135,12 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
options.removeEarlyFragmentTestsOptimization = options.removeEarlyFragmentTestsOptimization =
shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization; shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization;
options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers(); options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers();
options.isTransformFeedbackStage = shaderType == gl::ShaderType::Vertex; options.isTransformFeedbackStage = isLastPreFragmentStage;
if (isLastPreFragmentStage)
{
options.preRotation = static_cast<SurfaceRotation>(optionBits.surfaceRotation);
}
ANGLE_TRY(GlslangWrapperVk::TransformSpirV(contextVk, options, variableInfoMap, ANGLE_TRY(GlslangWrapperVk::TransformSpirV(contextVk, options, variableInfoMap,
originalSpirvBlob, &transformedSpirvBlob)); originalSpirvBlob, &transformedSpirvBlob));
...@@ -677,14 +686,18 @@ angle::Result ProgramExecutableVk::getGraphicsPipeline( ...@@ -677,14 +686,18 @@ angle::Result ProgramExecutableVk::getGraphicsPipeline(
mTransformOptions.surfaceRotation = ToUnderlying(desc.getSurfaceRotation()); mTransformOptions.surfaceRotation = ToUnderlying(desc.getSurfaceRotation());
// This must be called after mTransformOptions have been set. // This must be called after mTransformOptions have been set.
ProgramInfo &programInfo = getGraphicsProgramInfo(mTransformOptions); ProgramInfo &programInfo = getGraphicsProgramInfo(mTransformOptions);
for (const gl::ShaderType shaderType : glExecutable->getLinkedShaderStages()) const gl::ShaderBitSet linkedShaderStages = glExecutable->getLinkedShaderStages();
const gl::ShaderType lastPreFragmentStage = gl::GetLastPreFragmentStage(linkedShaderStages);
for (const gl::ShaderType shaderType : linkedShaderStages)
{ {
ProgramVk *programVk = getShaderProgram(glState, shaderType); ProgramVk *programVk = getShaderProgram(glState, shaderType);
if (programVk) if (programVk)
{ {
ANGLE_TRY(programVk->initGraphicsShaderProgram(contextVk, shaderType, mTransformOptions, ANGLE_TRY(programVk->initGraphicsShaderProgram(
&programInfo, mVariableInfoMap)); contextVk, shaderType, shaderType == lastPreFragmentStage, mTransformOptions,
&programInfo, mVariableInfoMap));
} }
} }
......
...@@ -67,6 +67,7 @@ class ProgramInfo final : angle::NonCopyable ...@@ -67,6 +67,7 @@ class ProgramInfo final : angle::NonCopyable
angle::Result initProgram(ContextVk *contextVk, angle::Result initProgram(ContextVk *contextVk,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool isLastPreFragmentStage,
const ShaderInfo &shaderInfo, const ShaderInfo &shaderInfo,
ProgramTransformOptions optionBits, ProgramTransformOptions optionBits,
const ShaderInterfaceVariableInfoMap &variableInfoMap); const ShaderInterfaceVariableInfoMap &variableInfoMap);
......
...@@ -148,11 +148,13 @@ class ProgramVk : public ProgramImpl ...@@ -148,11 +148,13 @@ class ProgramVk : public ProgramImpl
ANGLE_INLINE angle::Result initGraphicsShaderProgram( ANGLE_INLINE angle::Result initGraphicsShaderProgram(
ContextVk *contextVk, ContextVk *contextVk,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool isLastPreFragmentStage,
ProgramTransformOptions optionBits, ProgramTransformOptions optionBits,
ProgramInfo *programInfo, ProgramInfo *programInfo,
const ShaderInterfaceVariableInfoMap &variableInfoMap) const ShaderInterfaceVariableInfoMap &variableInfoMap)
{ {
return initProgram(contextVk, shaderType, optionBits, programInfo, variableInfoMap); return initProgram(contextVk, shaderType, isLastPreFragmentStage, optionBits, programInfo,
variableInfoMap);
} }
ANGLE_INLINE angle::Result initComputeProgram( ANGLE_INLINE angle::Result initComputeProgram(
...@@ -161,7 +163,7 @@ class ProgramVk : public ProgramImpl ...@@ -161,7 +163,7 @@ class ProgramVk : public ProgramImpl
const ShaderInterfaceVariableInfoMap &variableInfoMap) const ShaderInterfaceVariableInfoMap &variableInfoMap)
{ {
ProgramTransformOptions optionBits = {}; ProgramTransformOptions optionBits = {};
return initProgram(contextVk, gl::ShaderType::Compute, optionBits, programInfo, return initProgram(contextVk, gl::ShaderType::Compute, false, optionBits, programInfo,
variableInfoMap); variableInfoMap);
} }
...@@ -194,6 +196,7 @@ class ProgramVk : public ProgramImpl ...@@ -194,6 +196,7 @@ class ProgramVk : public ProgramImpl
ANGLE_INLINE angle::Result initProgram(ContextVk *contextVk, ANGLE_INLINE angle::Result initProgram(ContextVk *contextVk,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool isLastPreFragmentStage,
ProgramTransformOptions optionBits, ProgramTransformOptions optionBits,
ProgramInfo *programInfo, ProgramInfo *programInfo,
const ShaderInterfaceVariableInfoMap &variableInfoMap) const ShaderInterfaceVariableInfoMap &variableInfoMap)
...@@ -204,8 +207,8 @@ class ProgramVk : public ProgramImpl ...@@ -204,8 +207,8 @@ class ProgramVk : public ProgramImpl
// specialization constants. // specialization constants.
if (!programInfo->valid(shaderType)) if (!programInfo->valid(shaderType))
{ {
ANGLE_TRY(programInfo->initProgram(contextVk, shaderType, mOriginalShaderInfo, ANGLE_TRY(programInfo->initProgram(contextVk, shaderType, isLastPreFragmentStage,
optionBits, variableInfoMap)); mOriginalShaderInfo, optionBits, variableInfoMap));
} }
ASSERT(programInfo->valid(shaderType)); ASSERT(programInfo->valid(shaderType));
......
...@@ -109,11 +109,11 @@ class EGLPreRotationSurfaceTest : public ANGLETestWithParam<EGLPreRotationSurfac ...@@ -109,11 +109,11 @@ class EGLPreRotationSurfaceTest : public ANGLETestWithParam<EGLPreRotationSurfac
std::vector<const char *> disabledFeatures; std::vector<const char *> disabledFeatures;
if (::testing::get<1>(GetParam())) if (::testing::get<1>(GetParam()))
{ {
enabledFeatures.push_back("enable_pre_rotation_surfaces"); enabledFeatures.push_back("enablePreRotateSurfaces");
} }
else else
{ {
disabledFeatures.push_back("enable_pre_rotation_surfaces"); disabledFeatures.push_back("enablePreRotateSurfaces");
} }
enabledFeatures.push_back(nullptr); enabledFeatures.push_back(nullptr);
disabledFeatures.push_back(nullptr); disabledFeatures.push_back(nullptr);
......
...@@ -1348,9 +1348,6 @@ TEST_P(GeometryShaderTest, Prerotation) ...@@ -1348,9 +1348,6 @@ TEST_P(GeometryShaderTest, Prerotation)
{ {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
// http://anglebug.com/5478
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr char kVS[] = R"(#version 310 es constexpr char kVS[] = R"(#version 310 es
void main() void main()
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment