blob: e969524d44d93dd367b0f3f81dfeb493c28e55fa [file] [log] [blame]
#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,
VTCTYPE_LAST
};
VarTypeComponent (Type type_, int index_) : type(type_), index(index_) {}
VarTypeComponent (void) : type(VTCTYPE_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