Commit 4cc89e2b by Jiawei Shao Committed by Commit Bot

ES31: Enable 'location' layout qualifier on shader interfaces in compiler

This patch enables 'location' layout qualifier for vertex outputs and fragment shader inputs when the shader version is 3.1 in ANGLE GLSL compiler and adds the check on location conflicts for these varyings. According to GLSL ES 3.1 SPEC (Chapter 4.4.1 and Chapter 4.4.2), 'location' layout qualifier is allowed on both inputs and outputs of vertex and fragment shaders. 'location' layout qualifier on shader interfaces is only valid on shaders whose version is 3.1 and above. According to GLSL ES 3.0 SPEC, vertex shader cannot have output layout qualifiers (Chapter 4.3.8.2) and fragment shader cannot have input layout qualifiers (Chapter 4.3.8.1). The 'location' qualifier on varyings is used in the shader interface matching defined in OpenGL ES 3.1. (OpenGL ES 3.1 SPEC Chapter 7.4.1). This new link rule will be added to Program.cpp in another patch. For the OpenGL ES 3.1 extension GL_OES_geometry_shader, according to GL_OES_shader_io_blocks SPEC (Chapter 4.4.1 and Chapter 4.4.2), 'location' layout qualifier is both valid on geometry shader inputs and outputs. This feature will be implemented together with other rules on geometry shader inputs and outputs. BUG=angleproject:2144 TEST=angle_unittests Change-Id: I62d85f7144c177448321c2db36ed7aaeaa1fb205 Reviewed-on: https://chromium-review.googlesource.com/645366 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 729b2c6e
......@@ -96,7 +96,8 @@ struct ShaderVariable
protected:
bool isSameVariableAtLinkTime(const ShaderVariable &other,
bool matchPrecision) const;
bool matchPrecision,
bool matchName) const;
bool operator==(const ShaderVariable &other) const;
bool operator!=(const ShaderVariable &other) const
......@@ -183,7 +184,7 @@ struct InterfaceBlockField : public ShaderVariable
bool isRowMajorLayout;
};
struct Varying : public ShaderVariable
struct Varying : public VariableWithLocation
{
Varying();
~Varying();
......
......@@ -154,6 +154,8 @@
'compiler/translator/ValidateOutputs.h',
'compiler/translator/ValidateSwitch.cpp',
'compiler/translator/ValidateSwitch.h',
'compiler/translator/ValidateVaryingLocations.cpp',
'compiler/translator/ValidateVaryingLocations.h',
'compiler/translator/VariablePacker.cpp',
'compiler/translator/VariablePacker.h',
'compiler/translator/blocklayout.cpp',
......
......@@ -609,6 +609,7 @@ Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable)
Varying varying;
setCommonVariableProperties(type, variable.getName(), &varying);
varying.location = type.getLayoutQualifier().location;
switch (type.getQualifier())
{
......
......@@ -40,6 +40,7 @@
#include "compiler/translator/ValidateLimitations.h"
#include "compiler/translator/ValidateMaxParameters.h"
#include "compiler/translator/ValidateOutputs.h"
#include "compiler/translator/ValidateVaryingLocations.h"
#include "compiler/translator/VariablePacker.h"
#include "third_party/compiler/ArrayBoundsClamper.h"
......@@ -396,6 +397,11 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success)
PruneEmptyDeclarations(root);
if (success && shaderVersion >= 310)
{
success = ValidateVaryingLocations(root, &mDiagnostics);
}
if (success && shaderVersion >= 300 && shaderType == GL_FRAGMENT_SHADER)
{
success = ValidateOutputs(root, getExtensionBehavior(), compileResources.MaxDrawBuffers,
......
......@@ -63,7 +63,8 @@ bool NeedsToWriteLayoutQualifier(const TType &type)
const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
IsVarying(type.getQualifier())) &&
layoutQualifier.location >= 0)
{
return true;
......@@ -206,7 +207,8 @@ void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
CommaSeparatedListItemPrefixGenerator listItemPrefix;
if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
IsVarying(type.getQualifier()))
{
if (layoutQualifier.location >= 0)
{
......
......@@ -901,7 +901,7 @@ void TParseContext::checkLocationIsNotSpecified(const TSourceLoc &location,
if (mShaderVersion >= 310)
{
errorMsg =
"invalid layout qualifier: only valid on program inputs, outputs, and uniforms";
"invalid layout qualifier: only valid on shader inputs, outputs, and uniforms";
}
error(location, errorMsg, "location");
}
......@@ -1221,9 +1221,9 @@ void TParseContext::declarationQualifierErrorCheck(const sh::TQualifier qualifie
}
bool canHaveLocation = qualifier == EvqVertexIn || qualifier == EvqFragmentOut;
if (mShaderVersion >= 310 && qualifier == EvqUniform)
if (mShaderVersion >= 310)
{
canHaveLocation = true;
canHaveLocation = canHaveLocation || qualifier == EvqUniform || IsVarying(qualifier);
// We're not checking whether the uniform location is in range here since that depends on
// the type of the variable.
// The type can only be fully determined for non-empty declarations.
......
......@@ -156,22 +156,27 @@ bool ShaderVariable::findInfoByMappedName(const std::string &mappedFullName,
}
bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other,
bool matchPrecision) const
bool matchPrecision,
bool matchName) const
{
if (type != other.type)
return false;
if (matchPrecision && precision != other.precision)
return false;
if (name != other.name)
if (matchName && name != other.name)
return false;
ASSERT(mappedName == other.mappedName);
ASSERT(!matchName || mappedName == other.mappedName);
if (arraySize != other.arraySize)
return false;
if (fields.size() != other.fields.size())
return false;
// [OpenGL ES 3.1 SPEC Chapter 7.4.1]
// Variables declared as structures are considered to match in type if and only if structure
// members match in name, type, qualification, and declaration order.
for (size_t ii = 0; ii < fields.size(); ++ii)
{
if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision))
if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision, true))
{
return false;
}
......@@ -224,7 +229,7 @@ bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const
{
return false;
}
return VariableWithLocation::isSameVariableAtLinkTime(other, true);
return VariableWithLocation::isSameVariableAtLinkTime(other, true, true);
}
VariableWithLocation::VariableWithLocation() : location(-1)
......@@ -326,7 +331,7 @@ bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const
bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime(
const InterfaceBlockField &other) const
{
return (ShaderVariable::isSameVariableAtLinkTime(other, true) &&
return (ShaderVariable::isSameVariableAtLinkTime(other, true, true) &&
isRowMajorLayout == other.isRowMajorLayout);
}
......@@ -339,13 +344,15 @@ Varying::~Varying()
}
Varying::Varying(const Varying &other)
: ShaderVariable(other), interpolation(other.interpolation), isInvariant(other.isInvariant)
: VariableWithLocation(other),
interpolation(other.interpolation),
isInvariant(other.isInvariant)
{
}
Varying &Varying::operator=(const Varying &other)
{
ShaderVariable::operator=(other);
VariableWithLocation::operator=(other);
interpolation = other.interpolation;
isInvariant = other.isInvariant;
return *this;
......@@ -353,7 +360,7 @@ Varying &Varying::operator=(const Varying &other)
bool Varying::operator==(const Varying &other) const
{
return (ShaderVariable::operator==(other) && interpolation == other.interpolation &&
return (VariableWithLocation::operator==(other) && interpolation == other.interpolation &&
isInvariant == other.isInvariant);
}
......@@ -364,9 +371,11 @@ bool Varying::isSameVaryingAtLinkTime(const Varying &other) const
bool Varying::isSameVaryingAtLinkTime(const Varying &other, int shaderVersion) const
{
return (ShaderVariable::isSameVariableAtLinkTime(other, false) &&
return (ShaderVariable::isSameVariableAtLinkTime(other, false, false) &&
InterpolationTypesMatch(interpolation, other.interpolation) &&
(shaderVersion >= 300 || isInvariant == other.isInvariant));
(shaderVersion >= 300 || isInvariant == other.isInvariant) &&
(location == other.location) &&
(name == other.name || (shaderVersion >= 310 && location >= 0)));
}
InterfaceBlock::InterfaceBlock()
......
//
// Copyright (c) 2002-2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// The ValidateVaryingLocations function checks if there exists location conflicts on shader
// varyings.
//
#include "ValidateVaryingLocations.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/util.h"
namespace sh
{
namespace
{
void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
{
diagnostics->error(symbol.getLine(), reason, symbol.getSymbol().c_str());
}
int GetLocationCount(const TIntermSymbol *varying)
{
const auto &varyingType = varying->getType();
if (varyingType.getStruct() != nullptr)
{
ASSERT(!varyingType.isArray());
int totalLocation = 0;
for (const auto *field : varyingType.getStruct()->fields())
{
const auto *fieldType = field->type();
ASSERT(fieldType->getStruct() == nullptr && !fieldType->isArray());
totalLocation += fieldType->getSecondarySize();
}
return totalLocation;
}
else
{
return varyingType.getSecondarySize() * static_cast<int>(varyingType.getArraySizeProduct());
}
}
using VaryingVector = std::vector<const TIntermSymbol *>;
void ValidateShaderInterface(TDiagnostics *diagnostics, VaryingVector &varyingVector)
{
// Location conflicts can only happen when there are two or more varyings in varyingVector.
if (varyingVector.size() <= 1)
{
return;
}
std::map<int, const TIntermSymbol *> locationMap;
for (const TIntermSymbol *varying : varyingVector)
{
const int location = varying->getType().getLayoutQualifier().location;
ASSERT(location >= 0);
const int elementCount = GetLocationCount(varying);
for (int elementIndex = 0; elementIndex < elementCount; ++elementIndex)
{
const int offsetLocation = location + elementIndex;
if (locationMap.find(offsetLocation) != locationMap.end())
{
std::stringstream strstr;
strstr << "'" << varying->getSymbol()
<< "' conflicting location with previously defined '"
<< locationMap[offsetLocation]->getSymbol() << "'";
error(*varying, strstr.str().c_str(), diagnostics);
}
else
{
locationMap[offsetLocation] = varying;
}
}
}
}
class ValidateVaryingLocationsTraverser : public TIntermTraverser
{
public:
ValidateVaryingLocationsTraverser();
void validate(TDiagnostics *diagnostics);
private:
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
VaryingVector mInputVaryingsWithLocation;
VaryingVector mOutputVaryingsWithLocation;
};
ValidateVaryingLocationsTraverser::ValidateVaryingLocationsTraverser()
: TIntermTraverser(true, false, false)
{
}
bool ValidateVaryingLocationsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
{
const TIntermSequence &sequence = *(node->getSequence());
ASSERT(!sequence.empty());
const TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
if (symbol == nullptr)
{
return false;
}
// Collect varyings that have explicit 'location' qualifiers.
const TQualifier qualifier = symbol->getQualifier();
if (symbol->getType().getLayoutQualifier().location != -1)
{
if (IsVaryingIn(qualifier))
{
mInputVaryingsWithLocation.push_back(symbol);
}
else if (IsVaryingOut(qualifier))
{
mOutputVaryingsWithLocation.push_back(symbol);
}
}
return false;
}
bool ValidateVaryingLocationsTraverser::visitFunctionDefinition(Visit visit,
TIntermFunctionDefinition *node)
{
// We stop traversing function definitions because varyings cannot be defined in a function.
return false;
}
void ValidateVaryingLocationsTraverser::validate(TDiagnostics *diagnostics)
{
ASSERT(diagnostics);
ValidateShaderInterface(diagnostics, mInputVaryingsWithLocation);
ValidateShaderInterface(diagnostics, mOutputVaryingsWithLocation);
}
} // anonymous namespace
bool ValidateVaryingLocations(TIntermBlock *root, TDiagnostics *diagnostics)
{
ValidateVaryingLocationsTraverser varyingValidator;
root->traverse(&varyingValidator);
int numErrorsBefore = diagnostics->numErrors();
varyingValidator.validate(diagnostics);
return (diagnostics->numErrors() == numErrorsBefore);
}
} // namespace sh
\ No newline at end of file
//
// Copyright (c) 2002-2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// The ValidateVaryingLocations function checks if there exists location conflicts on shader
// varyings.
//
#ifndef COMPILER_TRANSLATOR_VALIDATEVARYINGLOCATIONS_H_
#define COMPILER_TRANSLATOR_VALIDATEVARYINGLOCATIONS_H_
namespace sh
{
class TIntermBlock;
class TDiagnostics;
bool ValidateVaryingLocations(TIntermBlock *root, TDiagnostics *diagnostics);
} // namespace sh
#endif
\ No newline at end of file
......@@ -44,7 +44,7 @@ class CollectVariablesTest : public testing::Test
initTranslator(resources);
}
void initTranslator(const ShBuiltInResources &resources)
virtual void initTranslator(const ShBuiltInResources &resources)
{
mTranslator.reset(
new TranslatorGLSL(mShaderType, SH_GLES3_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));
......@@ -141,10 +141,25 @@ class CollectFragmentVariablesTest : public CollectVariablesTest
CollectFragmentVariablesTest() : CollectVariablesTest(GL_FRAGMENT_SHADER) {}
};
class CollectVariablesOESGeometryShaderTest : public CollectVariablesTest
class CollectVariablesTestES31 : public CollectVariablesTest
{
public:
CollectVariablesTestES31(sh::GLenum shaderType) : CollectVariablesTest(shaderType) {}
protected:
void initTranslator(const ShBuiltInResources &resources) override
{
mTranslator.reset(
new TranslatorGLSL(mShaderType, SH_GLES3_1_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));
ASSERT_TRUE(mTranslator->Init(resources));
}
};
class CollectVariablesOESGeometryShaderTest : public CollectVariablesTestES31
{
public:
CollectVariablesOESGeometryShaderTest(sh::GLenum shaderType) : CollectVariablesTest(shaderType)
CollectVariablesOESGeometryShaderTest(sh::GLenum shaderType)
: CollectVariablesTestES31(shaderType)
{
}
......@@ -157,13 +172,6 @@ class CollectVariablesOESGeometryShaderTest : public CollectVariablesTest
initTranslator(resources);
}
void initTranslator(const ShBuiltInResources &resources)
{
mTranslator.reset(
new TranslatorGLSL(mShaderType, SH_GLES3_1_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));
ASSERT_TRUE(mTranslator->Init(resources));
}
};
class CollectGeometryVariablesTest : public CollectVariablesOESGeometryShaderTest
......@@ -196,6 +204,26 @@ class CollectFragmentVariablesOESGeometryShaderTest : public CollectVariablesOES
: CollectVariablesOESGeometryShaderTest(GL_FRAGMENT_SHADER)
{
}
protected:
void initTranslator(const ShBuiltInResources &resources)
{
mTranslator.reset(
new TranslatorGLSL(mShaderType, SH_GLES3_1_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));
ASSERT_TRUE(mTranslator->Init(resources));
}
};
class CollectVertexVariablesES31Test : public CollectVariablesTestES31
{
public:
CollectVertexVariablesES31Test() : CollectVariablesTestES31(GL_VERTEX_SHADER) {}
};
class CollectFragmentVariablesES31Test : public CollectVariablesTestES31
{
public:
CollectFragmentVariablesES31Test() : CollectVariablesTestES31(GL_FRAGMENT_SHADER) {}
};
TEST_F(CollectFragmentVariablesTest, SimpleOutputVar)
......@@ -1207,3 +1235,56 @@ TEST_F(CollectFragmentVariablesOESGeometryShaderTest, CollectLayer)
EXPECT_GLENUM_EQ(GL_HIGH_INT, varying->precision);
EXPECT_GLENUM_EQ(GL_INT, varying->type);
}
// Test collecting the location of vertex shader outputs.
TEST_F(CollectVertexVariablesES31Test, CollectOutputWithLocation)
{
const std::string &shaderString =
"#version 310 es\n"
"out vec4 v_output1;\n"
"layout (location = 1) out vec4 v_output2;\n"
"void main()\n"
"{\n"
"}\n";
compile(shaderString);
const auto &outputVaryings = mTranslator->getOutputVaryings();
ASSERT_EQ(2u, outputVaryings.size());
const Varying *varying1 = &outputVaryings[0];
EXPECT_EQ("v_output1", varying1->name);
EXPECT_EQ(-1, varying1->location);
const Varying *varying2 = &outputVaryings[1];
EXPECT_EQ("v_output2", varying2->name);
EXPECT_EQ(1, varying2->location);
}
// Test collecting the location of fragment shader inputs.
TEST_F(CollectFragmentVariablesES31Test, CollectInputWithLocation)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"in vec4 f_input1;\n"
"layout (location = 1) in vec4 f_input2;\n"
"layout (location = 0) out vec4 o_color;\n"
"void main()\n"
"{\n"
" o_color = f_input2;\n"
"}\n";
compile(shaderString);
const auto &inputVaryings = mTranslator->getInputVaryings();
ASSERT_EQ(2u, inputVaryings.size());
const Varying *varying1 = &inputVaryings[0];
EXPECT_EQ("f_input1", varying1->name);
EXPECT_EQ(-1, varying1->location);
const Varying *varying2 = &inputVaryings[1];
EXPECT_EQ("f_input2", varying2->name);
EXPECT_EQ(1, varying2->location);
}
......@@ -4833,4 +4833,182 @@ TEST_F(FragmentShaderValidationTest, TextureGatherTooGreatOffset)
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that it isn't allowed to use 'location' layout qualifier on GLSL ES 3.0 vertex shader
// outputs.
TEST_F(VertexShaderValidationTest, UseLocationOnVertexOutES30)
{
const std::string &shaderString =
"#version 300 es\n"
"in vec4 v1;\n"
"layout (location = 1) out vec4 o_color;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that using 'location' layout qualifier on vertex shader outputs is legal in GLSL ES 3.1
// shaders.
TEST_F(VertexShaderValidationTest, UseLocationOnVertexOutES31)
{
const std::string &shaderString =
"#version 310 es\n"
"in vec4 v1;\n"
"layout (location = 1) out vec4 o_color1;\n"
"layout (location = 2) out vec4 o_color2;\n"
"out vec3 v3;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that it isn't allowed to use 'location' layout qualifier on GLSL ES 3.0 fragment shader
// inputs.
TEST_F(FragmentShaderValidationTest, UseLocationOnFragmentInES30)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout (location = 0) in vec4 v_color1;\n"
"layout (location = 0) out vec4 o_color;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that using 'location' layout qualifier on fragment shader inputs is legal in GLSL ES 3.1
// shaders.
TEST_F(FragmentShaderValidationTest, UseLocationOnFragmentInES31)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout (location = 0) in mat4 v_mat;\n"
"layout (location = 4) in vec4 v_color1;\n"
"in vec2 v_color2;\n"
"layout (location = 0) out vec4 o_color;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that declaring outputs of a vertex shader with same location causes a compile error.
TEST_F(VertexShaderValidationTest, DeclareSameLocationOnVertexOut)
{
const std::string &shaderString =
"#version 310 es\n"
"in float i_value;\n"
"layout (location = 1) out vec4 o_color1;\n"
"layout (location = 1) out vec4 o_color2;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that declaring inputs of a fragment shader with same location causes a compile error.
TEST_F(FragmentShaderValidationTest, DeclareSameLocationOnFragmentIn)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"in float i_value;\n"
"layout (location = 1) in vec4 i_color1;\n"
"layout (location = 1) in vec4 i_color2;\n"
"layout (location = 0) out vec4 o_color;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that the location of an element of an array conflicting with other output varyings in a
// vertex shader causes a compile error.
TEST_F(VertexShaderValidationTest, LocationConflictsnOnArrayElement)
{
const std::string &shaderString =
"#version 310 es\n"
"in float i_value;\n"
"layout (location = 0) out vec4 o_color1[3];\n"
"layout (location = 1) out vec4 o_color2;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that the location of an element of a matrix conflicting with other output varyings in a
// vertex shader causes a compile error.
TEST_F(VertexShaderValidationTest, LocationConflictsOnMatrixElement)
{
const std::string &shaderString =
"#version 310 es\n"
"in float i_value;\n"
"layout (location = 0) out mat4 o_mvp;\n"
"layout (location = 2) out vec4 o_color;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that the location of an element of a struct conflicting with other output varyings in a
// vertex shader causes a compile error.
TEST_F(VertexShaderValidationTest, LocationConflictsOnStructElement)
{
const std::string &shaderString =
"#version 310 es\n"
"in float i_value;\n"
"struct S\n"
"{\n"
" float value1;\n"
" vec3 value2;\n"
"};\n"
"layout (location = 0) out S s_in;"
"layout (location = 1) out vec4 o_color;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
\ No newline at end of file
......@@ -422,4 +422,53 @@ TEST(ShaderVariableTest, BuiltinInvariantVarying)
sh::Destruct(compiler);
}
// Verify in ES3.1 two varyings with either same name or same declared location can match.
TEST(ShaderVariableTest, IsSameVaryingWithDifferentName)
{
// Varying float vary1;
Varying vx;
vx.type = GL_FLOAT;
vx.arraySize = 0;
vx.precision = GL_MEDIUM_FLOAT;
vx.name = "vary1";
vx.mappedName = "m_vary1";
vx.staticUse = true;
vx.isInvariant = false;
// Varying float vary2;
Varying fx;
fx.type = GL_FLOAT;
fx.arraySize = 0;
fx.precision = GL_MEDIUM_FLOAT;
fx.name = "vary2";
fx.mappedName = "m_vary2";
fx.staticUse = true;
fx.isInvariant = false;
// ESSL3 behavior: name must match
EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 300));
// ESSL3.1 behavior:
// [OpenGL ES 3.1 SPEC Chapter 7.4.1]
// An output variable is considered to match an input variable in the subsequent shader if:
// - the two variables match in name, type, and qualification; or
// - the two variables are declared with the same location qualifier and match in type and
// qualification.
vx.location = 0;
fx.location = 0;
EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 310));
fx.name = vx.name;
fx.mappedName = vx.mappedName;
fx.location = -1;
EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 310));
fx.location = 1;
EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 310));
fx.location = 0;
EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 310));
}
} // namespace sh
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