#ifndef _GLUVARTYPEUTIL_HPP
|
#define _GLUVARTYPEUTIL_HPP
|
/*-------------------------------------------------------------------------
|
* drawElements Quality Program OpenGL ES Utilities
|
* ------------------------------------------------
|
*
|
* Copyright 2014 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*
|
*//*!
|
* \file
|
* \brief Shader variable type utilities.
|
*//*--------------------------------------------------------------------*/
|
|
#include "tcuDefs.hpp"
|
#include "gluVarType.hpp"
|
|
#include <vector>
|
#include <string>
|
#include <iterator>
|
|
namespace glu
|
{
|
|
// Variable path tokenizer
|
|
class VarTokenizer
|
{
|
public:
|
enum Token
|
{
|
TOKEN_IDENTIFIER = 0,
|
TOKEN_LEFT_BRACKET,
|
TOKEN_RIGHT_BRACKET,
|
TOKEN_PERIOD,
|
TOKEN_NUMBER,
|
TOKEN_END,
|
|
TOKEN_LAST
|
};
|
|
VarTokenizer (const char* str);
|
~VarTokenizer (void) {}
|
|
Token getToken (void) const { return m_token; }
|
std::string getIdentifier (void) const { return std::string(m_str+m_tokenStart, m_str+m_tokenStart+m_tokenLen); }
|
int getNumber (void) const;
|
int getCurrentTokenStartLocation (void) const { return m_tokenStart; }
|
int getCurrentTokenEndLocation (void) const { return m_tokenStart + m_tokenLen; }
|
void advance (void);
|
|
private:
|
const char* m_str;
|
|
Token m_token;
|
int m_tokenStart;
|
int m_tokenLen;
|
};
|
|
// VarType subtype path utilities.
|
|
struct VarTypeComponent
|
{
|
enum Type
|
{
|
STRUCT_MEMBER = 0,
|
ARRAY_ELEMENT,
|
MATRIX_COLUMN,
|
VECTOR_COMPONENT,
|
|
TYPE_LAST
|
};
|
|
VarTypeComponent (Type type_, int index_) : type(type_), index(index_) {}
|
VarTypeComponent (void) : type(TYPE_LAST), index(0) {}
|
|
bool operator== (const VarTypeComponent& other) const { return type == other.type && index == other.index; }
|
bool operator!= (const VarTypeComponent& other) const { return type != other.type || index != other.index; }
|
|
Type type;
|
int index;
|
};
|
|
typedef std::vector<VarTypeComponent> TypeComponentVector;
|
|
// TypeComponentVector utilties.
|
|
template <typename Iterator>
|
bool isValidTypePath (const VarType& type, Iterator begin, Iterator end);
|
|
template <typename Iterator>
|
VarType getVarType (const VarType& type, Iterator begin, Iterator end);
|
|
inline bool isValidTypePath (const VarType& type, const TypeComponentVector& path) { return isValidTypePath(type, path.begin(), path.end()); }
|
inline VarType getVarType (const VarType& type, const TypeComponentVector& path) { return getVarType(type, path.begin(), path.end()); }
|
|
std::string parseVariableName (const char* nameWithPath);
|
void parseTypePath (const char* nameWithPath, const VarType& type, TypeComponentVector& path);
|
|
// Type path formatter.
|
|
struct TypeAccessFormat
|
{
|
TypeAccessFormat (const VarType& type_, const TypeComponentVector& path_) : type(type_), path(path_) {}
|
|
const VarType& type;
|
const TypeComponentVector& path;
|
};
|
|
std::ostream& operator<< (std::ostream& str, const TypeAccessFormat& format);
|
|
// Subtype path builder.
|
|
class SubTypeAccess
|
{
|
public:
|
SubTypeAccess (const VarType& type);
|
|
SubTypeAccess& member (int ndx) { m_path.push_back(VarTypeComponent(VarTypeComponent::STRUCT_MEMBER, ndx)); DE_ASSERT(isValid()); return *this; } //!< Access struct element.
|
SubTypeAccess& element (int ndx) { m_path.push_back(VarTypeComponent(VarTypeComponent::ARRAY_ELEMENT, ndx)); DE_ASSERT(isValid()); return *this; } //!< Access array element.
|
SubTypeAccess& column (int ndx) { m_path.push_back(VarTypeComponent(VarTypeComponent::MATRIX_COLUMN, ndx)); DE_ASSERT(isValid()); return *this; } //!< Access column.
|
SubTypeAccess& component (int ndx) { m_path.push_back(VarTypeComponent(VarTypeComponent::VECTOR_COMPONENT, ndx)); DE_ASSERT(isValid()); return *this; } //!< Access component.
|
SubTypeAccess& parent (void) { DE_ASSERT(!m_path.empty()); m_path.pop_back(); return *this; }
|
|
SubTypeAccess member (int ndx) const { return SubTypeAccess(*this).member(ndx); }
|
SubTypeAccess element (int ndx) const { return SubTypeAccess(*this).element(ndx); }
|
SubTypeAccess column (int ndx) const { return SubTypeAccess(*this).column(ndx); }
|
SubTypeAccess component (int ndx) const { return SubTypeAccess(*this).component(ndx); }
|
SubTypeAccess parent (void) const { return SubTypeAccess(*this).parent(); }
|
|
bool isValid (void) const { return isValidTypePath(m_type, m_path); }
|
VarType getType (void) const { return getVarType(m_type, m_path); }
|
const TypeComponentVector& getPath (void) const { return m_path; }
|
|
bool empty (void) const { return m_path.empty(); }
|
|
bool operator== (const SubTypeAccess& other) const { return m_path == other.m_path && m_type == other.m_type; }
|
bool operator!= (const SubTypeAccess& other) const { return m_path != other.m_path || m_type != other.m_type; }
|
|
private:
|
VarType m_type;
|
TypeComponentVector m_path;
|
};
|
|
// Subtype iterator.
|
|
// \note VarType must be live during iterator usage.
|
template <class IsExpanded>
|
class SubTypeIterator : public std::iterator<std::forward_iterator_tag, VarType>
|
{
|
public:
|
static SubTypeIterator<IsExpanded> begin (const VarType* type) { return SubTypeIterator(type); }
|
static SubTypeIterator<IsExpanded> end (const VarType* type) { DE_UNREF(type); return SubTypeIterator(DE_NULL); }
|
|
bool operator== (const SubTypeIterator<IsExpanded>& other) const { return m_type == other.m_type && m_path == other.m_path; }
|
bool operator!= (const SubTypeIterator<IsExpanded>& other) const { return m_type != other.m_type || m_path != other.m_path; }
|
|
SubTypeIterator<IsExpanded>& operator++ (void);
|
SubTypeIterator<IsExpanded> operator++ (int) { SubTypeIterator<IsExpanded> copy(*this); ++(*this); return copy; }
|
|
void toStream (std::ostream& str) const { str << TypeAccessFormat(*m_type, m_path); }
|
VarType getType (void) const { return getVarType(*m_type, m_path.begin(), m_path.end()); }
|
const TypeComponentVector& getPath (void) const { return m_path; }
|
|
VarType operator* (void) const { return getType(); }
|
|
private:
|
SubTypeIterator (const VarType* type);
|
|
void removeTraversed (void);
|
void findNext (void);
|
|
const VarType* m_type;
|
TypeComponentVector m_path;
|
};
|
|
struct IsBasicType { bool operator() (const VarType& type) const { return type.isBasicType(); } };
|
struct IsScalarType { bool operator() (const VarType& type) const { return type.isBasicType() && isDataTypeScalar(type.getBasicType()); } };
|
struct IsVectorOrScalarType { bool operator() (const VarType& type) const { return type.isBasicType() && isDataTypeScalarOrVector(type.getBasicType()); } };
|
|
typedef SubTypeIterator<IsBasicType> BasicTypeIterator;
|
typedef SubTypeIterator<IsVectorOrScalarType> VectorTypeIterator;
|
typedef SubTypeIterator<IsScalarType> ScalarTypeIterator;
|
|
template <class IsExpanded>
|
std::ostream& operator<< (std::ostream& str, const SubTypeIterator<IsExpanded>& iter)
|
{
|
iter.toStream(str);
|
return str;
|
}
|
|
template <class IsExpanded>
|
SubTypeIterator<IsExpanded>::SubTypeIterator (const VarType* type)
|
: m_type(type)
|
{
|
if (m_type)
|
findNext();
|
}
|
|
template <class IsExpanded>
|
SubTypeIterator<IsExpanded>& SubTypeIterator<IsExpanded>::operator++ (void)
|
{
|
if (!m_path.empty())
|
{
|
// Remove traversed nodes.
|
removeTraversed();
|
|
if (!m_path.empty())
|
findNext();
|
else
|
m_type = DE_NULL; // Unset type to signal end.
|
}
|
else
|
{
|
// First type was already expanded.
|
DE_ASSERT(IsExpanded()(getVarType(*m_type, m_path)));
|
m_type = DE_NULL;
|
}
|
|
return *this;
|
}
|
|
template <class IsExpanded>
|
void SubTypeIterator<IsExpanded>::removeTraversed (void)
|
{
|
DE_ASSERT(m_type && !m_path.empty());
|
|
// Pop traversed nodes.
|
while (!m_path.empty())
|
{
|
VarTypeComponent& curComp = m_path.back();
|
VarType parentType = getVarType(*m_type, m_path.begin(), m_path.end()-1);
|
|
if (curComp.type == VarTypeComponent::MATRIX_COLUMN)
|
{
|
DE_ASSERT(isDataTypeMatrix(parentType.getBasicType()));
|
if (curComp.index+1 < getDataTypeMatrixNumColumns(parentType.getBasicType()))
|
break;
|
}
|
else if (curComp.type == VarTypeComponent::VECTOR_COMPONENT)
|
{
|
DE_ASSERT(isDataTypeVector(parentType.getBasicType()));
|
if (curComp.index+1 < getDataTypeScalarSize(parentType.getBasicType()))
|
break;
|
}
|
else if (curComp.type == VarTypeComponent::ARRAY_ELEMENT)
|
{
|
DE_ASSERT(parentType.isArrayType());
|
if (curComp.index+1 < parentType.getArraySize())
|
break;
|
}
|
else if (curComp.type == VarTypeComponent::STRUCT_MEMBER)
|
{
|
DE_ASSERT(parentType.isStructType());
|
if (curComp.index+1 < parentType.getStructPtr()->getNumMembers())
|
break;
|
}
|
|
m_path.pop_back();
|
}
|
}
|
|
template <class IsExpanded>
|
void SubTypeIterator<IsExpanded>::findNext (void)
|
{
|
if (!m_path.empty())
|
{
|
// Increment child counter in current level.
|
VarTypeComponent& curComp = m_path.back();
|
curComp.index += 1;
|
}
|
|
for (;;)
|
{
|
VarType curType = getVarType(*m_type, m_path);
|
|
if (IsExpanded()(curType))
|
break;
|
|
// Recurse into child type.
|
if (curType.isBasicType())
|
{
|
DataType basicType = curType.getBasicType();
|
|
if (isDataTypeMatrix(basicType))
|
m_path.push_back(VarTypeComponent(VarTypeComponent::MATRIX_COLUMN, 0));
|
else if (isDataTypeVector(basicType))
|
m_path.push_back(VarTypeComponent(VarTypeComponent::VECTOR_COMPONENT, 0));
|
else
|
DE_ASSERT(false); // Can't expand scalars - IsExpanded() is buggy.
|
}
|
else if (curType.isArrayType())
|
m_path.push_back(VarTypeComponent(VarTypeComponent::ARRAY_ELEMENT, 0));
|
else if (curType.isStructType())
|
m_path.push_back(VarTypeComponent(VarTypeComponent::STRUCT_MEMBER, 0));
|
else
|
DE_ASSERT(false);
|
}
|
}
|
|
template <typename Iterator>
|
bool isValidTypePath (const VarType& type, Iterator begin, Iterator end)
|
{
|
const VarType* curType = &type;
|
Iterator pathIter = begin;
|
|
// Process struct member and array element parts of path.
|
while (pathIter != end)
|
{
|
if (pathIter->type == VarTypeComponent::STRUCT_MEMBER)
|
{
|
if (!curType->isStructType() || !de::inBounds(pathIter->index, 0, curType->getStructPtr()->getNumMembers()))
|
return false;
|
|
curType = &curType->getStructPtr()->getMember(pathIter->index).getType();
|
}
|
else if (pathIter->type == VarTypeComponent::ARRAY_ELEMENT)
|
{
|
if (!curType->isArrayType() || (curType->getArraySize() != VarType::UNSIZED_ARRAY && !de::inBounds(pathIter->index, 0, curType->getArraySize())))
|
return false;
|
|
curType = &curType->getElementType();
|
}
|
else
|
break;
|
|
++pathIter;
|
}
|
|
if (pathIter != end)
|
{
|
DE_ASSERT(pathIter->type == VarTypeComponent::MATRIX_COLUMN || pathIter->type == VarTypeComponent::VECTOR_COMPONENT);
|
|
// Current type should be basic type.
|
if (!curType->isBasicType())
|
return false;
|
|
DataType basicType = curType->getBasicType();
|
|
if (pathIter->type == VarTypeComponent::MATRIX_COLUMN)
|
{
|
if (!isDataTypeMatrix(basicType))
|
return false;
|
|
basicType = getDataTypeFloatVec(getDataTypeMatrixNumRows(basicType));
|
++pathIter;
|
}
|
|
if (pathIter != end && pathIter->type == VarTypeComponent::VECTOR_COMPONENT)
|
{
|
if (!isDataTypeVector(basicType))
|
return false;
|
|
basicType = getDataTypeScalarType(basicType);
|
++pathIter;
|
}
|
}
|
|
return pathIter == end;
|
}
|
|
template <typename Iterator>
|
VarType getVarType (const VarType& type, Iterator begin, Iterator end)
|
{
|
TCU_CHECK(isValidTypePath(type, begin, end));
|
|
const VarType* curType = &type;
|
Iterator pathIter = begin;
|
|
// Process struct member and array element parts of path.
|
while (pathIter != end)
|
{
|
if (pathIter->type == VarTypeComponent::STRUCT_MEMBER)
|
curType = &curType->getStructPtr()->getMember(pathIter->index).getType();
|
else if (pathIter->type == VarTypeComponent::ARRAY_ELEMENT)
|
curType = &curType->getElementType();
|
else
|
break;
|
|
++pathIter;
|
}
|
|
if (pathIter != end)
|
{
|
DataType basicType = curType->getBasicType();
|
Precision precision = curType->getPrecision();
|
|
if (pathIter->type == VarTypeComponent::MATRIX_COLUMN)
|
{
|
basicType = getDataTypeFloatVec(getDataTypeMatrixNumRows(basicType));
|
++pathIter;
|
}
|
|
if (pathIter != end && pathIter->type == VarTypeComponent::VECTOR_COMPONENT)
|
{
|
basicType = getDataTypeScalarType(basicType);
|
++pathIter;
|
}
|
|
DE_ASSERT(pathIter == end);
|
return VarType(basicType, precision);
|
}
|
else
|
return VarType(*curType);
|
}
|
|
} // glu
|
|
#endif // _GLUVARTYPEUTIL_HPP
|