Add FieldOffsets class

This commit is contained in:
Jérôme Leclercq 2020-08-04 01:33:52 +02:00
parent 7736312c2f
commit 7fd3264d08
4 changed files with 356 additions and 0 deletions

View File

@ -309,6 +309,40 @@ namespace Nz
SamplerWrap_Max = SamplerWrap_Repeat
};
enum StructFieldType
{
StructFieldType_Bool1,
StructFieldType_Bool2,
StructFieldType_Bool3,
StructFieldType_Bool4,
StructFieldType_Float1,
StructFieldType_Float2,
StructFieldType_Float3,
StructFieldType_Float4,
StructFieldType_Double1,
StructFieldType_Double2,
StructFieldType_Double3,
StructFieldType_Double4,
StructFieldType_Int1,
StructFieldType_Int2,
StructFieldType_Int3,
StructFieldType_Int4,
StructFieldType_UInt1,
StructFieldType_UInt2,
StructFieldType_UInt3,
StructFieldType_UInt4,
StructFieldType_Max = StructFieldType_UInt4
};
enum StructLayout
{
StructLayout_Packed,
StructLayout_Std140,
StructLayout_Max = StructLayout_Std140
};
enum StencilOperation
{
StencilOperation_Decrement,

View File

@ -0,0 +1,52 @@
// Copyright (C) 2019 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_FIELDOFFSETS_HPP
#define NAZARA_FIELDOFFSETS_HPP
#include <Nazara/Utility/Config.hpp>
#include <Nazara/Utility/Enums.hpp>
namespace Nz
{
class NAZARA_UTILITY_API FieldOffsets
{
public:
inline FieldOffsets(StructLayout layout);
FieldOffsets(const FieldOffsets&) = default;
FieldOffsets(FieldOffsets&&) = default;
~FieldOffsets() = default;
std::size_t AddField(StructFieldType type);
std::size_t AddFieldArray(StructFieldType type, std::size_t arraySize);
std::size_t AddMatrix(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor);
std::size_t AddMatrixArray(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor, std::size_t arraySize);
std::size_t AddStruct(const FieldOffsets& fieldStruct);
std::size_t AddStructArray(const FieldOffsets& fieldStruct, std::size_t arraySize);
inline std::size_t GetLargestFieldAlignement() const;
inline std::size_t GetSize() const;
FieldOffsets& operator=(const FieldOffsets&) = default;
FieldOffsets& operator=(FieldOffsets&&) = default;
static std::size_t GetAlignement(StructLayout layout, StructFieldType fieldType);
static std::size_t GetCount(StructFieldType fieldType);
static std::size_t GetSize(StructFieldType fieldType);
private:
static inline std::size_t Align(std::size_t source, std::size_t alignment);
std::size_t m_largestFieldAlignment;
std::size_t m_offsetRounding;
std::size_t m_size;
StructLayout m_layout;
};
}
#include <Nazara/Utility/FieldOffsets.inl>
#endif // NAZARA_FIELDOFFSETS_HPP

View File

@ -0,0 +1,169 @@
// Copyright (C) 2019 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/FieldOffsets.hpp>
#include <cassert>
#include <memory>
#include <Nazara/Utility/Debug.hpp>
namespace Nz
{
inline FieldOffsets::FieldOffsets(StructLayout layout) :
m_largestFieldAlignment(1),
m_offsetRounding(1),
m_size(0),
m_layout(layout)
{
}
inline std::size_t FieldOffsets::GetLargestFieldAlignement() const
{
return m_largestFieldAlignment;
}
inline std::size_t FieldOffsets::GetSize() const
{
return m_size;
}
inline std::size_t FieldOffsets::GetAlignement(StructLayout layout, StructFieldType fieldType)
{
switch (layout)
{
case StructLayout_Packed:
return 1;
case StructLayout_Std140:
{
switch (fieldType)
{
case StructFieldType_Bool1:
case StructFieldType_Float1:
case StructFieldType_Int1:
case StructFieldType_UInt1:
return 4;
case StructFieldType_Bool2:
case StructFieldType_Float2:
case StructFieldType_Int2:
case StructFieldType_UInt2:
return 2 * 4;
case StructFieldType_Bool3:
case StructFieldType_Float3:
case StructFieldType_Int3:
case StructFieldType_UInt3:
case StructFieldType_Bool4:
case StructFieldType_Float4:
case StructFieldType_Int4:
case StructFieldType_UInt4:
return 4 * 4;
case StructFieldType_Double1:
return 8;
case StructFieldType_Double2:
return 2 * 8;
case StructFieldType_Double3:
case StructFieldType_Double4:
return 4 * 8;
}
}
}
return 0;
}
inline std::size_t FieldOffsets::GetCount(StructFieldType fieldType)
{
switch (fieldType)
{
case StructFieldType_Bool1:
case StructFieldType_Double1:
case StructFieldType_Float1:
case StructFieldType_Int1:
case StructFieldType_UInt1:
return 1;
case StructFieldType_Bool2:
case StructFieldType_Double2:
case StructFieldType_Float2:
case StructFieldType_Int2:
case StructFieldType_UInt2:
return 2;
case StructFieldType_Bool3:
case StructFieldType_Double3:
case StructFieldType_Float3:
case StructFieldType_Int3:
case StructFieldType_UInt3:
return 3;
case StructFieldType_Bool4:
case StructFieldType_Double4:
case StructFieldType_Float4:
case StructFieldType_Int4:
case StructFieldType_UInt4:
return 4;
}
return 0;
}
inline std::size_t FieldOffsets::GetSize(StructFieldType fieldType)
{
switch (fieldType)
{
case StructFieldType_Bool1:
case StructFieldType_Float1:
case StructFieldType_Int1:
case StructFieldType_UInt1:
return 4;
case StructFieldType_Bool2:
case StructFieldType_Float2:
case StructFieldType_Int2:
case StructFieldType_UInt2:
return 2 * 4;
case StructFieldType_Bool3:
case StructFieldType_Float3:
case StructFieldType_Int3:
case StructFieldType_UInt3:
return 3 * 4;
case StructFieldType_Bool4:
case StructFieldType_Float4:
case StructFieldType_Int4:
case StructFieldType_UInt4:
return 4 * 4;
case StructFieldType_Double1:
return 8;
case StructFieldType_Double2:
return 2 * 8;
case StructFieldType_Double3:
return 3 * 8;
case StructFieldType_Double4:
return 4 * 8;
}
return 0;
}
inline std::size_t FieldOffsets::Align(std::size_t source, std::size_t alignment)
{
if (source == 0)
return source;
assert(alignment > 0);
return ((source + alignment - 1) / alignment) * alignment;
}
}
#include <Nazara/Utility/DebugOff.hpp>

View File

@ -0,0 +1,101 @@
// Copyright (C) 2019 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/FieldOffsets.hpp>
#include <algorithm>
#include <cassert>
#include <Nazara/Utility/Debug.hpp>
namespace Nz
{
std::size_t FieldOffsets::AddField(StructFieldType type)
{
std::size_t fieldAlignement = GetAlignement(m_layout, type);
m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement);
std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding));
m_size = offset + GetSize(type);
m_offsetRounding = 1;
return offset;
}
std::size_t FieldOffsets::AddFieldArray(StructFieldType type, std::size_t arraySize)
{
std::size_t fieldAlignement = GetAlignement(m_layout, type);
if (m_layout == StructLayout_Std140)
fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4));
m_largestFieldAlignment = std::max(fieldAlignement, m_largestFieldAlignment);
std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding));
m_size = offset + GetSize(type) * arraySize;
m_offsetRounding = 1;
return offset;
}
std::size_t FieldOffsets::AddMatrix(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor)
{
assert(GetCount(cellType) == 1);
assert(columns >= 2 && columns <= 4);
assert(rows >= 2 && rows <= 4);
if (columnMajor)
return AddFieldArray(static_cast<StructFieldType>(cellType + rows - 1), columns);
else
return AddFieldArray(static_cast<StructFieldType>(cellType + columns - 1), rows);
}
std::size_t FieldOffsets::AddMatrixArray(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor, std::size_t arraySize)
{
assert(GetCount(cellType) == 1);
assert(columns >= 2 && columns <= 4);
assert(rows >= 2 && rows <= 4);
if (columnMajor)
return AddFieldArray(static_cast<StructFieldType>(cellType + rows - 1), columns * arraySize);
else
return AddFieldArray(static_cast<StructFieldType>(cellType + columns - 1), rows * arraySize);
}
std::size_t FieldOffsets::AddStruct(const FieldOffsets& fieldStruct)
{
std::size_t fieldAlignement = fieldStruct.GetLargestFieldAlignement();
if (m_layout == StructLayout_Std140)
fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4));
m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement);
std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding));
m_size = offset + fieldStruct.GetSize();
m_offsetRounding = std::max<std::size_t>(Align(fieldStruct.GetSize(), fieldAlignement) - fieldStruct.GetSize(), 1);
return offset;
}
std::size_t FieldOffsets::AddStructArray(const FieldOffsets& fieldStruct, std::size_t arraySize)
{
assert(arraySize > 0);
std::size_t fieldAlignement = fieldStruct.GetLargestFieldAlignement();
if (m_layout == StructLayout_Std140)
fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4));
m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement);
std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding));
m_size = offset
+ fieldStruct.GetSize() * arraySize
+ (Align(fieldStruct.GetSize(), fieldAlignement) - fieldStruct.GetSize()) * (arraySize - 1);
m_offsetRounding = fieldAlignement;
return offset;
}
}