FreeValue.h#

Parent directory (types)

Two classes designed to carry values of arbitrary datatypes along with their “reflective” data (datatypes etc.) FreeValue is statically allocated but has a fixed (max) size of 64 bytes, while TypedMem stores arbitrary sized data.

Includes#

  • PVRCore/Log.h

  • PVRCore/math/MathUtils.h

  • PVRCore/types/GpuDataTypes.h

Namespaces#

Classes#

Source Code#

#pragma once
#include "PVRCore/types/GpuDataTypes.h"
#include "PVRCore/Log.h"
#include "PVRCore/math/MathUtils.h"
namespace pvr {
namespace GpuDatatypesHelper {

template<typename>
struct Metadata;

template<>
struct Metadata<char*>
{
    typedef std::array<char, 64> storagetype;
    static const GpuDatatypes dataTypeOf() { return GpuDatatypes::Float; }
    static const size_t gpuSizeOf() { return 1; }
};
template<>
struct Metadata<unsigned char*>
{
    typedef std::array<char, 64> storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::Float; }
    static size_t gpuSizeOf() { return 1; }
};
template<>
struct Metadata<const char*>
{
    typedef std::array<char, 64> storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::Float; }
    static size_t gpuSizeOf() { return 1; }
};
template<>
struct Metadata<const unsigned char*>
{
    typedef std::array<char, 64> storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::Float; }
    static size_t gpuSizeOf() { return 1; }
};
template<>
struct Metadata<double>
{
    typedef float storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::Float; }
    static size_t gpuSizeOf() { return 8; }
};
template<>
struct Metadata<float>
{
    typedef float storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::Float; }
    static size_t gpuSizeOf() { return 4; }
};
template<>
struct Metadata<int64_t>
{
    typedef int32_t storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::Integer; }
    static size_t gpuSizeOf() { return 8; }
};
template<>
struct Metadata<int32_t>
{
    typedef int32_t storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::Integer; }
    static size_t gpuSizeOf() { return 4; }
};
template<>
struct Metadata<int16_t>
{
    typedef int32_t storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::Integer; }
    static size_t gpuSizeOf() { return 2; }
};
template<>
struct Metadata<int8_t>
{
    typedef int32_t storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::Integer; }
    static size_t gpuSizeOf() { return 1; }
};
template<>
struct Metadata<uint64_t>
{
    typedef uint32_t storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::uinteger; }
    static size_t gpuSizeOf() { return 8; }
};
template<>
struct Metadata<uint32_t>
{
    typedef uint32_t storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::uinteger; }
    static size_t gpuSizeOf() { return 4; }
};
template<>
struct Metadata<uint16_t>
{
    typedef uint32_t storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::uinteger; }
    static size_t gpuSizeOf() { return 2; }
};
template<>
struct Metadata<uint8_t>
{
    typedef uint32_t storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::uinteger; }
    static size_t gpuSizeOf() { return 1; }
};
template<>
struct Metadata<glm::vec2>
{
    typedef glm::vec2 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::vec2; }
    static size_t gpuSizeOf() { return 8; }
};
template<>
struct Metadata<glm::vec3>
{
    typedef glm::vec3 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::vec3; }
    static size_t gpuSizeOf() { return 12; }
};
template<>
struct Metadata<glm::vec4>
{
    typedef glm::vec4 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::vec4; }
    static size_t gpuSizeOf() { return 16; }
};
template<>
struct Metadata<glm::ivec2>
{
    typedef glm::ivec2 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::ivec2; }
    static size_t gpuSizeOf() { return 8; }
};
template<>
struct Metadata<glm::ivec3>
{
    typedef glm::ivec3 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::ivec3; }
    static size_t gpuSizeOf() { return 12; }
};
template<>
struct Metadata<glm::ivec4>
{
    typedef glm::ivec4 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::ivec4; }
    static size_t gpuSizeOf() { return 16; }
};
template<>
struct Metadata<glm::uvec2>
{
    typedef glm::uvec2 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::uvec2; }
    static size_t gpuSizeOf() { return 8; }
};
template<>
struct Metadata<glm::uvec3>
{
    typedef glm::uvec3 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::uvec3; }
    static size_t gpuSizeOf() { return 12; }
};
template<>
struct Metadata<glm::uvec4>
{
    typedef glm::uvec4 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::uvec4; }
    static size_t gpuSizeOf() { return 16; }
};
template<>
struct Metadata<glm::bvec2>
{
    typedef glm::bvec2 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::bvec2; }
    static size_t gpuSizeOf() { return 8; }
};
template<>
struct Metadata<glm::bvec3>
{
    typedef glm::bvec3 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::bvec3; }
    static size_t gpuSizeOf() { return 12; }
};
template<>
struct Metadata<glm::bvec4>
{
    typedef glm::bvec4 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::bvec4; }
    static size_t gpuSizeOf() { return 16; }
};
template<>
struct Metadata<glm::mat2x2>
{
    typedef glm::mat2x2 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::mat2x2; }
    static size_t gpuSizeOf() { return 32; }
};
template<>
struct Metadata<glm::mat2x3>
{
    typedef glm::mat2x3 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::mat2x3; }
    static size_t gpuSizeOf() { return 32; }
};
template<>
struct Metadata<glm::mat2x4>
{
    typedef glm::mat2x4 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::mat2x4; }
    static size_t gpuSizeOf() { return 32; }
};
template<>
struct Metadata<glm::mat3x2>
{
    typedef glm::mat3x2 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::mat3x2; }
    static size_t gpuSizeOf() { return 48; }
};
template<>
struct Metadata<glm::mat3x3>
{
    typedef glm::mat3x3 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::mat3x3; }
    static size_t gpuSizeOf() { return 48; }
};
template<>
struct Metadata<glm::mat3x4>
{
    typedef glm::mat3x4 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::mat3x4; }
    static size_t gpuSizeOf() { return 48; }
};
template<>
struct Metadata<glm::mat4x2>
{
    typedef glm::mat4x2 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::mat4x2; }
    static size_t gpuSizeOf() { return 64; }
};
template<>
struct Metadata<glm::mat4x3>
{
    typedef glm::mat4x3 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::mat4x3; }
    static size_t gpuSizeOf() { return 64; }
};
template<>
struct Metadata<glm::mat4x4>
{
    typedef glm::mat4x4 storagetype;
    static GpuDatatypes dataTypeOf() { return GpuDatatypes::mat4x4; }
    static size_t gpuSizeOf() { return 64; }
};
} // namespace GpuDatatypesHelper

class FreeValueView
{
protected:
    unsigned char* value_;
    uint32_t arrayElements_;
    GpuDatatypes dataType_;
public:
    FreeValueView() : value_(0), arrayElements_(0), dataType_(GpuDatatypes::none) {}
    GpuDatatypes dataType() const { return dataType_; }

    bool isDataCompatible(const FreeValueView& rhs) const { return (dataType_ == rhs.dataType_) && (arrayElements_ == rhs.arrayElements_); }

    uint64_t dataSize() const
    {
        uint32_t isnone = (dataType_ == GpuDatatypes::none);
        return isnone ? arrayElements_ : getCpuPackedSize(dataType_, arrayElements_);
    }

    uint32_t arrayElements() const { return arrayElements_; }

    void* raw(uint32_t arrayIndex)
    {
        size_t offset = (size_t)(arrayIndex * getCpuPackedSize(dataType_));
        return value_ + offset;
    }

    const void* raw(uint32_t arrayIndex) const
    {
        size_t offset = (size_t)(arrayIndex * getCpuPackedSize(dataType_));
        return value_ + offset;
    }

    void* raw() { return value_; }
    const void* raw() const { return value_; }

    template<typename Type_>
    Type_* rawAs()
    {
        return reinterpret_cast<Type_*>(value_);
    }

    template<typename Type_>
    const Type_* rawAs() const
    {
        return reinterpret_cast<Type_*>(value_);
    }

    float* rawFloats() { return reinterpret_cast<float*>(value_); }
    const float* rawFloats() const { return reinterpret_cast<const float*>(value_); }
    int32_t* rawInts() { return reinterpret_cast<int32_t*>(value_); }
    const int32_t* rawInts() const { return reinterpret_cast<const int32_t*>(value_); }
    unsigned char* rawChars() { return value_; }
    const unsigned char* rawChars() const { return value_; }

    template<typename Type_>
    Type_& interpretValueAs(uint32_t entryIndex = 0)
    {
        return reinterpret_cast<Type_*>(value_)[entryIndex];
    }

    template<typename Type_>
    const Type_& interpretValueAs(uint32_t entryIndex = 0) const
    {
        return reinterpret_cast<const Type_*>(value_)[entryIndex];
    }
};

struct TypedMem : public FreeValueView
{
private:
    uint64_t currentSize_;

public:
    TypedMem() : currentSize_(0) {}
    ~TypedMem() { free(FreeValueView::value_); }

    void assign(const TypedMem& rhs)
    {
        uint64_t dataTypeSize = rhs.dataSize();
        allocate(rhs.dataType_, rhs.arrayElements_);
        memcpy(value_, rhs.value_, (size_t)dataTypeSize);
    }

    const TypedMem& operator=(const TypedMem& rhs) const
    {
        uint64_t dataTypeSize = rhs.dataSize();
        debug_assertion(dataTypeSize <= dataSize(), "TypedMem operator=: MISMATCHED SIZE");
        memcpy(value_, rhs.value_, (size_t)dataTypeSize);
        return *this;
    }

    TypedMem(const TypedMem& rhs) : currentSize_(0)
    {
        uint64_t dataTypeSize = rhs.dataSize();
        allocate(rhs.dataType_, rhs.arrayElements_);
        memcpy(value_, rhs.value_, (size_t)dataTypeSize);
    }

    uint64_t totalSize() const { return currentSize_; }

    void shrink(uint32_t arrayElements)
    {
        uint64_t dataTypeSize = (dataType_ == GpuDatatypes::none ? arrayElements : getCpuPackedSize(dataType_) * arrayElements);
        arrayElements_ = arrayElements;
        if (!arrayElements)
        {
            free(value_);
            value_ = 0;
        }
        else if (dataTypeSize != currentSize_)
        {
            value_ = static_cast<unsigned char*>(realloc(value_, (size_t)dataTypeSize));
        }
        currentSize_ = dataTypeSize;
    }

    void clear()
    {
        dataType_ = GpuDatatypes::none;
        arrayElements_ = 0;
    }

    void allocate(GpuDatatypes dataType, uint32_t arrayElements = 1)
    {
        uint32_t isnone = (dataType == GpuDatatypes::none);
        uint64_t dataTypeSize = isnone * arrayElements + (1 - isnone) * getCpuPackedSize(dataType, arrayElements);

        dataType_ = dataType;
        arrayElements_ = arrayElements;
        if (dataTypeSize > currentSize_)
        {
            value_ = static_cast<unsigned char*>(realloc(value_, (size_t)dataTypeSize));
            currentSize_ = dataTypeSize;
        }
    }

    template<typename Type_>
    void setValue(const Type_& rawvalue)
    {
        allocate(GpuDatatypesHelper::Metadata<Type_>::dataTypeOf(), 1);
        memcpy(value_, &rawvalue, sizeof(Type_));
    }

    template<typename Type_>
    void setValue(const Type_& rawvalue, uint32_t arrayIndex)
    {
        assertion(arrayElements_ > arrayIndex,
            "TypedMemory:: If array values "
            "are used with this class, they must be pre-allocated");
        memcpy(value_ + (arrayIndex * sizeof(Type_)), &rawvalue, sizeof(Type_));
    }

    template<typename Type_>
    void setValues(const Type_* rawvalues, uint32_t numElements, uint32_t startArrayIndex = 0)
    {
        assertion(numElements > startArrayIndex, "TypedMemory:: If array values are used with this class, they must be pre-allocated");
        uint32_t elementsSize = static_cast<uint32_t>(startArrayIndex * sizeof(Type_) + sizeof(Type_) * numElements);
        assertion(currentSize_ >= elementsSize, "TypedMemory:: If array values are used with this class, they must be pre-allocated");
        memcpy(value_ + (startArrayIndex * sizeof(Type_)), &rawvalues, sizeof(Type_) * numElements);
    }

    void setValue(const char* c_string_value)
    {
        this->dataType_ = GpuDatatypes::none;
        uint32_t sz = static_cast<uint32_t>(strlen(c_string_value));
        allocate(GpuDatatypes::none, sz + 1);
        memcpy(value_, c_string_value, sz);
        value_[sz] = 0;
    }
    void setValue(const std::string& rawvalue) { setValue(rawvalue.c_str()); }
};

struct FreeValue : public FreeValueView
{
private:
    union
    {
        double _alignment_[8];
        unsigned char chars_[64];
        int32_t integer32_[16];
        float float32_[16];
        int16_t int16_[16];
        int64_t int64_[8];
    };

public:
    FreeValue()
    {
        value_ = chars_;
        arrayElements_ = 1;
    }

    template<typename Type_>
    FreeValue(const Type_& rawvalue) : FreeValue()
    {
        setValue(rawvalue);
    }

    void setDataType(GpuDatatypes datatype) { dataType_ = datatype; }

    template<typename Type_>
    void setValue(const Type_& rawvalue)
    {
        this->dataType_ = GpuDatatypesHelper::Metadata<Type_>::dataTypeOf();

        memcpy(this->chars_, &rawvalue, sizeof(Type_));
    }

    void setValue(FreeValueView& other)
    {
        dataType_ = other.dataType();

        memcpy(chars_, other.raw(), (size_t)std::min(other.dataSize(), static_cast<uint64_t>(sizeof(chars_))));
    }

    void setValue(const char* c_string_value)
    {
        this->dataType_ = GpuDatatypes::none;
        size_t sz = strlen(c_string_value);

        memcpy(chars_, c_string_value, (size_t)std::min(sz, sizeof(chars_)));
        chars_[63] = 0;
    }

    void setValue(const std::string& rawvalue)
    {
        this->dataType_ = GpuDatatypes::none;

        memcpy(chars_, rawvalue.c_str(), std::min(sizeof(chars_), (size_t)rawvalue.length()));
        chars_[63] = 0;
    }

    void fastSet(GpuDatatypes type, char* value)
    {
        this->dataType_ = type;
        memcpy(this->chars_, value, (size_t)std::min(static_cast<uint64_t>(64), getSize(type)));
    }

    template<typename Type_>
    Type_& interpretValueAs()
    {
        return *reinterpret_cast<Type_*>(chars_);
    }

    template<typename Type_>
    const Type_& interpretValueAs() const
    {
        return *reinterpret_cast<const Type_*>(chars_);
    }

    template<typename Type_>
    Type_ castValueScalarToScalar() const
    {
        switch (dataType_)
        {
        case GpuDatatypes::Float: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<float>::storagetype>());
        case GpuDatatypes::Integer: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<int32_t>::storagetype>());
        default: Log("FreeValue: Tried to interpret matrix, std::string or vector value as scalar."); return Type_();
        }
    }

    template<typename Type_>
    Type_ castValueVectorToVector() const
    {
        switch (dataType_)
        {
        case GpuDatatypes::vec2: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::vec2>::storagetype>());
        case GpuDatatypes::vec3: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::vec3>::storagetype>());
        case GpuDatatypes::vec4: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::vec4>::storagetype>());
        case GpuDatatypes::ivec2: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::ivec2>::storagetype>());
        case GpuDatatypes::ivec3: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::ivec3>::storagetype>());
        case GpuDatatypes::ivec4: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::ivec4>::storagetype>());
        default: Log("FreeValue: Tried to interpret matrix, std::string or scalar value as vector."); return Type_();
        }
    }

    template<typename Type_>
    Type_ castValueMatrixToMatrix() const
    {
        switch (dataType_)
        {
        case GpuDatatypes::mat2x2: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::mat2x2>::storagetype>());
        case GpuDatatypes::mat2x3: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::mat2x3>::storagetype>());
        case GpuDatatypes::mat2x4: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::mat2x4>::storagetype>());
        case GpuDatatypes::mat3x2: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::mat3x2>::storagetype>());
        case GpuDatatypes::mat3x3: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::mat3x3>::storagetype>());
        case GpuDatatypes::mat3x4: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::mat3x4>::storagetype>());
        case GpuDatatypes::mat4x2: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::mat4x2>::storagetype>());
        case GpuDatatypes::mat4x3: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::mat4x3>::storagetype>());
        case GpuDatatypes::mat4x4: return Type_(interpretValueAs<GpuDatatypesHelper::Metadata<glm::mat4x4>::storagetype>());
        default: Log("FreeValue: Tried to interpret vector, std::string or scalar value as matrix."); return Type_();
        }
    }

    const char* getValueAsString() const
    {
        switch (dataType_)
        {
        case GpuDatatypes::none: return reinterpret_cast<const char*>(chars_);
        default: Log("FreeValue: Tried to interpret vector, matrix or scalar value as std::string."); return "";
        }
    }
};
} // namespace pvr