Commit ed13636a by Zhenyao Mo

Add type comparison, type retrieval, original name retrieval to ShaderVariable.

This is needed to effectively use the new APIs to get shader variable info. BUG=angle::770 TEST=ShaderVariableTest Change-Id: Ia591eb567868ebe898f4a7449c64167ad212f59b Reviewed-on: https://chromium-review.googlesource.com/221388Tested-by: 's avatarZhenyao Mo <zmo@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarKenneth Russell <kbr@chromium.org> Reviewed-by: 's avatarShannon Woods <shannonwoods@chromium.org>
parent e0a2d1c5
...@@ -52,6 +52,21 @@ struct COMPILER_EXPORT ShaderVariable ...@@ -52,6 +52,21 @@ struct COMPILER_EXPORT ShaderVariable
unsigned int elementCount() const { return std::max(1u, arraySize); } unsigned int elementCount() const { return std::max(1u, arraySize); }
bool isStruct() const { return !fields.empty(); } bool isStruct() const { return !fields.empty(); }
// All of the shader's variables are described using nested data
// structures. This is needed in order to disambiguate similar looking
// types, such as two structs containing the same fields, but in
// different orders. "findInfoByMappedName" provides an easy query for
// users to dive into the data structure and fetch the unique variable
// instance corresponding to a dereferencing chain of the top-level
// variable.
// Given a mapped name like 'a[0].b.c[0]', return the ShaderVariable
// that defines 'c' in |leafVar|, and the original name 'A[0].B.C[0]'
// in |originalName|, based on the assumption that |this| defines 'a'.
// If no match is found, return false.
bool findInfoByMappedName(const std::string &mappedFullName,
const ShaderVariable **leafVar,
std::string* originalFullName) const;
GLenum type; GLenum type;
GLenum precision; GLenum precision;
std::string name; std::string name;
...@@ -60,6 +75,16 @@ struct COMPILER_EXPORT ShaderVariable ...@@ -60,6 +75,16 @@ struct COMPILER_EXPORT ShaderVariable
bool staticUse; bool staticUse;
std::vector<ShaderVariable> fields; std::vector<ShaderVariable> fields;
std::string structName; std::string structName;
protected:
bool isSameVariableAtLinkTime(const ShaderVariable &other,
bool matchPrecision) const;
bool operator==(const ShaderVariable &other) const;
bool operator!=(const ShaderVariable &other) const
{
return !operator==(other);
}
}; };
struct COMPILER_EXPORT Uniform : public ShaderVariable struct COMPILER_EXPORT Uniform : public ShaderVariable
...@@ -68,6 +93,16 @@ struct COMPILER_EXPORT Uniform : public ShaderVariable ...@@ -68,6 +93,16 @@ struct COMPILER_EXPORT Uniform : public ShaderVariable
~Uniform(); ~Uniform();
Uniform(const Uniform &other); Uniform(const Uniform &other);
Uniform &operator=(const Uniform &other); Uniform &operator=(const Uniform &other);
bool operator==(const Uniform &other) const;
bool operator!=(const Uniform &other) const
{
return !operator==(other);
}
// Decide whether two uniforms are the same at shader link time,
// assuming one from vertex shader and the other from fragment shader.
// See GLSL ES Spec 3.00.3, sec 4.3.5.
bool isSameUniformAtLinkTime(const Uniform &other) const;
}; };
struct COMPILER_EXPORT Attribute : public ShaderVariable struct COMPILER_EXPORT Attribute : public ShaderVariable
...@@ -76,6 +111,11 @@ struct COMPILER_EXPORT Attribute : public ShaderVariable ...@@ -76,6 +111,11 @@ struct COMPILER_EXPORT Attribute : public ShaderVariable
~Attribute(); ~Attribute();
Attribute(const Attribute &other); Attribute(const Attribute &other);
Attribute &operator=(const Attribute &other); Attribute &operator=(const Attribute &other);
bool operator==(const Attribute &other) const;
bool operator!=(const Attribute &other) const
{
return !operator==(other);
}
int location; int location;
}; };
...@@ -86,6 +126,18 @@ struct COMPILER_EXPORT InterfaceBlockField : public ShaderVariable ...@@ -86,6 +126,18 @@ struct COMPILER_EXPORT InterfaceBlockField : public ShaderVariable
~InterfaceBlockField(); ~InterfaceBlockField();
InterfaceBlockField(const InterfaceBlockField &other); InterfaceBlockField(const InterfaceBlockField &other);
InterfaceBlockField &operator=(const InterfaceBlockField &other); InterfaceBlockField &operator=(const InterfaceBlockField &other);
bool operator==(const InterfaceBlockField &other) const;
bool operator!=(const InterfaceBlockField &other) const
{
return !operator==(other);
}
// Decide whether two InterfaceBlock fields are the same at shader
// link time, assuming one from vertex shader and the other from
// fragment shader.
// See GLSL ES Spec 3.00.3, sec 4.3.7.
bool isSameInterfaceBlockFieldAtLinkTime(
const InterfaceBlockField &other) const;
bool isRowMajorLayout; bool isRowMajorLayout;
}; };
...@@ -94,8 +146,18 @@ struct COMPILER_EXPORT Varying : public ShaderVariable ...@@ -94,8 +146,18 @@ struct COMPILER_EXPORT Varying : public ShaderVariable
{ {
Varying(); Varying();
~Varying(); ~Varying();
Varying(const Varying &other); Varying(const Varying &otherg);
Varying &operator=(const Varying &other); Varying &operator=(const Varying &other);
bool operator==(const Varying &other) const;
bool operator!=(const Varying &other) const
{
return !operator==(other);
}
// Decide whether two varyings are the same at shader link time,
// assuming one from vertex shader and the other from fragment shader.
// See GLSL ES Spec 3.00.3, sec 4.3.9.
bool isSameVaryingAtLinkTime(const Varying &other) const;
InterpolationType interpolation; InterpolationType interpolation;
bool isInvariant; bool isInvariant;
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <GLSLANG/ShaderLang.h> #include <GLSLANG/ShaderLang.h>
#include "compiler/translator/compilerdebug.h"
namespace sh namespace sh
{ {
...@@ -53,6 +55,126 @@ ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other) ...@@ -53,6 +55,126 @@ ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
return *this; return *this;
} }
bool ShaderVariable::operator==(const ShaderVariable &other) const
{
if (type != other.type ||
precision != other.precision ||
name != other.name ||
mappedName != other.mappedName ||
arraySize != other.arraySize ||
staticUse != other.staticUse ||
fields.size() != other.fields.size() ||
structName != other.structName)
{
return false;
}
for (size_t ii = 0; ii < fields.size(); ++ii)
{
if (fields[ii] != other.fields[ii])
return false;
}
return true;
}
bool ShaderVariable::findInfoByMappedName(
const std::string &mappedFullName,
const ShaderVariable **leafVar, std::string *originalFullName) const
{
ASSERT(leafVar && originalFullName);
// There are three cases:
// 1) the top variable is of struct type;
// 2) the top variable is an array;
// 3) otherwise.
size_t pos = mappedFullName.find_first_of(".[");
std::string topName;
if (pos == std::string::npos)
{
// Case 3.
if (mappedFullName != this->mappedName)
return false;
*originalFullName = this->name;
*leafVar = this;
return true;
}
else
{
std::string topName = mappedFullName.substr(0, pos);
if (topName != this->mappedName)
return false;
std::string originalName = this->name;
std::string remaining;
if (mappedFullName[pos] == '[')
{
// Case 2.
size_t closePos = mappedFullName.find_first_of(']');
if (closePos < pos || closePos == std::string::npos)
return false;
// Append '[index]'.
originalName += mappedFullName.substr(pos, closePos - pos + 1);
if (closePos + 1 == mappedFullName.size())
{
*originalFullName = originalName;
*leafVar = this;
return true;
}
else
{
// In the form of 'a[0].b', so after ']', '.' is expected.
if (mappedFullName[closePos + 1] != '.')
return false;
remaining = mappedFullName.substr(closePos + 2); // Skip "]."
}
}
else
{
// Case 1.
remaining = mappedFullName.substr(pos + 1); // Skip "."
}
for (size_t ii = 0; ii < this->fields.size(); ++ii)
{
const ShaderVariable *fieldVar = NULL;
std::string originalFieldName;
bool found = fields[ii].findInfoByMappedName(
remaining, &fieldVar, &originalFieldName);
if (found)
{
*originalFullName = originalName + "." + originalFieldName;
*leafVar = fieldVar;
return true;
}
}
return false;
}
}
bool ShaderVariable::isSameVariableAtLinkTime(
const ShaderVariable &other, bool matchPrecision) const
{
if (type != other.type)
return false;
if (matchPrecision && precision != other.precision)
return false;
if (name != other.name)
return false;
ASSERT(mappedName == other.mappedName);
if (arraySize != other.arraySize)
return false;
if (fields.size() != other.fields.size())
return false;
for (size_t ii = 0; ii < fields.size(); ++ii)
{
if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii],
matchPrecision))
{
return false;
}
}
if (structName != other.structName)
return false;
return true;
}
Uniform::Uniform() Uniform::Uniform()
{} {}
...@@ -69,6 +191,16 @@ Uniform &Uniform::operator=(const Uniform &other) ...@@ -69,6 +191,16 @@ Uniform &Uniform::operator=(const Uniform &other)
return *this; return *this;
} }
bool Uniform::operator==(const Uniform &other) const
{
return ShaderVariable::operator==(other);
}
bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const
{
return ShaderVariable::isSameVariableAtLinkTime(other, true);
}
Attribute::Attribute() Attribute::Attribute()
: location(-1) : location(-1)
{} {}
...@@ -88,6 +220,12 @@ Attribute &Attribute::operator=(const Attribute &other) ...@@ -88,6 +220,12 @@ Attribute &Attribute::operator=(const Attribute &other)
return *this; return *this;
} }
bool Attribute::operator==(const Attribute &other) const
{
return (ShaderVariable::operator==(other) &&
location == other.location);
}
InterfaceBlockField::InterfaceBlockField() InterfaceBlockField::InterfaceBlockField()
: isRowMajorLayout(false) : isRowMajorLayout(false)
{} {}
...@@ -107,6 +245,19 @@ InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &o ...@@ -107,6 +245,19 @@ InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &o
return *this; return *this;
} }
bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const
{
return (ShaderVariable::operator==(other) &&
isRowMajorLayout == other.isRowMajorLayout);
}
bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime(
const InterfaceBlockField &other) const
{
return (ShaderVariable::isSameVariableAtLinkTime(other, true) &&
isRowMajorLayout == other.isRowMajorLayout);
}
Varying::Varying() Varying::Varying()
: interpolation(INTERPOLATION_SMOOTH), : interpolation(INTERPOLATION_SMOOTH),
isInvariant(false) isInvariant(false)
...@@ -129,6 +280,20 @@ Varying &Varying::operator=(const Varying &other) ...@@ -129,6 +280,20 @@ Varying &Varying::operator=(const Varying &other)
return *this; return *this;
} }
bool Varying::operator==(const Varying &other) const
{
return (ShaderVariable::operator==(other) &&
interpolation == other.interpolation &&
isInvariant == other.isInvariant);
}
bool Varying::isSameVaryingAtLinkTime(const Varying &other) const
{
return (ShaderVariable::isSameVariableAtLinkTime(other, false) &&
interpolation == other.interpolation &&
isInvariant == other.isInvariant);
}
InterfaceBlock::InterfaceBlock() InterfaceBlock::InterfaceBlock()
: arraySize(0), : arraySize(0),
layout(BLOCKLAYOUT_PACKED), layout(BLOCKLAYOUT_PACKED),
......
//
// Copyright (c) 2014 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.
//
// CollectVariables_test.cpp:
// Some tests for shader inspection
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
namespace sh
{
TEST(ShaderVariableTest, FindInfoByMappedName)
{
// struct A {
// float x[2];
// vec3 y;
// };
// struct B {
// A a[3];
// };
// B uni[2];
ShaderVariable uni;
uni.arraySize = 2;
uni.name = "uni";
uni.mappedName = "m_uni";
uni.structName = "B";
{
ShaderVariable a;
a.arraySize = 3;
a.name = "a";
a.mappedName = "m_a";
a.structName = "A";
{
ShaderVariable x(GL_FLOAT, 2);
x.name = "x";
x.mappedName = "m_x";
a.fields.push_back(x);
ShaderVariable y(GL_FLOAT_VEC3, 0);
y.name = "y";
y.mappedName = "m_y";
a.fields.push_back(y);
}
uni.fields.push_back(a);
}
const ShaderVariable *leafVar = NULL;
std::string originalFullName;
std::string mappedFullName = "wrongName";
EXPECT_FALSE(uni.findInfoByMappedName(
mappedFullName, &leafVar, &originalFullName));
mappedFullName = "m_uni";
EXPECT_TRUE(uni.findInfoByMappedName(
mappedFullName, &leafVar, &originalFullName));
EXPECT_EQ(&uni, leafVar);
EXPECT_STREQ("uni", originalFullName.c_str());
mappedFullName = "m_uni[0].m_a[1].wrongName";
EXPECT_FALSE(uni.findInfoByMappedName(
mappedFullName, &leafVar, &originalFullName));
mappedFullName = "m_uni[0].m_a[1].m_x";
EXPECT_TRUE(uni.findInfoByMappedName(
mappedFullName, &leafVar, &originalFullName));
EXPECT_EQ(&(uni.fields[0].fields[0]), leafVar);
EXPECT_STREQ("uni[0].a[1].x", originalFullName.c_str());
mappedFullName = "m_uni[0].m_a[1].m_x[0]";
EXPECT_TRUE(uni.findInfoByMappedName(
mappedFullName, &leafVar, &originalFullName));
EXPECT_EQ(&(uni.fields[0].fields[0]), leafVar);
EXPECT_STREQ("uni[0].a[1].x[0]", originalFullName.c_str());
mappedFullName = "m_uni[0].m_a[1].m_y";
EXPECT_TRUE(uni.findInfoByMappedName(
mappedFullName, &leafVar, &originalFullName));
EXPECT_EQ(&(uni.fields[0].fields[1]), leafVar);
EXPECT_STREQ("uni[0].a[1].y", originalFullName.c_str());
}
TEST(ShaderVariableTest, IsSameUniformWithDifferentFieldOrder)
{
// struct A {
// float x;
// float y;
// };
// uniform A uni;
Uniform vx_a;
vx_a.arraySize = 0;
vx_a.name = "uni";
vx_a.mappedName = "m_uni";
vx_a.structName = "A";
{
ShaderVariable x(GL_FLOAT, 0);
x.name = "x";
x.mappedName = "m_x";
vx_a.fields.push_back(x);
ShaderVariable y(GL_FLOAT, 0);
y.name = "y";
y.mappedName = "m_y";
vx_a.fields.push_back(y);
}
// struct A {
// float y;
// float x;
// };
// uniform A uni;
Uniform fx_a;
fx_a.arraySize = 0;
fx_a.name = "uni";
fx_a.mappedName = "m_uni";
fx_a.structName = "A";
{
ShaderVariable y(GL_FLOAT, 0);
y.name = "y";
y.mappedName = "m_y";
fx_a.fields.push_back(y);
ShaderVariable x(GL_FLOAT, 0);
x.name = "x";
x.mappedName = "m_x";
fx_a.fields.push_back(x);
}
EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
}
TEST(ShaderVariableTest, IsSameUniformWithDifferentStructNames)
{
// struct A {
// float x;
// float y;
// };
// uniform A uni;
Uniform vx_a;
vx_a.arraySize = 0;
vx_a.name = "uni";
vx_a.mappedName = "m_uni";
vx_a.structName = "A";
{
ShaderVariable x(GL_FLOAT, 0);
x.name = "x";
x.mappedName = "m_x";
vx_a.fields.push_back(x);
ShaderVariable y(GL_FLOAT, 0);
y.name = "y";
y.mappedName = "m_y";
vx_a.fields.push_back(y);
}
// struct B {
// float x;
// float y;
// };
// uniform B uni;
Uniform fx_a;
fx_a.arraySize = 0;
fx_a.name = "uni";
fx_a.mappedName = "m_uni";
{
ShaderVariable x(GL_FLOAT, 0);
x.name = "x";
x.mappedName = "m_x";
fx_a.fields.push_back(x);
ShaderVariable y(GL_FLOAT, 0);
y.name = "y";
y.mappedName = "m_y";
fx_a.fields.push_back(y);
}
fx_a.structName = "B";
EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
fx_a.structName = "A";
EXPECT_TRUE(vx_a.isSameUniformAtLinkTime(fx_a));
fx_a.structName = "";
EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
}
TEST(ShaderVariableTest, IsSameVaryingWithDifferentInvariance)
{
// invariant varying float vary;
Varying vx;
vx.type = GL_FLOAT;
vx.arraySize = 0;
vx.precision = GL_MEDIUM_FLOAT;
vx.name = "vary";
vx.mappedName = "m_vary";
vx.staticUse = true;
vx.isInvariant = true;
// varying float vary;
Varying fx;
fx.type = GL_FLOAT;
fx.arraySize = 0;
fx.precision = GL_MEDIUM_FLOAT;
fx.name = "vary";
fx.mappedName = "m_vary";
fx.staticUse = true;
fx.isInvariant = false;
EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx));
// invariant varying float vary;
fx.isInvariant = true;
EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx));
}
} // 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