#ifndef _RSGVARIABLEVALUE_HPP #define _RSGVARIABLEVALUE_HPP /*------------------------------------------------------------------------- * drawElements Quality Program Random Shader Generator * ---------------------------------------------------- * * 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 Variable Value class. *//*--------------------------------------------------------------------*/ #include "rsgDefs.hpp" #include "rsgVariableType.hpp" #include "rsgVariable.hpp" #include "tcuVector.hpp" #include namespace rsg { union Scalar { int intVal; float floatVal; bool boolVal; Scalar(void) : intVal(0) { } Scalar(float v) : floatVal(v) { } Scalar(int v) : intVal(v) { } Scalar(bool v) : boolVal(v) { } // Bit-exact compare bool operator==(Scalar other) const { return intVal == other.intVal; } bool operator!=(Scalar other) const { return intVal != other.intVal; } template static Scalar min(void); template static Scalar max(void); template T as(void) const; template T &as(void); }; DE_STATIC_ASSERT(sizeof(Scalar) == sizeof(uint32_t)); template <> inline Scalar Scalar::min(void) { return Scalar((int)0xff800000); } template <> inline Scalar Scalar::max(void) { return Scalar((int)0x7f800000); } template <> inline Scalar Scalar::min(void) { return Scalar((int)0x80000000); } template <> inline Scalar Scalar::max(void) { return Scalar((int)0x7fffffff); } template <> inline Scalar Scalar::min(void) { return Scalar(false); } template <> inline Scalar Scalar::max(void) { return Scalar(true); } template <> inline float Scalar::as(void) const { return floatVal; } template <> inline float &Scalar::as(void) { return floatVal; } template <> inline int Scalar::as(void) const { return intVal; } template <> inline int &Scalar::as(void) { return intVal; } template <> inline bool Scalar::as(void) const { return boolVal; } template <> inline bool &Scalar::as(void) { return boolVal; } template class StridedValueRead { public: StridedValueRead(const VariableType &type, const Scalar *value) : m_type(type), m_value(value) { } const VariableType &getType(void) const { return m_type; } const Scalar *getValuePtr(void) const { return m_value; } private: const VariableType &m_type; const Scalar *m_value; }; template class ConstStridedValueAccess { public: ConstStridedValueAccess(void) : m_type(DE_NULL), m_value(DE_NULL) { } ConstStridedValueAccess(const VariableType &type, const Scalar *valuePtr) : m_type(&type) , m_value(const_cast(valuePtr)) { } const VariableType &getType(void) const { return *m_type; } // Read-only access ConstStridedValueAccess component(int compNdx) const { return ConstStridedValueAccess(getType().getElementType(), m_value + Stride * compNdx); } ConstStridedValueAccess arrayElement(int elementNdx) const { return ConstStridedValueAccess(getType().getElementType(), m_value + Stride * getType().getElementScalarOffset(elementNdx)); } ConstStridedValueAccess member(int memberNdx) const { return ConstStridedValueAccess(getType().getMembers()[memberNdx].getType(), m_value + Stride * getType().getMemberScalarOffset(memberNdx)); } float asFloat(void) const { DE_STATIC_ASSERT(Stride == 1); return m_value->floatVal; } int asInt(void) const { DE_STATIC_ASSERT(Stride == 1); return m_value->intVal; } bool asBool(void) const { DE_STATIC_ASSERT(Stride == 1); return m_value->boolVal; } Scalar asScalar(void) const { DE_STATIC_ASSERT(Stride == 1); return *m_value; } float asFloat(int ndx) const { DE_ASSERT(de::inBounds(ndx, 0, Stride)); return m_value[ndx].floatVal; } int asInt(int ndx) const { DE_ASSERT(de::inBounds(ndx, 0, Stride)); return m_value[ndx].intVal; } bool asBool(int ndx) const { DE_ASSERT(de::inBounds(ndx, 0, Stride)); return m_value[ndx].boolVal; } Scalar asScalar(int ndx) const { DE_ASSERT(de::inBounds(ndx, 0, Stride)); return m_value[ndx]; } template T as(int ndx) const { DE_ASSERT(de::inBounds(ndx, 0, Stride)); return this->m_value[ndx].template as(); } // For assignment: b = a.value() StridedValueRead value(void) const { return StridedValueRead(getType(), m_value); } protected: const VariableType *m_type; Scalar *m_value; // \note Non-const internal pointer is used so that ValueAccess can extend this class with RW access }; template class StridedValueAccess : public ConstStridedValueAccess { public: StridedValueAccess(void) { } StridedValueAccess(const VariableType &type, Scalar *valuePtr) : ConstStridedValueAccess(type, valuePtr) { } // Read-write access StridedValueAccess component(int compNdx) { return StridedValueAccess(this->getType().getElementType(), this->m_value + Stride * compNdx); } StridedValueAccess arrayElement(int elementNdx) { return StridedValueAccess(this->getType().getElementType(), this->m_value + Stride * this->getType().getElementScalarOffset(elementNdx)); } StridedValueAccess member(int memberNdx) { return StridedValueAccess(this->getType().getMembers()[memberNdx].getType(), this->m_value + Stride * this->getType().getMemberScalarOffset(memberNdx)); } float &asFloat(void) { DE_STATIC_ASSERT(Stride == 1); return this->m_value->floatVal; } int &asInt(void) { DE_STATIC_ASSERT(Stride == 1); return this->m_value->intVal; } bool &asBool(void) { DE_STATIC_ASSERT(Stride == 1); return this->m_value->boolVal; } Scalar &asScalar(void) { DE_STATIC_ASSERT(Stride == 1); return *this->m_value; } float &asFloat(int ndx) { DE_ASSERT(de::inBounds(ndx, 0, Stride)); return this->m_value[ndx].floatVal; } int &asInt(int ndx) { DE_ASSERT(de::inBounds(ndx, 0, Stride)); return this->m_value[ndx].intVal; } bool &asBool(int ndx) { DE_ASSERT(de::inBounds(ndx, 0, Stride)); return this->m_value[ndx].boolVal; } Scalar &asScalar(int ndx) { DE_ASSERT(de::inBounds(ndx, 0, Stride)); return this->m_value[ndx]; } template T &as(int ndx) { DE_ASSERT(de::inBounds(ndx, 0, Stride)); return this->m_value[ndx].template as(); } template StridedValueAccess &operator=(const StridedValueRead &value); // Helpers, work only in Stride == 1 case template StridedValueAccess &operator=(const tcu::Vector &vec); StridedValueAccess &operator=(float floatVal) { asFloat() = floatVal; return *this; } StridedValueAccess &operator=(int intVal) { asInt() = intVal; return *this; } StridedValueAccess &operator=(bool boolVal) { asBool() = boolVal; return *this; } StridedValueAccess &operator=(Scalar val) { asScalar() = val; return *this; } }; template template StridedValueAccess &StridedValueAccess::operator=(const StridedValueRead &valueRead) { DE_STATIC_ASSERT(SrcStride == Stride || SrcStride == 1); DE_ASSERT(this->getType() == valueRead.getType()); int scalarSize = this->getType().getScalarSize(); if (scalarSize == 0) return *this; // Happens when void value range is copied if (Stride == SrcStride) std::copy(valueRead.getValuePtr(), valueRead.getValuePtr() + scalarSize * Stride, this->m_value); else { for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) std::fill(this->m_value + scalarNdx * Stride, this->m_value + (scalarNdx + 1) * Stride, valueRead.getValuePtr()[scalarNdx]); } return *this; } template template StridedValueAccess &StridedValueAccess::operator=(const tcu::Vector &vec) { DE_ASSERT(this->getType() == VariableType(VariableType::TYPE_FLOAT, Size)); for (int comp = 0; comp < 4; comp++) component(comp).asFloat() = vec.getPtr()[comp]; return *this; } // Typedefs for stride == 1 case typedef ConstStridedValueAccess<1> ConstValueAccess; typedef StridedValueAccess<1> ValueAccess; class ConstValueRangeAccess { public: ConstValueRangeAccess(void) : m_type(DE_NULL), m_min(DE_NULL), m_max(DE_NULL) { } ConstValueRangeAccess(const VariableType &type, const Scalar *minVal, const Scalar *maxVal) : m_type(&type) , m_min(const_cast(minVal)) , m_max(const_cast(maxVal)) { } const VariableType &getType(void) const { return *m_type; } ConstValueAccess getMin(void) const { return ConstValueAccess(*m_type, m_min); } ConstValueAccess getMax(void) const { return ConstValueAccess(*m_type, m_max); } // Read-only access ConstValueRangeAccess component(int compNdx) const; ConstValueRangeAccess arrayElement(int elementNdx) const; ConstValueRangeAccess member(int memberNdx) const; // Set operations - tests condition for all elements bool intersects(const ConstValueRangeAccess &other) const; bool isSupersetOf(const ConstValueRangeAccess &other) const; bool isSubsetOf(const ConstValueRangeAccess &other) const; protected: const VariableType *m_type; Scalar *m_min; // \note See note in ConstValueAccess Scalar *m_max; }; inline ConstValueRangeAccess ConstValueRangeAccess::component(int compNdx) const { return ConstValueRangeAccess(m_type->getElementType(), m_min + compNdx, m_max + compNdx); } inline ConstValueRangeAccess ConstValueRangeAccess::arrayElement(int elementNdx) const { int offset = m_type->getElementScalarOffset(elementNdx); return ConstValueRangeAccess(m_type->getElementType(), m_min + offset, m_max + offset); } inline ConstValueRangeAccess ConstValueRangeAccess::member(int memberNdx) const { int offset = m_type->getMemberScalarOffset(memberNdx); return ConstValueRangeAccess(m_type->getMembers()[memberNdx].getType(), m_min + offset, m_max + offset); } class ValueRangeAccess : public ConstValueRangeAccess { public: ValueRangeAccess(const VariableType &type, Scalar *minVal, Scalar *maxVal) : ConstValueRangeAccess(type, minVal, maxVal) { } // Read-write access ValueAccess getMin(void) { return ValueAccess(*m_type, m_min); } ValueAccess getMax(void) { return ValueAccess(*m_type, m_max); } ValueRangeAccess component(int compNdx); ValueRangeAccess arrayElement(int elementNdx); ValueRangeAccess member(int memberNdx); }; inline ValueRangeAccess ValueRangeAccess::component(int compNdx) { return ValueRangeAccess(m_type->getElementType(), m_min + compNdx, m_max + compNdx); } inline ValueRangeAccess ValueRangeAccess::arrayElement(int elementNdx) { int offset = m_type->getElementScalarOffset(elementNdx); return ValueRangeAccess(m_type->getElementType(), m_min + offset, m_max + offset); } inline ValueRangeAccess ValueRangeAccess::member(int memberNdx) { int offset = m_type->getMemberScalarOffset(memberNdx); return ValueRangeAccess(m_type->getMembers()[memberNdx].getType(), m_min + offset, m_max + offset); } class ValueRange { public: ValueRange(const VariableType &type); ValueRange(const VariableType &type, const ConstValueAccess &minVal, const ConstValueAccess &maxVal); ValueRange(const VariableType &type, const Scalar *minVal, const Scalar *maxVal); ValueRange(ConstValueRangeAccess other); ~ValueRange(void); const VariableType &getType(void) const { return m_type; } ValueAccess getMin(void) { return ValueAccess(m_type, getMinPtr()); } ValueAccess getMax(void) { return ValueAccess(m_type, getMaxPtr()); } ConstValueAccess getMin(void) const { return ConstValueAccess(m_type, getMinPtr()); } ConstValueAccess getMax(void) const { return ConstValueAccess(m_type, getMaxPtr()); } ValueRangeAccess asAccess(void) { return ValueRangeAccess(m_type, getMinPtr(), getMaxPtr()); } ConstValueRangeAccess asAccess(void) const { return ConstValueRangeAccess(m_type, getMinPtr(), getMaxPtr()); } operator ConstValueRangeAccess(void) const { return asAccess(); } operator ValueRangeAccess(void) { return asAccess(); } static void computeIntersection(ValueRangeAccess dst, const ConstValueRangeAccess &a, const ConstValueRangeAccess &b); static void computeIntersection(ValueRange &dst, const ConstValueRangeAccess &a, const ConstValueRangeAccess &b); private: const Scalar *getMinPtr(void) const { return m_min.empty() ? DE_NULL : &m_min[0]; } const Scalar *getMaxPtr(void) const { return m_max.empty() ? DE_NULL : &m_max[0]; } Scalar *getMinPtr(void) { return m_min.empty() ? DE_NULL : &m_min[0]; } Scalar *getMaxPtr(void) { return m_max.empty() ? DE_NULL : &m_max[0]; } VariableType m_type; std::vector m_min; std::vector m_max; }; template class ValueStorage { public: ValueStorage(void); ValueStorage(const VariableType &type); void setStorage(const VariableType &type); StridedValueAccess getValue(const VariableType &type) { return StridedValueAccess(type, &m_value[0]); } ConstStridedValueAccess getValue(const VariableType &type) const { return ConstStridedValueAccess(type, &m_value[0]); } private: ValueStorage(const ValueStorage &other); ValueStorage operator=(const ValueStorage &other); std::vector m_value; }; template ValueStorage::ValueStorage(void) { } template ValueStorage::ValueStorage(const VariableType &type) { setStorage(type); } template void ValueStorage::setStorage(const VariableType &type) { m_value.resize(type.getScalarSize() * Stride); } class VariableValue { public: VariableValue(const Variable *variable) : m_variable(variable), m_storage(m_variable->getType()) { } ~VariableValue(void) { } const Variable *getVariable(void) const { return m_variable; } ValueAccess getValue(void) { return m_storage.getValue(m_variable->getType()); } ConstValueAccess getValue(void) const { return m_storage.getValue(m_variable->getType()); } VariableValue(const VariableValue &other); VariableValue &operator=(const VariableValue &other); private: const VariableType &getType(void) const { return m_variable->getType(); } const Variable *m_variable; ValueStorage<1> m_storage; }; } // namespace rsg #endif // _RSGVARIABLEVALUE_HPP