| #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 |