Commit b36a4816 by Jamie Madill Committed by Commit Bot

Vulkan: Add OpenGL line segment rasterization.

Line rasterization rules are implemented using a shader patch. The patch does a small test and discards pixels that are outside of the OpenGL line region. The feature is disabled on Android until we can determine the root cause of the test failures. Bug: angleproject:2598 Change-Id: Ic76c5e40fa3ceff7643e735e66f5a9050240c80b Reviewed-on: https://chromium-review.googlesource.com/1120153 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent beb669da
...@@ -591,6 +591,21 @@ bool IsTriangleMode(PrimitiveMode drawMode) ...@@ -591,6 +591,21 @@ bool IsTriangleMode(PrimitiveMode drawMode)
return false; return false;
} }
bool IsLineMode(PrimitiveMode primitiveMode)
{
switch (primitiveMode)
{
case PrimitiveMode::LineLoop:
case PrimitiveMode::LineStrip:
case PrimitiveMode::LineStripAdjacency:
case PrimitiveMode::Lines:
return true;
default:
return false;
}
}
bool IsIntegerFormat(GLenum unsizedFormat) bool IsIntegerFormat(GLenum unsizedFormat)
{ {
switch (unsizedFormat) switch (unsizedFormat)
......
...@@ -72,6 +72,7 @@ IndexRange ComputeIndexRange(GLenum indexType, ...@@ -72,6 +72,7 @@ IndexRange ComputeIndexRange(GLenum indexType,
GLuint GetPrimitiveRestartIndex(GLenum indexType); GLuint GetPrimitiveRestartIndex(GLenum indexType);
bool IsTriangleMode(PrimitiveMode drawMode); bool IsTriangleMode(PrimitiveMode drawMode);
bool IsLineMode(PrimitiveMode primitiveMode);
bool IsIntegerFormat(GLenum unsizedFormat); bool IsIntegerFormat(GLenum unsizedFormat);
// Returns the product of the sizes in the vector, or 1 if the vector is empty. Doesn't currently // Returns the product of the sizes in the vector, or 1 if the vector is empty. Doesn't currently
......
...@@ -863,6 +863,12 @@ void TIntermBlock::appendStatement(TIntermNode *statement) ...@@ -863,6 +863,12 @@ void TIntermBlock::appendStatement(TIntermNode *statement)
} }
} }
void TIntermBlock::insertStatement(size_t insertPosition, TIntermNode *statement)
{
ASSERT(statement != nullptr);
mStatements.insert(mStatements.begin() + insertPosition, statement);
}
void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator) void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
{ {
ASSERT(declarator != nullptr); ASSERT(declarator != nullptr);
......
...@@ -239,7 +239,7 @@ class TIntermBranch : public TIntermNode ...@@ -239,7 +239,7 @@ class TIntermBranch : public TIntermNode
protected: protected:
TOperator mFlowOp; TOperator mFlowOp;
TIntermTyped *mExpression; // non-zero except for "return exp;" statements TIntermTyped *mExpression; // zero except for "return exp;" statements
}; };
// Nodes that correspond to variable symbols in the source code. These may be regular variables or // Nodes that correspond to variable symbols in the source code. These may be regular variables or
...@@ -665,6 +665,7 @@ class TIntermBlock : public TIntermNode, public TIntermAggregateBase ...@@ -665,6 +665,7 @@ class TIntermBlock : public TIntermNode, public TIntermAggregateBase
// Only intended for initially building the block. // Only intended for initially building the block.
void appendStatement(TIntermNode *statement); void appendStatement(TIntermNode *statement);
void insertStatement(size_t insertPosition, TIntermNode *statement);
TIntermSequence *getSequence() override { return &mStatements; } TIntermSequence *getSequence() override { return &mStatements; }
const TIntermSequence *getSequence() const override { return &mStatements; } const TIntermSequence *getSequence() const override { return &mStatements; }
......
...@@ -81,7 +81,6 @@ class TOutputGLSLBase : public TIntermTraverser ...@@ -81,7 +81,6 @@ class TOutputGLSLBase : public TIntermTraverser
bool structDeclared(const TStructure *structure) const; bool structDeclared(const TStructure *structure) const;
private: private:
void declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock); void declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock);
void declareInterfaceBlock(const TInterfaceBlock *interfaceBlock); void declareInterfaceBlock(const TInterfaceBlock *interfaceBlock);
......
...@@ -44,6 +44,7 @@ class TSymbol : angle::NonCopyable ...@@ -44,6 +44,7 @@ class TSymbol : angle::NonCopyable
bool isFunction() const { return mSymbolClass == SymbolClass::Function; } bool isFunction() const { return mSymbolClass == SymbolClass::Function; }
bool isVariable() const { return mSymbolClass == SymbolClass::Variable; } bool isVariable() const { return mSymbolClass == SymbolClass::Variable; }
bool isStruct() const { return mSymbolClass == SymbolClass::Struct; } bool isStruct() const { return mSymbolClass == SymbolClass::Struct; }
bool isInterfaceBlock() const { return mSymbolClass == SymbolClass::InterfaceBlock; }
const TSymbolUniqueId &uniqueId() const { return mUniqueId; } const TSymbolUniqueId &uniqueId() const { return mUniqueId; }
SymbolType symbolType() const { return mSymbolType; } SymbolType symbolType() const { return mSymbolType; }
......
...@@ -153,25 +153,30 @@ constexpr ImmutableString kFlippedPointCoordName = ImmutableString("flippedPoint ...@@ -153,25 +153,30 @@ constexpr ImmutableString kFlippedPointCoordName = ImmutableString("flippedPoint
constexpr ImmutableString kFlippedFragCoordName = ImmutableString("flippedFragCoord"); constexpr ImmutableString kFlippedFragCoordName = ImmutableString("flippedFragCoord");
constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams"); constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams");
constexpr const char *kHalfRenderAreaHeight = "halfRenderAreaHeight"; constexpr const char kViewport[] = "viewport";
constexpr const char *kViewportYScale = "viewportYScale"; constexpr const char kHalfRenderAreaHeight[] = "halfRenderAreaHeight";
constexpr const char *kInviewportYScale = "invViewportYScale"; constexpr const char kViewportYScale[] = "viewportYScale";
constexpr const char *kDepthRange = "depthRange"; constexpr const char kNegViewportYScale[] = "negViewportYScale";
constexpr const char kDepthRange[] = "depthRange";
constexpr size_t kNumDriverUniforms = 6; constexpr size_t kNumDriverUniforms = 6;
constexpr std::array<const char *, kNumDriverUniforms> kDriverUniformNames = { constexpr std::array<const char *, kNumDriverUniforms> kDriverUniformNames = {
{"viewport", kHalfRenderAreaHeight, kViewportYScale, kInviewportYScale, "padding", {kViewport, kHalfRenderAreaHeight, kViewportYScale, kNegViewportYScale, "padding",
kDepthRange}}; kDepthRange}};
TIntermConstantUnion *CreateConstantFloat(float value) template <TBasicType BasicType = EbtFloat, unsigned char PrimarySize = 1>
TIntermConstantUnion *CreateBasicConstant(float value)
{ {
const TType *constantType = StaticType::GetBasic<TBasicType::EbtFloat>(); const TType *constantType = StaticType::GetBasic<BasicType, PrimarySize>();
TConstantUnion *constantValue = new TConstantUnion(); TConstantUnion *constantValue = new TConstantUnion[PrimarySize];
constantValue->setFConst(value); for (unsigned char sizeIndex = 0; sizeIndex < PrimarySize; ++sizeIndex)
{
constantValue[sizeIndex].setFConst(value);
}
return new TIntermConstantUnion(constantValue, *constantType); return new TIntermConstantUnion(constantValue, *constantType);
} }
size_t FieldFieldIndex(const TFieldList &fieldList, const char *fieldName) size_t FindFieldIndex(const TFieldList &fieldList, const char *fieldName)
{ {
for (size_t fieldIndex = 0; fieldIndex < fieldList.size(); ++fieldIndex) for (size_t fieldIndex = 0; fieldIndex < fieldList.size(); ++fieldIndex)
{ {
...@@ -187,7 +192,7 @@ size_t FieldFieldIndex(const TFieldList &fieldList, const char *fieldName) ...@@ -187,7 +192,7 @@ size_t FieldFieldIndex(const TFieldList &fieldList, const char *fieldName)
TIntermBinary *CreateDriverUniformRef(const TVariable *driverUniforms, const char *fieldName) TIntermBinary *CreateDriverUniformRef(const TVariable *driverUniforms, const char *fieldName)
{ {
size_t fieldIndex = size_t fieldIndex =
FieldFieldIndex(driverUniforms->getType().getInterfaceBlock()->fields(), fieldName); FindFieldIndex(driverUniforms->getType().getInterfaceBlock()->fields(), fieldName);
TIntermSymbol *angleUniformsRef = new TIntermSymbol(driverUniforms); TIntermSymbol *angleUniformsRef = new TIntermSymbol(driverUniforms);
TConstantUnion *uniformIndex = new TConstantUnion; TConstantUnion *uniformIndex = new TConstantUnion;
...@@ -199,6 +204,7 @@ TIntermBinary *CreateDriverUniformRef(const TVariable *driverUniforms, const cha ...@@ -199,6 +204,7 @@ TIntermBinary *CreateDriverUniformRef(const TVariable *driverUniforms, const cha
// Replaces a builtin variable with a version that corrects the Y coordinate. // Replaces a builtin variable with a version that corrects the Y coordinate.
void FlipBuiltinVariable(TIntermBlock *root, void FlipBuiltinVariable(TIntermBlock *root,
TIntermSequence *insertSequence,
TIntermTyped *viewportYScale, TIntermTyped *viewportYScale,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
const TVariable *builtin, const TVariable *builtin,
...@@ -240,10 +246,14 @@ void FlipBuiltinVariable(TIntermBlock *root, ...@@ -240,10 +246,14 @@ void FlipBuiltinVariable(TIntermBlock *root,
TIntermBinary *assignToY = new TIntermBinary(EOpAssign, correctedY, plusPivot); TIntermBinary *assignToY = new TIntermBinary(EOpAssign, correctedY, plusPivot);
// Add this assigment at the beginning of the main function // Add this assigment at the beginning of the main function
insertSequence->insert(insertSequence->begin(), assignToY);
insertSequence->insert(insertSequence->begin(), assignment);
}
TIntermSequence *GetMainSequence(TIntermBlock *root)
{
TIntermFunctionDefinition *main = FindMain(root); TIntermFunctionDefinition *main = FindMain(root);
TIntermSequence *mainSequence = main->getBody()->getSequence(); return main->getBody()->getSequence();
mainSequence->insert(mainSequence->begin(), assignToY);
mainSequence->insert(mainSequence->begin(), assignment);
} }
// Declares a new variable to replace gl_DepthRange, its values are fed from a driver uniform. // Declares a new variable to replace gl_DepthRange, its values are fed from a driver uniform.
...@@ -283,7 +293,7 @@ void AppendVertexShaderDepthCorrectionToMain(TIntermBlock *root, TSymbolTable *s ...@@ -283,7 +293,7 @@ void AppendVertexShaderDepthCorrectionToMain(TIntermBlock *root, TSymbolTable *s
TIntermSwizzle *positionZ = new TIntermSwizzle(positionRef, swizzleOffsetZ); TIntermSwizzle *positionZ = new TIntermSwizzle(positionRef, swizzleOffsetZ);
// Create a constant "0.5" // Create a constant "0.5"
TIntermConstantUnion *oneHalf = CreateConstantFloat(0.5f); TIntermConstantUnion *oneHalf = CreateBasicConstant(0.5f);
// Create a swizzle to "gl_Position.w" // Create a swizzle to "gl_Position.w"
TVector<int> swizzleOffsetW; TVector<int> swizzleOffsetW;
...@@ -371,6 +381,240 @@ const TVariable *AddDriverUniformsToShader(TIntermBlock *root, TSymbolTable *sym ...@@ -371,6 +381,240 @@ const TVariable *AddDriverUniformsToShader(TIntermBlock *root, TSymbolTable *sym
return driverUniformsVar; return driverUniformsVar;
} }
TIntermPreprocessorDirective *GenerateLineRasterIfDef()
{
return new TIntermPreprocessorDirective(
PreprocessorDirective::Ifdef, ImmutableString("ANGLE_ENABLE_LINE_SEGMENT_RASTERIZATION"));
}
TIntermPreprocessorDirective *GenerateEndIf()
{
return new TIntermPreprocessorDirective(PreprocessorDirective::Endif, kEmptyImmutableString);
}
TVariable *AddANGLEPositionVaryingDeclaration(TIntermBlock *root,
TSymbolTable *symbolTable,
TQualifier qualifier)
{
TIntermSequence *insertSequence = new TIntermSequence;
insertSequence->push_back(GenerateLineRasterIfDef());
// Define a driver varying vec2 "ANGLEPosition".
TType *varyingType = new TType(EbtFloat, EbpMedium, qualifier, 4);
TVariable *varyingVar = new TVariable(symbolTable, ImmutableString("ANGLEPosition"),
varyingType, SymbolType::AngleInternal);
TIntermSymbol *varyingDeclarator = new TIntermSymbol(varyingVar);
TIntermDeclaration *varyingDecl = new TIntermDeclaration;
varyingDecl->appendDeclarator(varyingDeclarator);
insertSequence->push_back(varyingDecl);
insertSequence->push_back(GenerateEndIf());
// Insert the declarations before Main.
size_t mainIndex = FindMainIndex(root);
root->insertChildNodes(mainIndex, *insertSequence);
return varyingVar;
}
void AddANGLEPositionVarying(TIntermBlock *root, TSymbolTable *symbolTable)
{
TVariable *anglePosition = AddANGLEPositionVaryingDeclaration(root, symbolTable, EvqVaryingOut);
// Create an assignment "ANGLEPosition = gl_Position".
const TVariable *position = BuiltInVariable::gl_Position();
TIntermSymbol *varyingRef = new TIntermSymbol(anglePosition);
TIntermBinary *assignment =
new TIntermBinary(EOpAssign, varyingRef, new TIntermSymbol(position));
// Ensure the assignment runs at the end of the main() function.
TIntermFunctionDefinition *main = FindMain(root);
TIntermBlock *mainBody = main->getBody();
mainBody->appendStatement(GenerateLineRasterIfDef());
mainBody->appendStatement(assignment);
mainBody->appendStatement(GenerateEndIf());
}
void InsertFragCoordCorrection(TIntermBlock *root,
TIntermSequence *insertSequence,
TSymbolTable *symbolTable,
const TVariable *driverUniforms)
{
TIntermBinary *viewportYScale = CreateDriverUniformRef(driverUniforms, kViewportYScale);
TIntermBinary *pivot = CreateDriverUniformRef(driverUniforms, kHalfRenderAreaHeight);
FlipBuiltinVariable(root, insertSequence, viewportYScale, symbolTable,
BuiltInVariable::gl_FragCoord(), kFlippedFragCoordName, pivot);
}
// This block adds OpenGL line segment rasterization emulation behind #ifdef guards.
// OpenGL's simple rasterization algorithm is a strict subset of the pixels generated by the Vulkan
// algorithm. Thus we can implement a shader patch that rejects pixels if they would not be
// generated by the OpenGL algorithm. OpenGL's algorithm is similar to Bresenham's line algorithm.
// It is implemented for each pixel by testing if the line segment crosses a small diamond inside
// the pixel. See the OpenGL ES 2.0 spec section "3.4.1 Basic Line Segment Rasterization". Also
// see the Vulkan spec section "24.6.1. Basic Line Segment Rasterization":
// https://khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#primsrast-lines-basic
//
// Using trigonometric math and the fact that we know the size of the diamond we can derive a
// formula to test if the line segment crosses the pixel center. gl_FragCoord is used along with an
// internal position varying to determine the inputs to the formula.
//
// The implementation of the test code is similar to the following pseudocode:
//
// void main()
// {
// vec2 b = (((position.xy / position.w) * 0.5) + 0.5) * gl_Viewport.zw + gl_Viewport.xy;
// vec2 ba = abs(b - gl_FragCoord.xy);
// vec2 ba2 = 2.0 * (ba * ba);
// vec2 bp = ba2 + ba2.yx - ba;
// if (bp.x > epsilon && bp.y > epsilon)
// discard;
// <otherwise run fragment shader main>
// }
void AddLineSegmentRasterizationEmulation(TInfoSinkBase &sink,
TIntermBlock *root,
TSymbolTable *symbolTable,
const TVariable *driverUniforms,
bool usesFragCoord)
{
TVariable *anglePosition = AddANGLEPositionVaryingDeclaration(root, symbolTable, EvqVaryingIn);
const TType *vec2Type = StaticType::GetBasic<EbtFloat, 2>();
// Create a swizzle to "ANGLEUniforms.viewport.xy".
TIntermBinary *viewportRef = CreateDriverUniformRef(driverUniforms, kViewport);
TVector<int> swizzleOffsetXY;
swizzleOffsetXY.push_back(0);
swizzleOffsetXY.push_back(1);
TIntermSwizzle *viewportXY = new TIntermSwizzle(viewportRef->deepCopy(), swizzleOffsetXY);
// Create a swizzle to "ANGLEUniforms.viewport.zw".
TVector<int> swizzleOffsetZW;
swizzleOffsetZW.push_back(2);
swizzleOffsetZW.push_back(3);
TIntermSwizzle *viewportZW = new TIntermSwizzle(viewportRef, swizzleOffsetZW);
// ANGLEPosition.xy / ANGLEPosition.w
TIntermSymbol *position = new TIntermSymbol(anglePosition);
TIntermSwizzle *positionXY = new TIntermSwizzle(position, swizzleOffsetXY);
TVector<int> swizzleOffsetW;
swizzleOffsetW.push_back(3);
TIntermSwizzle *positionW = new TIntermSwizzle(position->deepCopy(), swizzleOffsetW);
TIntermBinary *positionNDC = new TIntermBinary(EOpDiv, positionXY, positionW);
// ANGLEPosition * 0.5
TIntermConstantUnion *oneHalf = CreateBasicConstant(0.5f);
TIntermBinary *halfPosition = new TIntermBinary(EOpVectorTimesScalar, positionNDC, oneHalf);
// (ANGLEPosition * 0.5) + 0.5
TIntermBinary *offsetHalfPosition =
new TIntermBinary(EOpAdd, halfPosition, oneHalf->deepCopy());
// ((ANGLEPosition * 0.5) + 0.5) * ANGLEUniforms.viewport.zw
TIntermBinary *scaledPosition = new TIntermBinary(EOpMul, offsetHalfPosition, viewportZW);
// ((ANGLEPosition * 0.5) + 0.5) * ANGLEUniforms.viewport + ANGLEUniforms.viewport.xy
TIntermBinary *windowPosition = new TIntermBinary(EOpAdd, scaledPosition, viewportXY);
// Assign to a temporary "b".
TVariable *bTemp = CreateTempVariable(symbolTable, vec2Type);
TIntermDeclaration *bDecl = CreateTempInitDeclarationNode(bTemp, windowPosition);
// gl_FragCoord.xy
const TVariable *fragCoord = BuiltInVariable::gl_FragCoord();
TIntermSymbol *fragCoordRef = new TIntermSymbol(fragCoord);
TIntermSwizzle *fragCoordXY = new TIntermSwizzle(fragCoordRef, swizzleOffsetXY);
// b - gl_FragCoord.xy
TIntermSymbol *bRef = CreateTempSymbolNode(bTemp);
TIntermBinary *differenceExpr = new TIntermBinary(EOpSub, bRef, fragCoordXY);
// abs(b - gl_FragCoord.xy)
TIntermUnary *baAbs = new TIntermUnary(EOpAbs, differenceExpr, nullptr);
// Assign to a temporary "ba".
TVariable *baTemp = CreateTempVariable(symbolTable, vec2Type);
TIntermDeclaration *baDecl = CreateTempInitDeclarationNode(baTemp, baAbs);
TIntermSymbol *ba = CreateTempSymbolNode(baTemp);
// ba * ba
TIntermBinary *baSq = new TIntermBinary(EOpMul, ba, ba->deepCopy());
// 2.0 * ba * ba
TIntermTyped *two = CreateBasicConstant(2.0f);
TIntermBinary *twoBaSq = new TIntermBinary(EOpVectorTimesScalar, baSq, two);
// Assign to a temporary "ba2".
TVariable *ba2Temp = CreateTempVariable(symbolTable, vec2Type);
TIntermDeclaration *ba2Decl = CreateTempInitDeclarationNode(ba2Temp, twoBaSq);
// Create a swizzle to "ba2.yx".
TVector<int> swizzleOffsetYX;
swizzleOffsetYX.push_back(1);
swizzleOffsetYX.push_back(0);
TIntermSymbol *ba2 = CreateTempSymbolNode(ba2Temp);
TIntermSwizzle *ba2YX = new TIntermSwizzle(ba2, swizzleOffsetYX);
// ba2 + ba2.yx - ba
TIntermBinary *ba2PlusBaYX2 = new TIntermBinary(EOpAdd, ba2->deepCopy(), ba2YX);
TIntermBinary *bpInit = new TIntermBinary(EOpSub, ba2PlusBaYX2, ba->deepCopy());
// Assign to a temporary "bp".
TVariable *bpTemp = CreateTempVariable(symbolTable, vec2Type);
TIntermDeclaration *bpDecl = CreateTempInitDeclarationNode(bpTemp, bpInit);
TIntermSymbol *bp = CreateTempSymbolNode(bpTemp);
// Create a swizzle to "bp.x".
TVector<int> swizzleOffsetX;
swizzleOffsetX.push_back(0);
TIntermSwizzle *bpX = new TIntermSwizzle(bp, swizzleOffsetX);
// Using a small epsilon value ensures that we don't suffer from numerical instability when
// lines are exactly vertical or horizontal.
static constexpr float kEpisilon = 0.00001f;
TIntermConstantUnion *epsilon = CreateBasicConstant(kEpisilon);
// bp.x > epsilon
TIntermBinary *checkX = new TIntermBinary(EOpGreaterThan, bpX, epsilon);
// Create a swizzle to "bp.y".
TVector<int> swizzleOffsetY;
swizzleOffsetY.push_back(1);
TIntermSwizzle *bpY = new TIntermSwizzle(bp->deepCopy(), swizzleOffsetY);
// bp.y > epsilon
TIntermBinary *checkY = new TIntermBinary(EOpGreaterThan, bpY, epsilon->deepCopy());
// (bp.x > epsilon) && (bp.y > epsilon)
TIntermBinary *checkXY = new TIntermBinary(EOpLogicalAnd, checkX, checkY);
// discard
TIntermBranch *discard = new TIntermBranch(EOpKill, nullptr);
TIntermBlock *discardBlock = new TIntermBlock;
discardBlock->appendStatement(discard);
// if ((bp.x > epsilon) && (bp.y > epsilon)) discard;
TIntermIfElse *ifStatement = new TIntermIfElse(checkXY, discardBlock, nullptr);
// Ensure the line raster code runs at the beginning of main().
TIntermFunctionDefinition *main = FindMain(root);
TIntermSequence *mainSequence = main->getBody()->getSequence();
ASSERT(mainSequence);
std::array<TIntermNode *, 6> nodes = {
{bDecl, baDecl, ba2Decl, bpDecl, ifStatement, GenerateEndIf()}};
mainSequence->insert(mainSequence->begin(), nodes.begin(), nodes.end());
// If the shader does not use frag coord, we should insert it inside the ifdef.
if (!usesFragCoord)
{
InsertFragCoordCorrection(root, mainSequence, symbolTable, driverUniforms);
}
mainSequence->insert(mainSequence->begin(), GenerateLineRasterIfDef());
}
} // anonymous namespace } // anonymous namespace
TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec) TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec)
...@@ -438,6 +682,33 @@ void TranslatorVulkan::translate(TIntermBlock *root, ...@@ -438,6 +682,33 @@ void TranslatorVulkan::translate(TIntermBlock *root,
// if it's core profile shaders and they are used. // if it's core profile shaders and they are used.
if (getShaderType() == GL_FRAGMENT_SHADER) if (getShaderType() == GL_FRAGMENT_SHADER)
{ {
bool usesPointCoord = false;
bool usesFragCoord = false;
// Search for the gl_PointCoord usage, if its used, we need to flip the y coordinate.
for (const Varying &inputVarying : inputVaryings)
{
if (!inputVarying.isBuiltIn())
{
continue;
}
if (inputVarying.name == "gl_PointCoord")
{
usesPointCoord = true;
break;
}
if (inputVarying.name == "gl_FragCoord")
{
usesFragCoord = true;
break;
}
}
AddLineSegmentRasterizationEmulation(sink, root, &getSymbolTable(), driverUniforms,
usesFragCoord);
bool hasGLFragColor = false; bool hasGLFragColor = false;
bool hasGLFragData = false; bool hasGLFragData = false;
...@@ -466,41 +737,27 @@ void TranslatorVulkan::translate(TIntermBlock *root, ...@@ -466,41 +737,27 @@ void TranslatorVulkan::translate(TIntermBlock *root,
sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
} }
// Search for the gl_PointCoord usage, if its used, we need to flip the y coordinate. if (usesPointCoord)
for (const Varying &inputVarying : inputVaryings)
{
if (!inputVarying.isBuiltIn())
{
continue;
}
if (inputVarying.name == "gl_PointCoord")
{ {
TIntermBinary *viewportYScale = TIntermBinary *viewportYScale =
CreateDriverUniformRef(driverUniforms, kInviewportYScale); CreateDriverUniformRef(driverUniforms, kNegViewportYScale);
TIntermConstantUnion *pivot = CreateConstantFloat(0.5f); TIntermConstantUnion *pivot = CreateBasicConstant(0.5f);
FlipBuiltinVariable(root, viewportYScale, &getSymbolTable(), FlipBuiltinVariable(root, GetMainSequence(root), viewportYScale, &getSymbolTable(),
BuiltInVariable::gl_PointCoord(), kFlippedPointCoordName, BuiltInVariable::gl_PointCoord(), kFlippedPointCoordName, pivot);
pivot);
break;
} }
if (inputVarying.name == "gl_FragCoord") if (usesFragCoord)
{ {
TIntermBinary *viewportYScale = InsertFragCoordCorrection(root, GetMainSequence(root), &getSymbolTable(),
CreateDriverUniformRef(driverUniforms, kViewportYScale); driverUniforms);
TIntermBinary *pivot =
CreateDriverUniformRef(driverUniforms, kHalfRenderAreaHeight);
FlipBuiltinVariable(root, viewportYScale, &getSymbolTable(),
BuiltInVariable::gl_FragCoord(), kFlippedFragCoordName, pivot);
break;
}
} }
} }
else else
{ {
ASSERT(getShaderType() == GL_VERTEX_SHADER); ASSERT(getShaderType() == GL_VERTEX_SHADER);
AddANGLEPositionVarying(root, &getSymbolTable());
// Append depth range translation to main. // Append depth range translation to main.
AppendVertexShaderDepthCorrectionToMain(root, &getSymbolTable()); AppendVertexShaderDepthCorrectionToMain(root, &getSymbolTable());
} }
......
...@@ -146,6 +146,8 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer) ...@@ -146,6 +146,8 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
mDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyIndexBuffer; mDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyIndexBuffer;
mDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] = &ContextVk::handleDirtyDriverUniforms; mDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] = &ContextVk::handleDirtyDriverUniforms;
mDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets; mDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets;
mDirtyBits = mNewCommandBufferDirtyBits;
} }
ContextVk::~ContextVk() = default; ContextVk::~ContextVk() = default;
......
...@@ -288,7 +288,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -288,7 +288,7 @@ class ContextVk : public ContextImpl, public vk::Context
float halfRenderAreaHeight; float halfRenderAreaHeight;
float viewportYScale; float viewportYScale;
float invViewportYScale; float negViewportYScale;
float padding; float padding;
// We'll use x, y, z for near / far / diff respectively. // We'll use x, y, z for near / far / diff respectively.
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <array> #include <array>
#include "common/FixedVector.h"
#include "common/string_utils.h" #include "common/string_utils.h"
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/Caps.h" #include "libANGLE/Caps.h"
...@@ -25,14 +26,17 @@ ...@@ -25,14 +26,17 @@
namespace rx namespace rx
{ {
namespace namespace
{ {
constexpr char kQualifierMarkerBegin[] = "@@ QUALIFIER-"; constexpr char kQualifierMarkerBegin[] = "@@ QUALIFIER-";
constexpr char kLayoutMarkerBegin[] = "@@ LAYOUT-"; constexpr char kLayoutMarkerBegin[] = "@@ LAYOUT-";
constexpr char kMarkerEnd[] = " @@"; constexpr char kMarkerEnd[] = " @@";
constexpr char kUniformQualifier[] = "uniform"; constexpr char kUniformQualifier[] = "uniform";
constexpr char kVersionDefine[] = "#version 450 core\n";
constexpr char kLineRasterDefine[] = R"(#version 450 core
#define ANGLE_ENABLE_LINE_SEGMENT_RASTERIZATION
)";
void GetBuiltInResourcesFromCaps(const gl::Caps &caps, TBuiltInResource *outBuiltInResources) void GetBuiltInResourcesFromCaps(const gl::Caps &caps, TBuiltInResource *outBuiltInResources)
{ {
...@@ -203,15 +207,13 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState, ...@@ -203,15 +207,13 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
// Bind the default uniforms for vertex and fragment shaders. // Bind the default uniforms for vertex and fragment shaders.
// See corresponding code in OutputVulkanGLSL.cpp. // See corresponding code in OutputVulkanGLSL.cpp.
std::stringstream searchStringBuilder; std::string uniformsSearchString("@@ DEFAULT-UNIFORMS-SET-BINDING @@");
searchStringBuilder << "@@ DEFAULT-UNIFORMS-SET-BINDING @@";
std::string searchString = searchStringBuilder.str();
std::string vertexDefaultUniformsBinding = "set = 0, binding = 0"; std::string vertexDefaultUniformsBinding = "set = 0, binding = 0";
std::string fragmentDefaultUniformsBinding = "set = 0, binding = 1"; std::string fragmentDefaultUniformsBinding = "set = 0, binding = 1";
angle::ReplaceSubstring(&vertexSource, searchString, vertexDefaultUniformsBinding); angle::ReplaceSubstring(&vertexSource, uniformsSearchString, vertexDefaultUniformsBinding);
angle::ReplaceSubstring(&fragmentSource, searchString, fragmentDefaultUniformsBinding); angle::ReplaceSubstring(&fragmentSource, uniformsSearchString, fragmentDefaultUniformsBinding);
// Assign textures to a descriptor set and binding. // Assign textures to a descriptor set and binding.
int textureCount = 0; int textureCount = 0;
...@@ -279,6 +281,18 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState, ...@@ -279,6 +281,18 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
InsertQualifierSpecifierString(&vertexSource, kDriverBlockName, kUniformQualifier); InsertQualifierSpecifierString(&vertexSource, kDriverBlockName, kUniformQualifier);
InsertQualifierSpecifierString(&fragmentSource, kDriverBlockName, kUniformQualifier); InsertQualifierSpecifierString(&fragmentSource, kDriverBlockName, kUniformQualifier);
// Substitute layout and qualifier strings for the position varying. Use the first free
// varying register after the packed varyings.
constexpr char kVaryingName[] = "ANGLEPosition";
std::stringstream layoutStream;
layoutStream << "location = " << (resources.varyingPacking.getMaxSemanticIndex() + 1);
const std::string layout = layoutStream.str();
InsertLayoutSpecifierString(&vertexSource, kVaryingName, layout);
InsertLayoutSpecifierString(&fragmentSource, kVaryingName, layout);
InsertQualifierSpecifierString(&vertexSource, kVaryingName, "out");
InsertQualifierSpecifierString(&fragmentSource, kVaryingName, "in");
*vertexSourceOut = vertexSource; *vertexSourceOut = vertexSource;
*fragmentSourceOut = fragmentSource; *fragmentSourceOut = fragmentSource;
} }
...@@ -286,6 +300,40 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState, ...@@ -286,6 +300,40 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
// static // static
angle::Result GlslangWrapper::GetShaderCode(vk::Context *context, angle::Result GlslangWrapper::GetShaderCode(vk::Context *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation,
const std::string &vertexSource,
const std::string &fragmentSource,
std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut)
{
if (enableLineRasterEmulation)
{
std::string patchedVertexSource = vertexSource;
std::string patchedFragmentSource = fragmentSource;
// #defines must come after the #version directive.
ANGLE_VK_CHECK(
context,
angle::ReplaceSubstring(&patchedVertexSource, kVersionDefine, kLineRasterDefine),
VK_ERROR_INVALID_SHADER_NV);
ANGLE_VK_CHECK(
context,
angle::ReplaceSubstring(&patchedFragmentSource, kVersionDefine, kLineRasterDefine),
VK_ERROR_INVALID_SHADER_NV);
return GetShaderCodeImpl(context, glCaps, patchedVertexSource, patchedFragmentSource,
vertexCodeOut, fragmentCodeOut);
}
else
{
return GetShaderCodeImpl(context, glCaps, vertexSource, fragmentSource, vertexCodeOut,
fragmentCodeOut);
}
}
// static
angle::Result GlslangWrapper::GetShaderCodeImpl(vk::Context *context,
const gl::Caps &glCaps,
const std::string &vertexSource, const std::string &vertexSource,
const std::string &fragmentSource, const std::string &fragmentSource,
std::vector<uint32_t> *vertexCodeOut, std::vector<uint32_t> *vertexCodeOut,
......
...@@ -29,12 +29,20 @@ class GlslangWrapper ...@@ -29,12 +29,20 @@ class GlslangWrapper
static angle::Result GetShaderCode(vk::Context *context, static angle::Result GetShaderCode(vk::Context *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation,
const std::string &vertexSource, const std::string &vertexSource,
const std::string &fragmentSource, const std::string &fragmentSource,
std::vector<uint32_t> *vertexCodeOut, std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut); std::vector<uint32_t> *fragmentCodeOut);
};
private:
static angle::Result GetShaderCodeImpl(vk::Context *context,
const gl::Caps &glCaps,
const std::string &vertexSource,
const std::string &fragmentSource,
std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut);
};
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_GLSLANG_WRAPPER_H_ #endif // LIBANGLE_RENDERER_VULKAN_GLSLANG_WRAPPER_H_
...@@ -128,6 +128,12 @@ angle::Result SyncDefaultUniformBlock(ContextVk *contextVk, ...@@ -128,6 +128,12 @@ angle::Result SyncDefaultUniformBlock(ContextVk *contextVk,
ANGLE_TRY(dynamicBuffer->flush(contextVk)); ANGLE_TRY(dynamicBuffer->flush(contextVk));
return angle::Result::Continue(); return angle::Result::Continue();
} }
bool UseLineRaster(const ContextVk *contextVk, const gl::DrawCallParams &drawCallParams)
{
return contextVk->getFeatures().basicGLLineRasterization &&
gl::IsLineMode(drawCallParams.mode());
}
} // anonymous namespace } // anonymous namespace
// ProgramVk::ShaderInfo implementation. // ProgramVk::ShaderInfo implementation.
...@@ -141,6 +147,7 @@ angle::Result ProgramVk::ShaderInfo::getShaders( ...@@ -141,6 +147,7 @@ angle::Result ProgramVk::ShaderInfo::getShaders(
ContextVk *contextVk, ContextVk *contextVk,
const std::string &vertexSource, const std::string &vertexSource,
const std::string &fragmentSource, const std::string &fragmentSource,
bool enableLineRasterEmulation,
const vk::ShaderAndSerial **vertexShaderAndSerialOut, const vk::ShaderAndSerial **vertexShaderAndSerialOut,
const vk::ShaderAndSerial **fragmentShaderAndSerialOut) const vk::ShaderAndSerial **fragmentShaderAndSerialOut)
{ {
...@@ -148,7 +155,8 @@ angle::Result ProgramVk::ShaderInfo::getShaders( ...@@ -148,7 +155,8 @@ angle::Result ProgramVk::ShaderInfo::getShaders(
{ {
std::vector<uint32_t> vertexCode; std::vector<uint32_t> vertexCode;
std::vector<uint32_t> fragmentCode; std::vector<uint32_t> fragmentCode;
ANGLE_TRY(GlslangWrapper::GetShaderCode(contextVk, contextVk->getCaps(), vertexSource, ANGLE_TRY(GlslangWrapper::GetShaderCode(contextVk, contextVk->getCaps(),
enableLineRasterEmulation, vertexSource,
fragmentSource, &vertexCode, &fragmentCode)); fragmentSource, &vertexCode, &fragmentCode));
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mVertexShaderAndSerial, vertexCode.data(), ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mVertexShaderAndSerial, vertexCode.data(),
...@@ -211,8 +219,8 @@ angle::Result ProgramVk::reset(ContextVk *contextVk) ...@@ -211,8 +219,8 @@ angle::Result ProgramVk::reset(ContextVk *contextVk)
uniformBlock.storage.release(renderer); uniformBlock.storage.release(renderer);
} }
// TODO(jmadill): Line rasterization emulation shaders. http://anglebug.com/2598
mDefaultShaderInfo.destroy(device); mDefaultShaderInfo.destroy(device);
mLineRasterShaderInfo.destroy(device);
Serial currentSerial = renderer->getCurrentQueueSerial(); Serial currentSerial = renderer->getCurrentQueueSerial();
renderer->releaseObject(currentSerial, &mEmptyUniformBlockStorage.memory); renderer->releaseObject(currentSerial, &mEmptyUniformBlockStorage.memory);
...@@ -732,10 +740,20 @@ angle::Result ProgramVk::initShaders(ContextVk *contextVk, ...@@ -732,10 +740,20 @@ angle::Result ProgramVk::initShaders(ContextVk *contextVk,
const vk::ShaderAndSerial **fragmentShaderAndSerialOut, const vk::ShaderAndSerial **fragmentShaderAndSerialOut,
const vk::PipelineLayout **pipelineLayoutOut) const vk::PipelineLayout **pipelineLayoutOut)
{ {
// TODO(jmadill): Line rasterization emulation shaders. http://anglebug.com/2598 if (UseLineRaster(contextVk, drawCallParams))
ANGLE_TRY(mDefaultShaderInfo.getShaders(contextVk, mVertexSource, mFragmentSource, {
vertexShaderAndSerialOut, fragmentShaderAndSerialOut)); ANGLE_TRY(mLineRasterShaderInfo.getShaders(contextVk, mVertexSource, mFragmentSource, true,
vertexShaderAndSerialOut,
fragmentShaderAndSerialOut));
ASSERT(mLineRasterShaderInfo.valid());
}
else
{
ANGLE_TRY(mDefaultShaderInfo.getShaders(contextVk, mVertexSource, mFragmentSource, false,
vertexShaderAndSerialOut,
fragmentShaderAndSerialOut));
ASSERT(mDefaultShaderInfo.valid()); ASSERT(mDefaultShaderInfo.valid());
}
*pipelineLayoutOut = &mPipelineLayout.get(); *pipelineLayoutOut = &mPipelineLayout.get();
...@@ -925,7 +943,6 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk, ...@@ -925,7 +943,6 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk,
const gl::DrawCallParams &drawCallParams, const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
{ {
// TODO(jmadill): Line rasterization emulation shaders. http://anglebug.com/2598
// Can probably use better dirty bits here. // Can probably use better dirty bits here.
if (mUsedDescriptorSetRange.empty()) if (mUsedDescriptorSetRange.empty())
......
...@@ -183,6 +183,7 @@ class ProgramVk : public ProgramImpl ...@@ -183,6 +183,7 @@ class ProgramVk : public ProgramImpl
angle::Result getShaders(ContextVk *contextVk, angle::Result getShaders(ContextVk *contextVk,
const std::string &vertexSource, const std::string &vertexSource,
const std::string &fragmentSource, const std::string &fragmentSource,
bool enableLineRasterEmulation,
const vk::ShaderAndSerial **vertexShaderAndSerialOut, const vk::ShaderAndSerial **vertexShaderAndSerialOut,
const vk::ShaderAndSerial **fragmentShaderAndSerialOut); const vk::ShaderAndSerial **fragmentShaderAndSerialOut);
void destroy(VkDevice device); void destroy(VkDevice device);
...@@ -193,8 +194,8 @@ class ProgramVk : public ProgramImpl ...@@ -193,8 +194,8 @@ class ProgramVk : public ProgramImpl
vk::ShaderAndSerial mFragmentShaderAndSerial; vk::ShaderAndSerial mFragmentShaderAndSerial;
}; };
// TODO(jmadill): Line rasterization emulation shaders. http://anglebug.com/2598
ShaderInfo mDefaultShaderInfo; ShaderInfo mDefaultShaderInfo;
ShaderInfo mLineRasterShaderInfo;
// We keep the translated linked shader sources to use with shader draw call patching. // We keep the translated linked shader sources to use with shader draw call patching.
std::string mVertexSource; std::string mVertexSource;
......
...@@ -683,8 +683,13 @@ std::string RendererVk::getRendererDescription() const ...@@ -683,8 +683,13 @@ std::string RendererVk::getRendererDescription() const
void RendererVk::initFeatures() void RendererVk::initFeatures()
{ {
// Use OpenGL line rasterization rules by default. // Use OpenGL line rasterization rules by default.
// TODO(jmadill): Fix Android support. http://anglebug.com/2830
#if defined(ANGLE_PLATFORM_ANDROID)
mFeatures.basicGLLineRasterization = false;
#else
mFeatures.basicGLLineRasterization = true; mFeatures.basicGLLineRasterization = true;
#endif // defined(ANGLE_PLATFORM_ANDROID)
// TODO(lucferron): Currently disabled on Intel only since many tests are failing and need // TODO(lucferron): Currently disabled on Intel only since many tests are failing and need
// investigation. http://anglebug.com/2728 // investigation. http://anglebug.com/2728
......
...@@ -183,6 +183,19 @@ ...@@ -183,6 +183,19 @@
2630 GLES ANDROID : dEQP-GLES2.functional.shaders.struct.uniform.sampler_in_array_function_arg_* = FAIL 2630 GLES ANDROID : dEQP-GLES2.functional.shaders.struct.uniform.sampler_in_array_function_arg_* = FAIL
2630 GLES ANDROID : dEQP-GLES2.functional.shaders.struct.uniform.sampler_in_function_arg_* = FAIL 2630 GLES ANDROID : dEQP-GLES2.functional.shaders.struct.uniform.sampler_in_function_arg_* = FAIL
2567 GLES ANDROID : dEQP-GLES2.functional.fbo.completeness.renderable.texture.depth.red_unsigned_byte = FAIL
2567 GLES ANDROID : dEQP-GLES2.functional.fbo.completeness.renderable.texture.depth.rg_unsigned_byte = FAIL
2567 GLES ANDROID : dEQP-GLES2.functional.fbo.completeness.renderable.texture.stencil.red_unsigned_byte = FAIL
2567 GLES ANDROID : dEQP-GLES2.functional.fbo.completeness.renderable.texture.stencil.rg_unsigned_byte = FAIL
// Windows Linux and Mac failures
1028 WIN LINUX MAC : dEQP-GLES2.functional.fbo.completeness.renderable.texture.color0.srgb8 = FAIL
1028 WIN LINUX MAC : dEQP-GLES2.functional.fbo.completeness.renderable.texture.stencil.srgb8 = FAIL
1028 WIN LINUX MAC : dEQP-GLES2.functional.fbo.completeness.renderable.texture.depth.srgb8 = FAIL
// General Vulkan failures
// Nothing here!
// Android Vulkan backend only failures // Android Vulkan backend only failures
2549 VULKAN ANDROID : dEQP-GLES2.functional.fragment_ops.depth_stencil.stencil* = SKIP 2549 VULKAN ANDROID : dEQP-GLES2.functional.fragment_ops.depth_stencil.stencil* = SKIP
2606 VULKAN ANDROID : dEQP-GLES2.functional.debug_marker.random = SKIP 2606 VULKAN ANDROID : dEQP-GLES2.functional.debug_marker.random = SKIP
...@@ -190,23 +203,15 @@ ...@@ -190,23 +203,15 @@
2609 VULKAN ANDROID : dEQP-GLES2.functional.texture.mipmap.cube.generate.* = SKIP 2609 VULKAN ANDROID : dEQP-GLES2.functional.texture.mipmap.cube.generate.* = SKIP
2405 VULKAN ANDROID : dEQP-GLES2.functional.draw.random.42 = SKIP 2405 VULKAN ANDROID : dEQP-GLES2.functional.draw.random.42 = SKIP
2405 VULKAN ANDROID : dEQP-GLES2.functional.draw.random.59 = SKIP 2405 VULKAN ANDROID : dEQP-GLES2.functional.draw.random.59 = SKIP
2830 VULKAN ANDROID : dEQP-GLES2.functional.rasterization.primitives.line* = SKIP
// Fails on Nexus 5x only. TODO(jmadill): Remove suppression when possible. http://anglebug.com/2791 // Fails on Nexus 5x only. TODO(jmadill): Remove suppression when possible. http://anglebug.com/2791
2791 VULKAN ANDROID : dEQP-GLES2.functional.clipping.* = SKIP 2791 VULKAN ANDROID : dEQP-GLES2.functional.clipping.* = SKIP
2599 VULKAN ANDROID : dEQP-GLES2.functional.rasterization.limits.points = FAIL 2599 VULKAN ANDROID : dEQP-GLES2.functional.rasterization.limits.points = FAIL
2567 GLES ANDROID : dEQP-GLES2.functional.fbo.completeness.renderable.texture.depth.red_unsigned_byte = FAIL // Failing on the Pixel 2.
2567 GLES ANDROID : dEQP-GLES2.functional.fbo.completeness.renderable.texture.depth.rg_unsigned_byte = FAIL 2727 VULKAN ANDROID : dEQP-GLES2.functional.shaders.builtin_variable.pointcoord = FAIL
2567 GLES ANDROID : dEQP-GLES2.functional.fbo.completeness.renderable.texture.stencil.red_unsigned_byte = FAIL 2808 VULKAN ANDROID : dEQP-GLES2.functional.shaders.builtin_variable.fragcoord_w = FAIL
2567 GLES ANDROID : dEQP-GLES2.functional.fbo.completeness.renderable.texture.stencil.rg_unsigned_byte = FAIL
// Windows Linux and Mac failures
1028 WIN LINUX MAC : dEQP-GLES2.functional.fbo.completeness.renderable.texture.color0.srgb8 = FAIL
1028 WIN LINUX MAC : dEQP-GLES2.functional.fbo.completeness.renderable.texture.stencil.srgb8 = FAIL
1028 WIN LINUX MAC : dEQP-GLES2.functional.fbo.completeness.renderable.texture.depth.srgb8 = FAIL
// Vulkan failures
2598 VULKAN : dEQP-GLES2.functional.rasterization.primitives.line* = SKIP
// Vulkan AMD Windows specific failures // Vulkan AMD Windows specific failures
2602 VULKAN WIN AMD : dEQP-GLES2.functional.buffer.write.* = SKIP 2602 VULKAN WIN AMD : dEQP-GLES2.functional.buffer.write.* = SKIP
...@@ -243,6 +248,5 @@ ...@@ -243,6 +248,5 @@
2405 VULKAN WIN AMD : dEQP-GLES2.functional.vertex_arrays.single_attribute.usages.buffer_0_32_float* = SKIP 2405 VULKAN WIN AMD : dEQP-GLES2.functional.vertex_arrays.single_attribute.usages.buffer_0_32_float* = SKIP
2405 VULKAN WIN AMD : dEQP-GLES2.functional.vertex_arrays.single_attribute.usages.buffer_0_32_short* = SKIP 2405 VULKAN WIN AMD : dEQP-GLES2.functional.vertex_arrays.single_attribute.usages.buffer_0_32_short* = SKIP
// Failing on the Pixel 2. // Fails after OpenGL line rasterization rules implementation. Possibly a bug in FragCoord.
2727 VULKAN ANDROID : dEQP-GLES2.functional.shaders.builtin_variable.pointcoord = FAIL 2809 VULKAN WIN AMD : dEQP-GLES2.functional.clipping.line.long_line_clip = FAIL
2808 VULKAN ANDROID : dEQP-GLES2.functional.shaders.builtin_variable.fragcoord_w = FAIL
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// //
#include "test_utils/ANGLETest.h" #include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle; using namespace angle;
...@@ -241,6 +242,86 @@ TEST_P(ViewportTest, TripleWindowOffCenter) ...@@ -241,6 +242,86 @@ TEST_P(ViewportTest, TripleWindowOffCenter)
runScissoredTest(); runScissoredTest();
} }
// Test line rendering with a non-standard viewport.
TEST_P(ViewportTest, DrawLineWithViewport)
{
// We assume in the test the width and height are equal and we are tracing
// the line from bottom left to top right. Verify that all pixels along that line
// have been traced with green.
ASSERT_EQ(getWindowWidth(), getWindowHeight());
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
glUseProgram(program);
std::vector<Vector3> vertices = {{-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}};
const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
ASSERT_NE(-1, positionLocation);
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
// Set the viewport.
GLint quarterWidth = getWindowWidth() / 4;
GLint quarterHeight = getWindowHeight() / 4;
glViewport(quarterWidth, quarterHeight, quarterWidth, quarterHeight);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(vertices.size()));
glDisableVertexAttribArray(positionLocation);
ASSERT_GL_NO_ERROR();
for (GLint x = quarterWidth; x < getWindowWidth() / 2; x++)
{
EXPECT_PIXEL_COLOR_EQ(x, x, GLColor::green);
}
}
// Test line rendering with an overly large viewport.
TEST_P(ViewportTest, DrawLineWithLargeViewport)
{
// We assume in the test the width and height are equal and we are tracing
// the line from bottom left to top right. Verify that all pixels along that line
// have been traced with green.
ASSERT_EQ(getWindowWidth(), getWindowHeight());
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
glUseProgram(program);
std::vector<Vector3> vertices = {{-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}};
const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
ASSERT_NE(-1, positionLocation);
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
// Set the viewport.
glViewport(0, 0, getWindowWidth() * 2, getWindowHeight() * 2);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(vertices.size()));
glDisableVertexAttribArray(positionLocation);
ASSERT_GL_NO_ERROR();
for (GLint x = 0; x < getWindowWidth(); x++)
{
EXPECT_PIXEL_COLOR_EQ(x, x, GLColor::green);
}
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
// D3D11 Feature Level 9 and D3D9 emulate large and negative viewports in the vertex shader. We should test both of these as well as D3D11 Feature Level 10_0+. // D3D11 Feature Level 9 and D3D9 emulate large and negative viewports in the vertex shader. We should test both of these as well as D3D11 Feature Level 10_0+.
ANGLE_INSTANTIATE_TEST(ViewportTest, ANGLE_INSTANTIATE_TEST(ViewportTest,
......
...@@ -364,6 +364,17 @@ void main() ...@@ -364,6 +364,17 @@ void main()
})"; })";
} }
// A shader that fills with 100% opaque green.
const char *Green()
{
return R"(precision mediump float;
void main()
{
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
})";
}
// A shader that fills with 100% opaque blue. // A shader that fills with 100% opaque blue.
const char *Blue() const char *Blue()
{ {
......
...@@ -83,6 +83,9 @@ ANGLE_EXPORT const char *UniformColor(); ...@@ -83,6 +83,9 @@ ANGLE_EXPORT const char *UniformColor();
// A shader that fills with 100% opaque red. // A shader that fills with 100% opaque red.
ANGLE_EXPORT const char *Red(); ANGLE_EXPORT const char *Red();
// A shader that fills with 100% opaque green.
ANGLE_EXPORT const char *Green();
// A shader that fills with 100% opaque blue. // A shader that fills with 100% opaque blue.
ANGLE_EXPORT const char *Blue(); ANGLE_EXPORT const char *Blue();
......
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