rk_engine/cpp/render/vertex_format_opengles.hpp

231 lines
8.6 KiB
C++

// Copyright (C) 2023 RozK
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef RK_ENGINE_VERTEX_FORMAT_H
#define RK_ENGINE_VERTEX_FORMAT_H
#include "render_opengles.hpp"
#include <limits>
namespace rk_vertex {
#pragma pack(push, 1)
template<typename _type>
struct alignas(alignof(_type)) rk_input {
_type input;
};
template<typename _type, typename _input, bool _signed, bool _normalized>
struct alignas(alignof(_type)) rk_output {
_type output;
[[RK_FAST]]
inline void convert(
rk_input<_input> const & __restrict src) {
output = static_cast<_type>(src.input);
}
};
template<typename _type, bool _signed>
struct alignas(alignof(_type)) rk_output<_type, rk_float, _signed, true> {
_type output;
[[RK_FAST]]
inline void convert(
rk_input<rk_float> const & __restrict src) {
enum : _type { max = std::numeric_limits<_type>::max() };
output = static_cast<_type>(src.input * static_cast<float>(max));
}
};
#pragma pack(4)
template<typename _input, unsigned _cols>
struct alignas(4) rk_input_row {
rk_input<_input> input_col[_cols];
};
template<typename _output, typename _input, unsigned _cols, bool _signed, bool _normalized>
struct alignas(4) rk_output_row {
rk_output<_output, _input, _signed, _normalized> output_col[_cols];
[[RK_FAST, RK_FLATTEN, RK_UNROLLED]]
inline void convert(
rk_input_row<_input, _cols> const & __restrict src) {
for (unsigned col = 0; col < _cols; ++col) {
output_col[col].convert(src.input_col[col]);
}
}
};
template<typename _input, unsigned _cols, bool _signed, bool _normalized>
struct alignas(4) rk_output_row<rk_packed<_signed, _cols>, _input, _cols, _signed, _normalized> {
rk_output<rk_packed<_signed, _cols>, _input, _signed, _normalized> output_cols;
[[RK_FAST, RK_FLATTEN]]
inline void convert(
rk_input_row<_input, _cols> const & __restrict src) {
output_cols.convert(src);
}
};
template<typename _input, unsigned _cols, unsigned _rows>
struct alignas(4) rk_input_format {
rk_input_row<_input, _cols> input_row[_rows];
};
template<typename _output, typename _input, unsigned _cols, unsigned _rows, bool _signed, bool _normalized>
struct alignas(4) rk_output_format {
rk_output_row<_output, _input, _cols, _signed, _normalized> output_row[_rows];
[[RK_FAST, RK_FLATTEN, RK_UNROLLED]]
inline void convert(
rk_input_format<_input, _cols, _rows> const & __restrict src) {
for (unsigned row = 0; row < _rows; ++row) {
output_row[row].convert(src.input_row[row]);
}
}
};
template<typename _input, bool _signed, bool _normalized>
struct alignas(alignof(rk_packed<_signed, 3>)) rk_output<rk_packed<_signed, 3>, _input, _signed, _normalized> {
rk_packed<_signed, 3> output;
[[RK_FAST]]
inline void convert(
rk_input_row<_input, 3> const & __restrict src) {
typedef typename rk_packed<_signed, 3>::type packed_type;
output.packed =
((static_cast<packed_type>(src.input_col[0].input) & 1023)) |
((static_cast<packed_type>(src.input_col[1].input) & 1023) << 10) |
((static_cast<packed_type>(src.input_col[2].input) & 1023) << 20);
}
};
template<typename _input, bool _signed, bool _normalized>
struct alignas(alignof(rk_packed<_signed, 4>)) rk_output<rk_packed<_signed, 4>, _input, _signed, _normalized> {
rk_packed<_signed, 4> output;
[[RK_FAST]]
inline void convert(
rk_input_row<_input, 4> const & __restrict src) {
typedef typename rk_packed<_signed, 4>::type packed_type;
output.packed =
((static_cast<packed_type>(src.input_col[0].input) & 1023)) |
((static_cast<packed_type>(src.input_col[1].input) & 1023) << 10) |
((static_cast<packed_type>(src.input_col[2].input) & 1023) << 20) |
((static_cast<packed_type>(src.input_col[3].input) & 3) << 30);
}
};
template<>
struct alignas(alignof(rk_packed<true, 3>)) rk_output<rk_packed<true, 3>, rk_float, true, true> {
rk_packed<true, 3> output;
[[RK_FAST]]
inline void convert(
rk_input_row<rk_float, 3> const & __restrict src) {
output.packed =
((static_cast<rk_int>(src.input_col[0].input * 511.f) & 1023)) |
((static_cast<rk_int>(src.input_col[1].input * 511.f) & 1023) << 10) |
((static_cast<rk_int>(src.input_col[2].input * 511.f) & 1023) << 20);
}
};
template<>
struct alignas(alignof(rk_packed<true, 4>)) rk_output<rk_packed<true, 4>, rk_float, true, true> {
rk_packed<true, 4> output;
[[RK_FAST]]
inline void convert(
rk_input_row<rk_float, 4> const & __restrict src) {
output.packed =
((static_cast<rk_uint>(src.input_col[0].input * 511.f) & 1023)) |
((static_cast<rk_uint>(src.input_col[1].input * 511.f) & 1023) << 10) |
((static_cast<rk_uint>(src.input_col[2].input * 511.f) & 1023) << 20) |
((static_cast<rk_uint>(src.input_col[3].input) & 3) << 30);
}
};
#pragma pack(pop)
template<typename _output, typename _input, unsigned _cols, unsigned _rows, bool _signed, bool _normalized>
struct rk_format {
typedef rk_input<_input> input;
typedef rk_output<_output, input, _signed, _normalized> output;
typedef rk_input_row<_input, _cols> input_row;
typedef rk_output_row<_output, _input, _cols, _signed, _normalized> output_row;
typedef rk_input_format<_input, _cols, _rows> input_format;
typedef rk_output_format<_output, _input, _cols, _rows, _signed, _normalized> output_format;
static_assert(sizeof(input) == sizeof(_input));
static_assert(sizeof(output) == sizeof(_output));
static_assert((sizeof(input_row) % sizeof(rk_vertex_input)) == 0);
static_assert((sizeof(output_row) % sizeof(rk_vertex_output)) == 0);
static_assert((sizeof(input_format) % sizeof(rk_vertex_input)) == 0);
static_assert((sizeof(output_format) % sizeof(rk_vertex_output)) == 0);
static unsigned get_input_size() {
return sizeof(input_format);
}
static unsigned get_output_size() {
return sizeof(output_format);
}
static unsigned get_output_offset(unsigned const index) {
return index * sizeof(output_row);
}
[[RK_FAST, RK_FLATTEN]]
inline static void convert(
output_format & __restrict dst,
input_format const & __restrict src) {
dst.convert(src);
}
[[RK_HOT, RK_FAST, RK_FLATTEN]]
static void param_packer(
unsigned const count,
rk_instance_index const * const __restrict indices,
rk_param_output * __restrict _dst,
rk_param_input const * const __restrict _src) {
rk_instance_index const * const last_index = indices + count;
output_format * __restrict dst = reinterpret_cast<output_format *>(_dst);
input_format const * const __restrict src = reinterpret_cast<input_format const *>(_src);
for (rk_instance_index const * __restrict index = indices; index < last_index; ++index, ++dst) {
dst->convert(src[*index]);
}
}
};
} // namepace rk_vertex
typedef rk_vertex::rk_format<rk_float, rk_float, 3, 1, true, false> rk_vec3_float;
typedef rk_vertex::rk_format<rk_short, rk_float, 3, 1, true, false> rk_vec3_short;
typedef rk_vertex::rk_format<rk_short, rk_float, 3, 1, true, true> rk_vec3_short_norm;
typedef rk_vertex::rk_format<rk_packed<true, 3>, rk_float, 3, 1, true, false> rk_vec3_int10;
typedef rk_vertex::rk_format<rk_packed<true, 3>, rk_float, 3, 1, true, true> rk_vec3_int10_norm;
typedef rk_vertex::rk_format<rk_packed<false, 3>, rk_float, 3, 1, false, false> rk_vec3_uint10;
typedef rk_vertex::rk_format<rk_packed<false, 3>, rk_float, 3, 1, false, true> rk_vec3_uint10_norm;
typedef rk_vertex::rk_format<rk_float, rk_float, 3, 3, true, false> rk_mat3_float;
typedef rk_vertex::rk_format<rk_packed<true, 3>, rk_float, 3, 3, true, false> rk_mat3_int10;
typedef rk_vertex::rk_format<rk_packed<true, 3>, rk_float, 3, 3, true, true> rk_mat3_int10_norm;
#endif // RK_ENGINE_VERTEX_FORMAT_H