StructuredMemory.h#
Contains a utility class which allows flexible and easy access and setting of memory that would usually be accessed as raw data.
Includes#
PVRCore/strings/StringHash.h
PVRCore/types/FreeValue.h
PVRCore/types/GpuDataTypes.h
PVRCore/types/Types.h
iomanip
sstream
Included By#
Namespaces#
Classes#
Defines#
Source Code#
#pragma once
#include "PVRCore/types/Types.h"
#include "PVRCore/types/GpuDataTypes.h"
#include "PVRCore/types/FreeValue.h"
#include "PVRCore/strings/StringHash.h"
#include <sstream>
#include <iomanip>
namespace pvr {
namespace utils {
class StructuredMemoryEntry;
class StructuredBufferView;
class StructuredMemoryDescription
{
private:
friend class StructuredMemoryEntry;
std::string _name;
std::vector<StructuredMemoryDescription> _children;
GpuDatatypes _type;
uint32_t _numArrayElements;
public:
StructuredMemoryDescription(const StructuredMemoryDescription& rhs) : _name(rhs._name), _children(rhs._children), _type(rhs._type), _numArrayElements(rhs._numArrayElements) {}
StructuredMemoryDescription(const std::string& name, uint32_t arraySize, std::initializer_list<StructuredMemoryDescription> children)
: _name(name), _children(std::move(children)), _numArrayElements(arraySize), _type(GpuDatatypes::none)
{}
StructuredMemoryDescription(std::string&& name, uint32_t arraySize, std::initializer_list<StructuredMemoryDescription> children)
: _name(std::move(name)), _children(std::move(children)), _numArrayElements(arraySize), _type(GpuDatatypes::none)
{}
StructuredMemoryDescription(std::string&& name, GpuDatatypes type) : _name(std::move(name)), _type(type), _numArrayElements(1) {}
StructuredMemoryDescription(const std::string& str, uint32_t arraySize, pvr::GpuDatatypes type) : _name(std::move(str)), _type(type), _numArrayElements(arraySize) {}
StructuredMemoryDescription() : _type(GpuDatatypes::none), _numArrayElements(1) {}
StructuredMemoryDescription(StructuredMemoryDescription&& rhs)
: _name(std::move(rhs._name)), _children(std::move(rhs._children)), _type(std::move(rhs._type)), _numArrayElements(std::move(rhs._numArrayElements))
{}
StructuredMemoryDescription& operator=(const StructuredMemoryDescription& rhs)
{
_name = rhs._name;
_children = rhs._children;
_type = rhs._type;
_numArrayElements = rhs._numArrayElements;
return *this;
}
StructuredMemoryDescription& setName(const std::string& name)
{
_name = name;
return *this;
}
StructuredMemoryDescription& setName(std::string&& name)
{
_name = std::move(name);
return *this;
}
StructuredMemoryDescription& setNumArrayElements(uint32_t numArrayElements)
{
_numArrayElements = numArrayElements;
return *this;
}
StructuredMemoryDescription& setType(GpuDatatypes type)
{
_type = type;
return *this;
}
StructuredMemoryDescription& addElement(const std::string& name, GpuDatatypes type, uint32_t numArrayElements = 1)
{
_children.emplace_back(name, numArrayElements, type);
return *this;
}
StructuredMemoryDescription& addElement(std::string& name, GpuDatatypes type, uint32_t numArrayElements = 1)
{
_children.emplace_back(name, numArrayElements, type);
return *this;
}
StructuredMemoryDescription& addElement(const StructuredMemoryDescription& smd)
{
_children.emplace_back(smd);
return *this;
}
StructuredMemoryDescription getElement(const std::string& name)
{
for (uint32_t i = 0; i < _children.size(); i++)
{
if (_children[i].getName() == name) { return _children[i]; }
}
return StructuredMemoryDescription();
}
StructuredMemoryDescription getElement(uint32_t index)
{
if (index < _children.size()) { return _children[index]; }
return StructuredMemoryDescription();
}
const std::string& getName() const { return _name; }
const GpuDatatypes getType() { return _type; }
const uint32_t getNumArrayElements() { return _numArrayElements; }
const uint32_t getNumChildren() { return static_cast<uint32_t>(_children.size()); }
};
class StructuredMemoryEntry
{
private:
friend class StructuredBufferView;
friend class StructuredBufferViewElement;
StringHash _name;
StructuredMemoryEntry* _parent;
std::vector<StructuredMemoryEntry> _childEntries; // These must never reallocate. Hence the list is non-copyable
GpuDatatypes _type;
uint32_t _baseAlignment; // The alignment requirements of this object as defined by std140. Takes into account array etc.
uint32_t _numArrayElements; // The number of array elements.
bool _variableArray; // This is the last 1st level element, so can be resized dynamically
uint64_t _size; // The minimum size of this item, including self-padding IF an arrays or structures, NOT taking into account next item alignment.
uint64_t _singleElementSize; // The minimum size of this item, including self-padding IF an arrays or structures, NOT taking into account next item alignment.
uint32_t _arrayMemberSize; // The size of each slice of this item, ALWAYS including self-padding for array or structure.
uint32_t _offset;
uint64_t _minDynamicAlignment;
void* _mappedMemory;
uint32_t _mappedDynamicSlice;
struct IsEqual
{
const StringHash& _hash;
IsEqual(const StringHash& name) : _hash(name) {}
bool operator()(const StructuredMemoryEntry& rhs) const { return _hash == rhs.getName(); }
};
void calcBaseAlignment()
{
if (isStructure())
{
_baseAlignment = 0;
for (auto& child : _childEntries)
{
child.calcBaseAlignment();
_baseAlignment = std::max(_baseAlignment, child._baseAlignment);
}
_baseAlignment = std::max(_baseAlignment, getAlignment(GpuDatatypes::vec4)); // STD140
}
else
{
_baseAlignment = getAlignment(_type);
if (_numArrayElements > 1) { _baseAlignment = std::max(_baseAlignment, getAlignment(GpuDatatypes::vec4)); }
}
}
void calcDynamicAlignment(BufferUsageFlags usage = BufferUsageFlags::UniformBuffer, const uint64_t minUboDynamicAlignment = 0, const uint64_t minSsboDynamicAlignment = 0)
{
_minDynamicAlignment = 0;
uint64_t uboAlign = 0;
uint64_t ssboAlign = 0;
// if dynamic ubo OR dynamic ssbo take the relevant alignment
if (static_cast<uint32_t>(usage & BufferUsageFlags::UniformBuffer) != 0 && minUboDynamicAlignment) { uboAlign = minUboDynamicAlignment; }
if (static_cast<uint32_t>(usage & BufferUsageFlags::StorageBuffer) != 0 && minSsboDynamicAlignment) { ssboAlign = minSsboDynamicAlignment; }
_minDynamicAlignment = std::max(uboAlign, ssboAlign);
if (isStructure())
{
for (auto& child : _childEntries) { child.calcDynamicAlignment(); }
}
}
// INTERNAL NOTE: CALL THIS ** AFTER ** CALC BASE ALIGNMENT, TO FIX THE _offset AND _size MEMBERS
void calcSizeAndOffset(const uint32_t& offset)
{
_offset = align(offset, _baseAlignment);
_offset = align(_offset, _minDynamicAlignment);
if (isStructure())
{
uint32_t tmp_offset = 0;
for (auto& child : _childEntries)
{
child.calcSizeAndOffset(tmp_offset);
tmp_offset = child.getOffset() + static_cast<uint32_t>(child.getSize());
}
// STD140: Structures are padded to their alignment so that a[n] ==> sizeof(a[0]) == sizeof[a] / n
tmp_offset = align(tmp_offset, _baseAlignment);
tmp_offset = align(tmp_offset, _minDynamicAlignment);
_arrayMemberSize = tmp_offset;
_singleElementSize = _arrayMemberSize;
tmp_offset *= _numArrayElements;
_size = tmp_offset;
}
else
{
_arrayMemberSize = getSelfAlignedArraySize(_type);
_singleElementSize = pvr::getSize(_type);
_size = _variableArray ? _arrayMemberSize * _numArrayElements : pvr::getSize(_type, _numArrayElements);
}
}
void privateInit(const StructuredMemoryDescription& desc, StructuredMemoryEntry* parent, bool firstLevel, bool isVariableArray)
{
_name = desc._name;
_numArrayElements = desc._numArrayElements;
_variableArray = isVariableArray;
_parent = parent;
this->_type = desc._type;
if (!desc._children.empty()) // isStruct
{
_childEntries.resize(desc._children.size()); // Called once
for (uint32_t i = 0; i < desc._children.size(); ++i)
{
// PASS "TRUE" TO "VARIABLEARRAY" OF THE LAST ENTRY OF THE FIRST LEVEL.
// THIS IS TO A) ALLOW SSBO VARIABLE SIZED ARRAYS.
// B) ALIGN THE SIZE OF THE WHOLE BLOCK TO CONTAIN ITS OWN PADDING
_childEntries[i].privateInit(desc._children[i], this, false, firstLevel && (i + 1 == desc._children.size()));
}
_type = GpuDatatypes::none;
}
}
void layout(BufferUsageFlags usage = BufferUsageFlags::UniformBuffer, const uint64_t minUboDynamicAlignment = 0, const uint64_t minSsboDynamicAlignment = 0)
{
calcBaseAlignment();
calcDynamicAlignment(usage, minUboDynamicAlignment, minSsboDynamicAlignment);
calcSizeAndOffset(0);
}
void setMappedMemory(void* mappedMemory, const uint32_t mappedDynamicSlice = 0)
{
_mappedMemory = mappedMemory;
_mappedDynamicSlice = mappedDynamicSlice;
}
uint32_t getMappedDynamicSlice() const { return _mappedDynamicSlice; }
void* getMappedMemory() const { return _mappedMemory; }
void fixParentPointers(StructuredMemoryEntry* parent)
{
_parent = parent;
for (auto&& child : _childEntries)
{ //
child.fixParentPointers(this);
}
}
friend void swap(StructuredBufferView& first, StructuredBufferView& second);
public:
StructuredMemoryEntry()
: _name(), _parent(0), _type(GpuDatatypes::none), _numArrayElements(0), _size(0), _arrayMemberSize(0), _singleElementSize(0), _offset(0), _mappedMemory(nullptr),
_mappedDynamicSlice(0), _baseAlignment(0), _minDynamicAlignment(0), _variableArray(0)
{}
StructuredMemoryEntry(const StructuredMemoryEntry& other)
{
_name = other._name;
_parent = other._parent;
_childEntries.reserve(other._childEntries.size());
std::copy(other._childEntries.begin(), other._childEntries.end(), back_inserter(_childEntries));
_type = other._type;
_baseAlignment = other._baseAlignment;
_numArrayElements = other._numArrayElements;
_variableArray = other._variableArray;
_size = other._size;
_singleElementSize = other._singleElementSize;
_arrayMemberSize = other._arrayMemberSize;
_offset = other._offset;
_minDynamicAlignment = other._minDynamicAlignment;
_mappedMemory = other._mappedMemory;
_mappedDynamicSlice = other._mappedDynamicSlice;
}
virtual ~StructuredMemoryEntry() {}
friend void swap(StructuredMemoryEntry& first, StructuredMemoryEntry& second)
{
std::swap(first._name, second._name);
std::swap(first._parent, second._parent);
std::swap(first._childEntries, second._childEntries);
std::swap(first._type, second._type);
std::swap(first._baseAlignment, second._baseAlignment);
std::swap(first._numArrayElements, second._numArrayElements);
std::swap(first._variableArray, second._variableArray);
std::swap(first._size, second._size);
std::swap(first._singleElementSize, second._singleElementSize);
std::swap(first._arrayMemberSize, second._arrayMemberSize);
std::swap(first._offset, second._offset);
std::swap(first._minDynamicAlignment, second._minDynamicAlignment);
std::swap(first._mappedMemory, second._mappedMemory);
std::swap(first._mappedDynamicSlice, second._mappedDynamicSlice);
}
StructuredMemoryEntry& operator=(StructuredMemoryEntry other)
{
swap(*this, other);
return *this;
}
const uint32_t getNumChildren() const { return static_cast<uint32_t>(_childEntries.size()); }
const StructuredMemoryEntry& getChild(uint32_t index) const { return _childEntries[index]; }
const StructuredMemoryEntry* getParent() const { return _parent; }
uint32_t getNumArrayElements() const { return _numArrayElements; }
bool isStructure() const { return _childEntries.size() != 0; }
bool isPrimitive() const { return !isStructure(); }
const StringHash& getName() const { return _name; }
GpuDatatypes getPrimitiveType() const { return _type; }
uint32_t getOffset() const { return _offset; }
uint32_t getArrayElementOffset(uint32_t arrayElement) const { return _offset + _arrayMemberSize * arrayElement; }
uint64_t getSize() const { return _size; }
uint64_t getSingleItemSize() const { return _singleElementSize; }
void setLastElementArraySize(uint32_t arraySize)
{
auto& child = _childEntries.back();
uint64_t oldSize = child._size;
uint64_t newSize = child._arrayMemberSize * arraySize;
debug_assertion(child._size == (child._arrayMemberSize * child._numArrayElements), "1");
child._numArrayElements = arraySize;
int64_t sizeDiff = static_cast<int64_t>(newSize) - static_cast<int64_t>(oldSize);
child._size = newSize;
_size += sizeDiff;
}
uint32_t getIndex(const StringHash& name) const
{
auto entry = std::find_if(_childEntries.begin(), _childEntries.end(), IsEqual(name));
if (entry == _childEntries.end()) { return static_cast<uint32_t>(-1); }
return static_cast<uint32_t>(entry - _childEntries.begin());
}
void init(const StructuredMemoryDescription& desc)
{
privateInit(desc, nullptr, true, false);
layout();
}
void initDynamic(const StructuredMemoryDescription& desc, BufferUsageFlags usage = BufferUsageFlags::UniformBuffer, const uint64_t minUboDynamicAlignment = 0,
const uint64_t minSsboDynamicAlignment = 0)
{
privateInit(desc, nullptr, true, false);
layout(usage, minUboDynamicAlignment, minSsboDynamicAlignment);
}
inline static void printPreamble(std::stringstream& str, uint32_t level)
{
for (uint32_t i = 0; i < level; ++i) { str << " "; }
}
void printIntoStringStream(std::stringstream& str, uint32_t level) const
{
str << "\n" << std::setw(3) << _offset << ": ";
printPreamble(str, level * 2);
str << (isStructure() ? "struct" : toString(_type)) << " " << _name.str();
if (_numArrayElements > 1) { str << "[" << _numArrayElements << "]"; }
str << ";";
if (!isStructure()) { str << "\t"; }
str << "\t baseSz:" << _size / _numArrayElements << "\t size:" << getSize() << "\t baseAlign:" << _baseAlignment << "\t nextOffset:" << _offset + getSize()
<< "\t arrayMemberSize:" << _arrayMemberSize;
if (isStructure())
{
str << "\n";
printPreamble(str, level * 2 + 5);
str << "{";
for (auto& child : _childEntries) { child.printIntoStringStream(str, level + 1); }
str << "\n";
printPreamble(str, level * 2 + 5);
str << "}";
}
}
};
class StructuredBufferView;
class StructuredBufferViewElement
{
private:
friend class StructuredBufferView;
uint32_t _offset;
void* _mappedMemory;
uint32_t _level;
uint32_t _indices[5]; // This, is the array index of each ancestor item up the chain. Is carried to children elements to enable offset calcs.
const StructuredMemoryEntry& _prototype;
StructuredBufferViewElement(const StructuredMemoryEntry& entry, uint32_t level, uint32_t elementArrayIndex, const uint32_t* parentIndices, uint32_t dynamicSlice = 0)
: _mappedMemory(nullptr), _level(level), _prototype(entry)
{
_indices[0] = elementArrayIndex;
if (parentIndices) { memcpy(_indices + 1, parentIndices, sizeof(uint32_t) * (level)); }
init(dynamicSlice);
}
void init(uint32_t dynamicSlice = 0)
{
// Get the offset INSIDE CURRENT LEVEL.
_offset = _prototype.getArrayElementOffset(_indices[0]);
const StructuredMemoryEntry* parent = _prototype.getParent();
size_t level = 1; // How many levels up we have gone
uint64_t dynamicSliceSize = 0;
uint32_t mappedDynamicSlice = 0;
while (parent) // Until we reach the root element
{
debug_assertion(parent->getNumArrayElements() > _indices[level], "StructuredBufferViewElement: Attempted out-of-bounds access in getOffset");
_offset += parent->getArrayElementOffset(_indices[level++]);
dynamicSliceSize = parent->getSize();
mappedDynamicSlice = parent->getMappedDynamicSlice();
// store the mapped memory so we only have to do this lookup once rather than each time setValue is called
_mappedMemory = parent->getMappedMemory();
parent = parent->getParent();
}
// at this point dynamicSliceSize matches the root size
debug_assertion(dynamicSlice >= mappedDynamicSlice, "StructuredBufferViewElement: Mapped dynamic slice must be greater than or equal to the current dynamic slice");
uint32_t sliceOffset = (dynamicSlice * static_cast<uint32_t>(dynamicSliceSize)) - (mappedDynamicSlice * static_cast<uint32_t>(dynamicSliceSize));
_offset += sliceOffset;
}
void* getMappedMemory()
{
debug_assertion(_mappedMemory != nullptr, "StructuredBufferViewElement: Before getting mapped memory the memory must be set.");
return _mappedMemory;
}
public:
StructuredBufferViewElement getElementByName(const StringHash& str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0)
{
return getElement(_prototype.getIndex(str), elementArrayIndex, dynamicSlice);
}
const StructuredBufferViewElement getElementByName(const StringHash& str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0) const
{
return getElement(_prototype.getIndex(str), elementArrayIndex, dynamicSlice);
}
StructuredBufferViewElement getElementByName(const std::string& str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0)
{
return getElement(_prototype.getIndex(str), elementArrayIndex, dynamicSlice);
}
const StructuredBufferViewElement getElementByName(const std::string& str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0) const
{
return getElement(_prototype.getIndex(str), elementArrayIndex, dynamicSlice);
}
StructuredBufferViewElement getElementByName(const char* str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0)
{
return getElement(_prototype.getIndex(str), elementArrayIndex, dynamicSlice);
}
const StructuredBufferViewElement getElementByName(const char* str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0) const
{
return getElement(_prototype.getIndex(str), elementArrayIndex, dynamicSlice);
}
StructuredBufferViewElement getElement(uint32_t elementIndex, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0)
{
return StructuredBufferViewElement(_prototype.getChild(elementIndex), _level + 1, elementArrayIndex, _indices, dynamicSlice);
}
const StructuredBufferViewElement getElement(uint32_t elementIndex, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0) const
{
return StructuredBufferViewElement(_prototype.getChild(elementIndex), _level + 1, elementArrayIndex, _indices, dynamicSlice);
}
const std::string& getElementNameByIndex(uint32_t elementIndex) const { return _prototype.getChild(elementIndex).getName(); }
uint32_t getIndex(const StringHash& str) { return _prototype.getIndex(str); }
uint32_t getIndex(const std::string& str) { return _prototype.getIndex(str); }
uint32_t getIndex(const char* str) { return _prototype.getIndex(str); }
uint32_t getOffset() const { return _offset; }
uint64_t getValueSize() const { return _prototype.getSingleItemSize(); }
uint64_t getArrayPaddedSize() const { return _prototype._arrayMemberSize; }
// clang-format off
#define DEFINE_SETVALUE_FOR_TYPE(ParamType)\
void setValue(const ParamType& value)\
{\
memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), &value, (size_t)getValueSize()); \
}\
\
void setValue(const ParamType* value)\
{\
memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), value, (size_t)getValueSize()); \
}
DEFINE_SETVALUE_FOR_TYPE(float)
DEFINE_SETVALUE_FOR_TYPE(uint32_t)
DEFINE_SETVALUE_FOR_TYPE(uint64_t)
DEFINE_SETVALUE_FOR_TYPE(int32_t)
DEFINE_SETVALUE_FOR_TYPE(int64_t)
DEFINE_SETVALUE_FOR_TYPE(glm::vec2)
DEFINE_SETVALUE_FOR_TYPE(glm::vec4)
DEFINE_SETVALUE_FOR_TYPE(glm::ivec2)
DEFINE_SETVALUE_FOR_TYPE(glm::ivec4)
DEFINE_SETVALUE_FOR_TYPE(glm::uvec2)
DEFINE_SETVALUE_FOR_TYPE(glm::uvec4)
DEFINE_SETVALUE_FOR_TYPE(glm::mat2x2)
DEFINE_SETVALUE_FOR_TYPE(glm::mat2x4)
DEFINE_SETVALUE_FOR_TYPE(glm::mat3x2)
DEFINE_SETVALUE_FOR_TYPE(glm::mat3x4)
DEFINE_SETVALUE_FOR_TYPE(glm::mat4x2)
DEFINE_SETVALUE_FOR_TYPE(glm::mat4x4)
#undef DEFINE_SETVALUE_FOR_TYPE
// clang-format on
void setValue(const glm::vec3& value) { memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), &value, sizeof(glm::vec3)); }
void setValue(const glm::ivec3& value) { memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), &value, sizeof(glm::ivec3)); }
void setValue(const glm::uvec3& value) { memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), &value, sizeof(glm::uvec3)); }
void setValue(const glm::vec3* value)
{
for (uint32_t i = 0; i < this->_prototype.getNumArrayElements(); ++i)
{ memcpy(static_cast<char*>(getMappedMemory()) + getOffset() + sizeof(glm::vec4) * i, value + i, sizeof(glm::vec3)); }
}
void setValue(const glm::ivec3* value)
{
for (uint32_t i = 0; i < this->_prototype.getNumArrayElements(); ++i)
{ memcpy(static_cast<char*>(getMappedMemory()) + getOffset() + sizeof(glm::ivec4) * i, value + i, sizeof(glm::ivec3)); }
}
void setValue(const glm::uvec3* value)
{
for (uint32_t i = 0; i < this->_prototype.getNumArrayElements(); ++i)
{ memcpy(static_cast<char*>(getMappedMemory()) + getOffset() + sizeof(glm::uvec4) * i, value + i, sizeof(glm::uvec3)); }
}
void setValue(const glm::mat2x3& value)
{
glm::mat2x4 newvalue(value);
memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), (const void*)&newvalue, (size_t)getValueSize());
}
void setValue(const glm::mat3x3& value)
{
glm::mat3x4 newvalue(value);
memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), (const void*)&newvalue, (size_t)getValueSize());
}
void setValue(const glm::mat4x3& value)
{
glm::mat4x4 newvalue(value);
memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), (const void*)&newvalue, (size_t)getValueSize());
}
void setValue(const glm::mat2x3* value)
{
glm::mat2x4 newvalue(*value);
memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), (const void*)&newvalue, (size_t)getValueSize());
}
void setValue(const glm::mat3x3* value)
{
glm::mat3x4 newvalue(*value);
memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), (const void*)&newvalue, (size_t)getValueSize());
}
void setValue(const glm::mat4x3* value)
{
glm::mat4x4 newvalue(*value);
memcpy(static_cast<char*>(getMappedMemory()) + getOffset(), (const void*)&newvalue, (size_t)getValueSize());
}
void setValue(const FreeValue& value)
{
if (this->_prototype.getPrimitiveType() != value.dataType() && value.dataType() != GpuDatatypes::mat3x3)
{ throw std::runtime_error("StructuredBufferView: Mismatched FreeValue datatype"); }
if (value.dataType() == GpuDatatypes::mat3x3)
{
glm::mat3x4 tmp(value.interpretValueAs<glm::mat3x3>());
memcpy((char*)getMappedMemory() + getOffset(), &tmp[0][0], (size_t)getValueSize());
}
else
{
memcpy((char*)getMappedMemory() + getOffset(), value.raw(), (size_t)getValueSize());
}
}
void setValue(const TypedMem& value)
{
debug_assertion(value.arrayElements() == 1, "Calling set value would have updated multiple elements here");
setArrayValuesStartingFromThis(value);
}
void setArrayValuesStartingFromThis(const TypedMem& value)
{
if (this->_prototype.getPrimitiveType() != value.dataType() && value.dataType() != GpuDatatypes::mat3x3)
{ throw std::runtime_error("StructuredBufferView: Mismatched FreeValue datatype"); }
if (value.arrayElements() != _prototype.getNumArrayElements()) { throw std::runtime_error("StructuredBufferView: Mismatched number of array elements"); }
if (value.dataType() == GpuDatatypes::mat3x3)
{
size_t startoff = getOffset();
for (uint32_t i = 0; i < value.arrayElements(); ++i)
{
glm::mat3x4 tmp(value.interpretValueAs<glm::mat3x3>(i));
uint64_t myoff = startoff + _prototype._arrayMemberSize * i;
uint64_t myvaluesize = getSize(value.dataType());
memcpy((char*)getMappedMemory() + (size_t)myoff, &tmp[0][0], (size_t)myvaluesize);
}
}
else
{
uint64_t myoff = getOffset();
uint64_t myvaluesize = value.dataSize();
memcpy((char*)getMappedMemory() + (size_t)myoff, value.raw(), (size_t)myvaluesize);
}
}
uint32_t getNumElements()
{
if (_prototype.isStructure()) { return _prototype.getNumChildren(); }
return 1;
}
};
class StructuredBufferView
{
private:
StructuredMemoryEntry _root;
uint32_t _numDynamicSlices;
public:
StructuredBufferView() : _numDynamicSlices(1) {}
StructuredBufferView(const StructuredBufferView& other) : _numDynamicSlices(other._numDynamicSlices), _root(other._root)
{ //
_root.fixParentPointers(0);
}
StructuredBufferView(const StructuredBufferView&& other) : _numDynamicSlices(other._numDynamicSlices), _root(std::move(other._root))
{ //
_root.fixParentPointers(0);
}
StructuredBufferView& operator=(StructuredBufferView other)
{
swap(*this, other);
_root.fixParentPointers(0);
return *this;
}
friend void swap(StructuredBufferView& first, StructuredBufferView& second)
{
swap(first._root, second._root);
std::swap(first._numDynamicSlices, second._numDynamicSlices);
first._root.fixParentPointers(0);
second._root.fixParentPointers(0);
}
void pointToMappedMemory(void* mappedMemory, const uint32_t mappedDynamicSlice = 0) { _root.setMappedMemory(mappedMemory, mappedDynamicSlice); }
uint64_t getSize() const { return getDynamicSliceSize() * _numDynamicSlices; }
uint32_t getMappedDynamicSlice() const { return _root.getMappedDynamicSlice(); }
const void* getMappedMemory() const { return _root.getMappedMemory(); }
uint64_t getDynamicSliceSize() const { return _root.getSize(); }
uint32_t getNumDynamicSlices() const { return _numDynamicSlices; }
const std::string& getName() const { return _root.getName(); }
uint32_t getDynamicSliceOffset(uint32_t dynamicSliceIndex) const { return dynamicSliceIndex * static_cast<uint32_t>(getDynamicSliceSize()); }
void init(const StructuredMemoryDescription& desc) { _root.init(desc); }
void initDynamic(const StructuredMemoryDescription& desc, uint32_t numDynamicSlices = 1, BufferUsageFlags usage = BufferUsageFlags::UniformBuffer,
const uint64_t minUboDynamicAlignment = 0, const uint64_t minSsboDynamicAlignment = 0)
{
_root.initDynamic(desc, usage, minUboDynamicAlignment, minSsboDynamicAlignment);
_numDynamicSlices = numDynamicSlices;
}
const StructuredBufferViewElement getElementByName(const StringHash& str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0) const
{
return StructuredBufferViewElement(_root, 0, 0, nullptr).getElementByName(str, elementArrayIndex, dynamicSlice);
}
StructuredBufferViewElement getElementByName(const StringHash& str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0)
{
return StructuredBufferViewElement(_root, 0, 0, nullptr).getElementByName(str, elementArrayIndex, dynamicSlice);
}
const StructuredBufferViewElement getElementByName(const std::string& str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0) const
{
return StructuredBufferViewElement(_root, 0, 0, nullptr).getElementByName(str, elementArrayIndex, dynamicSlice);
}
StructuredBufferViewElement getElementByName(const std::string& str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0)
{
return StructuredBufferViewElement(_root, 0, 0, nullptr).getElementByName(str, elementArrayIndex, dynamicSlice);
}
const StructuredBufferViewElement getElementByName(const char* str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0) const
{
return StructuredBufferViewElement(_root, 0, 0, nullptr).getElementByName(str, elementArrayIndex, dynamicSlice);
}
StructuredBufferViewElement getElementByName(const char* str, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0)
{
return StructuredBufferViewElement(_root, 0, 0, nullptr).getElementByName(str, elementArrayIndex, dynamicSlice);
}
const StructuredBufferViewElement getElement(uint32_t elementIndex, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0) const
{
return StructuredBufferViewElement(_root, 0, 0, nullptr).getElement(elementIndex, elementArrayIndex, dynamicSlice);
}
StructuredBufferViewElement getElement(uint32_t elementIndex, uint32_t elementArrayIndex = 0, uint32_t dynamicSlice = 0)
{
return StructuredBufferViewElement(_root, 0, 0, nullptr).getElement(elementIndex, elementArrayIndex, dynamicSlice);
}
std::string getElementNameByIndex(uint32_t elementIndex) { return StructuredBufferViewElement(_root, 0, 0, nullptr).getElementNameByIndex(elementIndex); }
uint32_t getNumElements() { return StructuredBufferViewElement(_root, 0, 0, nullptr).getNumElements(); }
void setLastElementArraySize(uint32_t arraySize) { return _root.setLastElementArraySize(arraySize); }
uint32_t getIndex(const StringHash& name) const { return _root.getIndex(name); }
uint32_t getIndex(const char* name) const { return _root.getIndex(name); }
uint32_t getIndex(const std::string& name) const { return _root.getIndex(name); }
std::string toString()
{
std::stringstream ss;
ss << "\n";
_root.printIntoStringStream(ss, 0);
return ss.str();
}
};
} // namespace utils
} // namespace pvr