PDA

View Full Version : Playing with a C++ tuple, implementing std140 padding



Gessos Paul
11-24-2014, 10:54 AM
I just finish a tuple like implementation of std140 standard to avoid errors in structure padding.
It seems working with my GeForce (OpenGL 4.4) card, but I am not sure if it is 100% compatible with GL4.5 standard.

Please shoot me with errors and comments.

Feel free to use this code (or corrected version of this code) for any project.



#include <GL/gl.h>
#include <GL/glcorearb.h>
#include <iostream>
#include <array>
using namespace std;


//! Round up \p value to next multiple of \p roundedto.
constexpr static size_t roundedup(size_t value, size_t roundedto)
{ return (value & ~(roundedto - 1)) + ((value & (roundedto - 1)) ? roundedto : 0); }


template<typename T>
class std140_traits
{
template<typename C = T>
constexpr static typename std::enable_if<std::is_arithmetic<C>::value, size_t>::type
align_helper() { return sizeof(C); }
template<typename C = T>
constexpr static typename std::enable_if<!std::is_arithmetic<C>::value, size_t>::type
align_helper() { return C::align; }
public:
constexpr static size_t align = align_helper();
};

// declaration
template<typename Arg0, typename ...Args>
struct std140_struct_impl;
//!\internal
template<typename Arg0, typename ...Args>
class std140_struct_impl : public std140_struct_impl<Args...>
{
typedef std140_struct_impl<Args...> Next;
public:
template<int S>
constexpr static size_t offset(size_t offs)
{
return S
? Next::template offset<S - 1>(roundedup(offs, std140_traits<Arg0>::align) + sizeof(Arg0))
: roundedup(offs, std140_traits<Arg0>::align);
}
template<int S>
static typename std::conditional<S, decltype(Next::template type<S - 1>()), Arg0>::type type();
};
//!\internal
template<typename Arg0>
struct std140_struct_impl<Arg0>
{
template<int S>
constexpr static size_t offset(size_t offs)
{
static_assert(S < 1, "There is no std140_struct member with that index.");
return roundedup(offs, std140_traits<Arg0>::align) + (S ? sizeof(Arg0) : 0);
}
template<int> static Arg0 type();
};

//! std140 structure with \p Args arguments.
template<typename ...Args>
class std140_struct : private std140_struct_impl<Args...>
{
typedef std140_struct_impl<Args...> Next;
public:
//! Offset of \p S element of structure.
template<int S>
constexpr static size_t offset() { return Next::template offset<S>(0); }
//! Size of std140 structure (with padding at the end).
constexpr static size_t size = roundedup(Next::template offset<-1>(0), 16);
//! Alignment of std140 structure
constexpr static size_t align = 16;

//! Get a reference to \p S element of structure.
template<int S> auto &get()
{
return *reinterpret_cast<decltype(Next::template type<S>())*>(
reinterpret_cast<char*>(this) + offset<S>());
}
private:
char reserved[size];
};

// scalar types
typedef int32_t std140_bool; //!< std140 bool
typedef int32_t std140_int; //!< std140 int
typedef uint32_t std140_uint; //!< std140 unsigned int
typedef float std140_float; //!< std140 float
typedef double std140_double; //!< std140 double

//! std140 vector with \p T type elements and \p N size
template<typename T, size_t N>
struct std140_vector : public std::array<T, N>
{
static_assert(N > 1 && N < 5, "Number of GLSL vector elements can be 2, 3 or 4");
static_assert(std::is_same<T, std140_float>::value || std::is_same<T, std140_double>::value ||
std::is_same<T, std140_int>::value || std::is_same<T, std140_uint>::value ||
std::is_same<T, std140_bool>::value,
"Elements of GLSL vectors must be bool, int, uint, float or double");
//! Alignment of std140 vector
constexpr static size_t align = sizeof(T) * (N == 3 ? 4 : N);
};

//! std140 array with \p T type elements and \p N size
template<typename T, size_t N>
struct std140_array
{
//! Stride of std140 array elements
constexpr static size_t stride = roundedup(sizeof(T), 16);
//! Alignment of std140 array
constexpr static size_t align = roundedup(std140_traits<T>::align, 16);
//! Get a reference to \p idx element of array.
T &operator[](size_t idx) { return *reinterpret_cast<T*>(reinterpret_cast<char*>(this) + idx * stride); }
private:
char reserved[N * stride];
};

//! std140 matrix with \p T type elements, \p C columns, \p R rows and <tt>col_major = true</tt> if matrix is column major
template<typename T, size_t R, size_t C, bool col_major = true>
struct std140_matrix : public std140_array<std140_vector<T, col_major ? R : C>, col_major ? C : R>
{
static_assert(R > 1 && R < 5 && C > 1 && C < 5, "Dimensions of GLSL matrices must be 2, 3 or 4");
static_assert(std::is_same<T, std140_float>::value || std::is_same<T, std140_double>::value,
"Elements of GLSL matrices must be float or double");
};




int main()
{
typedef std140_struct<
std140_int,
std140_array<
std140_struct<
std140_vector<std140_float, 3>,
std140_float>, 4>,
std140_int,
std140_int
> holy;
holy f;
cout << holy::size << "\n";
cout << holy::offset<0>() << "\n";
cout << holy::offset<1>() << "\n";
cout << holy::offset<2>() << "\n";
cout << holy::offset<3>() << "\n";

f.get<1>()[3].get<0>()[2] = 15.001;
cout << f.get<1>()[3].get<0>()[2] << "\n";


return 0;
}