diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/collections.h | 6 | ||||
| -rw-r--r-- | lib/glAllocator.h | 90 | ||||
| -rw-r--r-- | lib/glArrays.cpp | 14 | ||||
| -rw-r--r-- | lib/glArrays.h | 4 | ||||
| -rw-r--r-- | lib/glContainer.h | 496 | ||||
| -rw-r--r-- | lib/gl_traits.h | 84 |
6 files changed, 145 insertions, 549 deletions
diff --git a/lib/collections.h b/lib/collections.h index e182af5..3c80125 100644 --- a/lib/collections.h +++ b/lib/collections.h @@ -10,10 +10,8 @@ #include <vector> template<typename T, typename E> -concept SequentialCollection = requires(T c) { - { c.size() } -> std::integral; - { c.data() } -> std::same_as<const E *>; -}; +concept SequentialCollection + = std::ranges::contiguous_range<T> && std::is_same_v<const E, const typename T::value_type>; template<typename T> concept IterableCollection = std::is_same_v<decltype(std::declval<T>().begin()), decltype(std::declval<T>().end())>; diff --git a/lib/glAllocator.h b/lib/glAllocator.h new file mode 100644 index 0000000..a9015da --- /dev/null +++ b/lib/glAllocator.h @@ -0,0 +1,90 @@ +#include <concepts> +#include <flat_map> +#include <glad/gl.h> +#include <memory> +#include <stream_support.h> +#include <vector> + +namespace Detail { + template<typename T> class glAllocator; + template<typename C, typename T> + concept IsGlBufferAllocated = requires(const C & container) { + { container.get_allocator() } -> std::same_as<glAllocator<T>>; + }; + + template<typename T> class glAllocator { + public: + // NOLINTBEGIN(readability-identifier-naming) - STL like + using pointer = T *; + using const_pointer = const T *; + using value_type = T; + + // NOLINTEND(readability-identifier-naming) + + pointer + allocate(size_t count) + { + constexpr static GLbitfield MAPPING_FLAGS + = GL_MAP_WRITE_BIT | GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; + constexpr static GLbitfield STORAGE_FLAGS = GL_DYNAMIC_STORAGE_BIT | MAPPING_FLAGS; + GLuint name = 0; + glCreateBuffers(1, &name); + const auto size = static_cast<GLsizeiptr>(count * sizeof(T)); + glNamedBufferStorage(name, size, nullptr, STORAGE_FLAGS); + const auto data = static_cast<pointer>(glMapNamedBufferRange(name, 0, size, MAPPING_FLAGS)); + if (!data) { + glDeleteBuffers(1, &name); + throw std::bad_alloc(); + } + buffers->emplace(data, name); + return data; + } + + void + deallocate(const_pointer ptr, size_t) + { + const auto itr = buffers->find(ptr); + glUnmapNamedBuffer(itr->second); + glDeleteBuffers(1, &itr->second); + buffers->erase(itr); + } + + [[nodiscard]] GLuint + getNameFor(const_pointer ptr) const + { + const auto itr = buffers->find(ptr); + if (itr != buffers->end()) { + return itr->second; + } + return 0; + } + + template<IsGlBufferAllocated<T> C> + [[nodiscard]] + GLuint + getNameFor(const C & container) const + { + return getNameFor(container.data()); + } + + bool operator==(const glAllocator &) const = default; + + private: + using BufferMap = std::flat_map<const_pointer, GLuint>; + std::shared_ptr<BufferMap> buffers = std::make_shared<BufferMap>(); + }; +} + +template<typename T> +// NOLINTNEXTLINE(readability-identifier-naming) - OpenGL like +using glVector = std::vector<T, typename std::allocator_traits<Detail::glAllocator<T>>::allocator_type>; + +template<typename C> +GLuint +operator*(const C & container) + requires Detail::IsGlBufferAllocated<C, typename C::value_type> +{ + return container.get_allocator().getNameFor(container); +} + +static_assert(Detail::IsGlBufferAllocated<glVector<int>, int>); diff --git a/lib/glArrays.cpp b/lib/glArrays.cpp deleted file mode 100644 index cb12f91..0000000 --- a/lib/glArrays.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "glArrays.h" -#include <type_traits> - -// Specialisations (glBuffer is an example of the typedef) -static_assert(std::is_nothrow_default_constructible_v<glBuffer>); -static_assert(!std::is_trivially_default_constructible_v<glBuffer>); -static_assert(std::is_nothrow_destructible_v<glBuffer>); -static_assert(!std::is_trivially_destructible_v<glBuffer>); -static_assert(std::is_default_constructible_v<glBuffer>); -static_assert(!std::is_copy_constructible_v<glBuffer>); -static_assert(!std::is_copy_assignable_v<glBuffer>); -static_assert(std::is_nothrow_move_constructible_v<glBuffer>); -static_assert(std::is_nothrow_move_assignable_v<glBuffer>); -static_assert(sizeof(glBuffer) == sizeof(GLuint)); diff --git a/lib/glArrays.h b/lib/glArrays.h index 48bd577..1cf2fbf 100644 --- a/lib/glArrays.h +++ b/lib/glArrays.h @@ -119,10 +119,6 @@ struct glManagedArray : public std::array<Named, N> { }; // NOLINTBEGIN(readability-identifier-naming) -template<size_t N> using glVertexArrays = glManagedArray<Detail::glNamed, N, &glGenVertexArrays, &glDeleteVertexArrays>; -using glVertexArray = glManagedSingle<Detail::glNamed, &glGenVertexArrays, &glDeleteVertexArrays>; -template<size_t N> using glBuffers = glManagedArray<Detail::glNamed, N, &glGenBuffers, &glDeleteBuffers>; -using glBuffer = glManagedSingle<Detail::glNamed, &glGenBuffers, &glDeleteBuffers>; template<size_t N> using glFrameBuffers = glManagedArray<Detail::glNamed, N, &glGenFramebuffers, &glDeleteFramebuffers>; using glFrameBuffer = glManagedSingle<Detail::glNamed, &glGenFramebuffers, &glDeleteFramebuffers>; template<size_t N> diff --git a/lib/glContainer.h b/lib/glContainer.h deleted file mode 100644 index 4119ef5..0000000 --- a/lib/glContainer.h +++ /dev/null @@ -1,496 +0,0 @@ -#pragma once - -#include "glArrays.h" -#include <cassert> -#include <span> -#include <stdexcept> -#include <utility> -#include <vector> - -static_assert(GL_READ_ONLY < GL_READ_WRITE); -static_assert(GL_WRITE_ONLY < GL_READ_WRITE); - -template<typename T> class glContainer { -public: - using span = std::span<T>; - using const_span = std::span<const T>; - using value_type = T; - using reference_type = T &; - using const_reference_type = const T &; - using pointer_type = T *; - using const_pointer_type = const T *; - using size_type = std::size_t; - using iterator = span::iterator; - using const_iterator = const_span::iterator; - using reverse_iterator = span::reverse_iterator; - using const_reverse_iterator = const_span::reverse_iterator; - static constexpr bool is_trivial_dest = std::is_trivially_destructible_v<T>; - - explicit glContainer(GLenum target = GL_ARRAY_BUFFER) : target_ {target} - { - allocBuffer(1); - } - - ~glContainer() - requires(is_trivial_dest) - = default; - - ~glContainer() - requires(!is_trivial_dest) - { - clear(); - } - - template<template<typename, typename...> typename C> - explicit glContainer(const C<T> & src, GLenum target = GL_ARRAY_BUFFER) : target_ {target} - { - reserve(src.size()); - std::copy(src.begin(), src.end(), std::back_inserter(*this)); - } - - DEFAULT_MOVE_NO_COPY(glContainer); - - [[nodiscard]] iterator - begin() - { - map(GL_READ_WRITE); - return mkspan().begin(); - } - - [[nodiscard]] iterator - end() - { - map(GL_READ_WRITE); - return mkspan().end(); - } - - [[nodiscard]] const_iterator - begin() const - { - map(GL_READ_ONLY); - return mkcspan().begin(); - } - - [[nodiscard]] const_iterator - end() const - { - map(GL_READ_ONLY); - return mkcspan().end(); - } - - [[nodiscard]] const_iterator - cbegin() const - { - map(GL_READ_ONLY); - return mkcspan().begin(); - } - - [[nodiscard]] const_iterator - cend() const - { - map(GL_READ_ONLY); - return mkcspan().end(); - } - - [[nodiscard]] reverse_iterator - rbegin() - { - map(GL_READ_WRITE); - return mkspan().rbegin(); - } - - [[nodiscard]] reverse_iterator - rend() - { - map(GL_READ_WRITE); - return mkspan().rend(); - } - - [[nodiscard]] const_reverse_iterator - rbegin() const - { - map(GL_READ_ONLY); - return mkcspan().rbegin(); - } - - [[nodiscard]] const_reverse_iterator - rend() const - { - map(GL_READ_ONLY); - return mkcspan().rend(); - } - - [[nodiscard]] const_reverse_iterator - crbegin() const - { - map(GL_READ_ONLY); - return mkcspan().rbegin(); - } - - [[nodiscard]] const_reverse_iterator - crend() const - { - map(GL_READ_ONLY); - return mkcspan().rend(); - } - - [[nodiscard]] const auto & - bufferName() const - { - return buffer_; - } - - [[nodiscard]] size_type - size() const - { - return size_; - } - - void - at(size_type pos, const T & value) - { - if (pos >= size()) { - throw std::out_of_range {__FUNCTION__}; - } - if (data_) { - mkspan()[pos] = value; - } - else { - glBindBuffer(target_, buffer_); - glBufferSubData(target_, static_cast<GLintptr>(pos * sizeof(T)), sizeof(value), &value); - glBindBuffer(target_, 0); - } - } - - [[nodiscard]] reference_type - at(size_type pos) - { - if (pos >= size()) { - throw std::out_of_range {__FUNCTION__}; - } - map(GL_READ_WRITE); - return mkspan()[pos]; - } - - [[nodiscard]] const_reference_type - at(size_type pos) const - { - if (pos >= size()) { - throw std::out_of_range {__FUNCTION__}; - } - map(GL_READ_ONLY); - return mkcspan()[pos]; - } - - [[nodiscard]] reference_type - operator[](size_type pos) - { - map(GL_READ_WRITE); - return mkspan()[pos]; - } - - [[nodiscard]] const_reference_type - operator[](size_type pos) const - { - map(GL_READ_ONLY); - return mkcspan()[pos]; - } - - [[nodiscard]] pointer_type - data() - { - map(GL_READ_WRITE); - return data_; - } - - [[nodiscard]] const_pointer_type - data() const - { - map(GL_READ_ONLY); - return data_; - } - - [[nodiscard]] reference_type - front() - { - map(GL_READ_WRITE); - return mkspan().front(); - } - - [[nodiscard]] reference_type - back() - { - map(GL_READ_WRITE); - return mkspan().back(); - } - - [[nodiscard]] const_reference_type - front() const - { - map(GL_READ_ONLY); - return mkcspan().front(); - } - - [[nodiscard]] const_reference_type - back() const - { - map(GL_READ_ONLY); - return mkcspan().back(); - } - - [[nodiscard]] bool - empty() const - { - return !size(); - } - - [[nodiscard]] size_type - capacity() const - { - return capacity_; - } - - void - unmap() const - { - if (data_) { - glBindBuffer(target_, buffer_); - glUnmapBuffer(target_); - glBindBuffer(target_, 0); - data_ = {}; - access_ = {}; - } - } - - void - reserve(size_type newCapacity) - { - if (newCapacity <= capacity_) { - return; - } - newCapacity = std::max(newCapacity, capacity_ * 2); - - std::vector<T> existing; - existing.reserve(size_); - std::move(begin(), end(), std::back_inserter(existing)); - allocBuffer(newCapacity); - std::move(existing.begin(), existing.end(), begin()); - } - - void - resize(size_type newSize) - requires std::is_default_constructible_v<T> - { - if (newSize == size_) { - return; - } - - if (const auto maintain = std::min(newSize, size_)) { - std::vector<T> existing; - const auto maintaind = static_cast<typename decltype(existing)::difference_type>(maintain); - existing.reserve(maintain); - std::move(begin(), end(), std::back_inserter(existing)); - allocBuffer(newSize); - mapForAdd(); - std::move(existing.begin(), existing.begin() + maintaind, begin()); - } - else { - allocBuffer(newSize); - mapForAdd(); - } - if (const auto prevSize = setSize(newSize); newSize > prevSize) { - for (auto & uninitialised : mkspan().subspan(prevSize, newSize - prevSize)) { - new (&uninitialised) T {}; - } - } - } - - void - shrink_to_fit() - { - if (capacity_ <= size_) { - return; - } - - std::vector<T> existing; - existing.reserve(size_); - map(is_trivial_dest ? GL_READ_ONLY : GL_READ_WRITE); - std::move(begin(), end(), std::back_inserter(existing)); - allocBuffer(size_); - map(GL_READ_WRITE); - std::move(existing.begin(), existing.end(), begin()); - } - - void - clear() noexcept(is_trivial_dest) - { - if constexpr (!is_trivial_dest) { - map(GL_READ_WRITE); - std::for_each(begin(), end(), [](auto && v) { - v.~T(); - }); - } - setSize(0); - } - - template<typename... P> - reference_type - emplace_back(P &&... ps) - requires std::is_constructible_v<T, P...> - { - auto newSize = size_ + 1; - reserve(newSize); - mapForAdd(); - new (&*end()) T {std::forward<P>(ps)...}; - setSize(newSize); - return back(); - } - - template<typename... P> - iterator - emplace(iterator pos, P &&... ps) - requires std::is_nothrow_constructible_v<T, P...> - { - auto newSize = size_ + 1; - const auto idx = pos - begin(); - reserve(newSize); - mapForAdd(); - pos = begin() + idx; - std::move_backward(pos, end(), end() + 1); - pos->~T(); - new (&*pos) T {std::forward<P>(ps)...}; - setSize(newSize); - return pos; - } - - reference_type - push_back(T p) - requires std::is_move_constructible_v<T> - { - auto newSize = size_ + 1; - reserve(newSize); - mapForAdd(); - new (&*end()) T {std::move(p)}; - setSize(newSize); - return back(); - } - - iterator - insert(iterator pos, T p) - requires std::is_nothrow_move_constructible_v<T> - { - auto newSize = size_ + 1; - const auto idx = pos - begin(); - reserve(newSize); - mapForAdd(); - pos = begin() + idx; - std::move_backward(pos, end(), end() + 1); - pos->~T(); - new (&*pos) T {std::move(p)}; - setSize(newSize); - return pos; - } - - void - pop_back() - { - if constexpr (!is_trivial_dest) { - map(GL_READ_WRITE); - back().~T(); - } - --size_; - } - - void - erase(iterator pos) - { - erase(pos, pos + 1); - } - - void - erase(iterator pos, iterator to) - { - const auto eraseSize = to - pos; - map(GL_READ_WRITE); - std::move(to, end(), pos); - if constexpr (!is_trivial_dest) { - std::for_each(end() - eraseSize, end(), [](auto && v) { - v.~T(); - }); - } - setSize(size_ - static_cast<size_type>(eraseSize)); - } - -protected: - size_type - setSize(size_type s) - { - return std::exchange(size_, s); - } - - void - allocBuffer(size_type newCapacity) - { - if (newCapacity == 0) { - return allocBuffer(1); - } - glBindBuffer(target_, buffer_); - glBufferData(target_, static_cast<GLsizeiptr>(sizeof(T) * newCapacity), nullptr, GL_DYNAMIC_DRAW); - glBindBuffer(target_, 0); - capacity_ = newCapacity; - data_ = {}; - access_ = {}; - } - - void - map(GLenum access) const - { - if (size_ > 0) { - mapMode(access); - } - } - - void - mapForAdd() const - { - if (!data_) { - mapMode(GL_READ_WRITE); - } - } - - void - mapMode(GLenum access) const - { - if (data_ && access_ < access) { - unmap(); - } - if (!data_) { - glBindBuffer(target_, buffer_); - data_ = static_cast<T *>(glMapBuffer(target_, access)); - glBindBuffer(target_, 0); - assert(data_); - access_ = access; - } - } - - span - mkspan() const - { - assert(!size_ || data_); - return span {data_, size_}; - } - - const_span - mkcspan() const - { - assert(!size_ || data_); - return const_span {data_, size_}; - } - - glBuffer buffer_; - GLenum target_; - std::size_t capacity_ {}; - std::size_t size_ {}; - mutable T * data_; - mutable GLenum access_ {}; -}; diff --git a/lib/gl_traits.h b/lib/gl_traits.h index b3c6909..35ae9e8 100644 --- a/lib/gl_traits.h +++ b/lib/gl_traits.h @@ -14,27 +14,33 @@ struct gl_traits_base { }; struct gl_traits_float : public gl_traits_base { - static constexpr auto vertexAttribFunc { - [](GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer) -> GLuint { - glVertexAttribPointer(index, size, type, GL_FALSE, stride, pointer); - return 1; - }}; + template<GLenum type, GLint size> + static GLuint + vertexAttribFormatFunc(GLuint vao, GLuint index, GLuint offset) + { + glVertexArrayAttribFormat(vao, index, size, type, GL_FALSE, offset); + return 1; + } }; struct gl_traits_longfloat : public gl_traits_base { - static constexpr auto vertexAttribFunc { - [](GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer) -> GLuint { - glVertexAttribLPointer(index, size, type, stride, pointer); - return 1; - }}; + template<GLenum type, GLint size> + static GLuint + vertexAttribFormatFunc(GLuint vao, GLuint index, GLuint offset) + { + glVertexArrayAttribLFormat(vao, index, size, type, offset); + return 1; + } }; struct gl_traits_integer : public gl_traits_base { - static constexpr auto vertexAttribFunc { - [](GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer) -> GLuint { - glVertexAttribIPointer(index, size, type, stride, pointer); - return 1; - }}; + template<GLenum type, GLint size> + static GLuint + vertexAttribFormatFunc(GLuint vao, GLuint index, GLuint offset) + { + glVertexArrayAttribIFormat(vao, index, size, type, offset); + return 1; + } }; template<> struct gl_traits<glm::f32> : public gl_traits_float { @@ -44,18 +50,22 @@ template<> struct gl_traits<glm::f32> : public gl_traits_float { static constexpr std::array glUniformmFunc {&glUniformMatrix2fv, &glUniformMatrix3fv, &glUniformMatrix4fv}; static constexpr auto glTexParameterFunc {&glTexParameterf}; static constexpr auto glTexParameterfFunc {&glTexParameterfv}; + static constexpr auto vertexArrayAttribFormat {&vertexAttribFormatFunc<type, 1>}; }; template<> struct gl_traits<glm::f64> : public gl_traits_longfloat { static constexpr GLenum type {GL_DOUBLE}; + static constexpr auto vertexArrayAttribFormat {&vertexAttribFormatFunc<type, 1>}; }; template<> struct gl_traits<glm::int8> : public gl_traits_integer { static constexpr GLenum type {GL_BYTE}; + static constexpr auto vertexArrayAttribFormat {&vertexAttribFormatFunc<type, 1>}; }; template<> struct gl_traits<glm::int16> : public gl_traits_integer { static constexpr GLenum type {GL_SHORT}; + static constexpr auto vertexArrayAttribFormat {&vertexAttribFormatFunc<type, 1>}; }; template<> struct gl_traits<glm::int32> : public gl_traits_integer { @@ -64,14 +74,17 @@ template<> struct gl_traits<glm::int32> : public gl_traits_integer { static constexpr std::array glUniformvFunc {&glUniform1iv, &glUniform2iv, &glUniform3iv, &glUniform4iv}; static constexpr auto glTexParameterFunc {&glTexParameteri}; static constexpr auto glTexParameterfFunc {&glTexParameteriv}; + static constexpr auto vertexArrayAttribFormat {&vertexAttribFormatFunc<type, 1>}; }; template<> struct gl_traits<glm::uint8> : public gl_traits_integer { static constexpr GLenum type {GL_UNSIGNED_BYTE}; + static constexpr auto vertexArrayAttribFormat {&vertexAttribFormatFunc<type, 1>}; }; template<> struct gl_traits<glm::uint16> : public gl_traits_integer { static constexpr GLenum type {GL_UNSIGNED_SHORT}; + static constexpr auto vertexArrayAttribFormat {&vertexAttribFormatFunc<type, 1>}; }; template<> struct gl_traits<glm::uint32> : public gl_traits_integer { @@ -79,35 +92,44 @@ template<> struct gl_traits<glm::uint32> : public gl_traits_integer { static constexpr auto glUniformFunc {&glUniform1ui}; static constexpr std::array<decltype(&glUniform1uiv), 5> glUniformvFunc { &glUniform1uiv, &glUniform2uiv, &glUniform3uiv, &glUniform4uiv}; + static constexpr auto vertexArrayAttribFormat {&vertexAttribFormatFunc<type, 1>}; }; template<typename T, std::size_t S> struct gl_traits<std::array<T, S>> : public gl_traits<T> { static constexpr GLint size {S * gl_traits<T>::size}; - static constexpr auto vertexAttribFunc { - [](GLuint index, GLint, GLenum type, GLsizei stride, const void * pointer) -> GLuint { - const auto base = static_cast<const T *>(pointer); - for (GLuint e = 0; e < S; e++) { - glVertexAttribPointer(index + e, gl_traits<T>::size, type, GL_FALSE, stride, base + e); - } - return S; - }}; + static constexpr auto vertexArrayAttribFormat {[](GLuint vao, GLuint index, GLuint offset) { + if constexpr (std::is_pod_v<T>) { + return gl_traits<T>::template vertexAttribFormatFunc<gl_traits<T>::type, S>(vao, index, offset); + } + else { + GLuint used = 0; + for (GLuint e = 0; e < S; e++) { + used += gl_traits<T>::template vertexAttribFormatFunc<gl_traits<T>::type, 1>( + vao, index + e, offset + (e * sizeof(T))); + } + return used; + } + }}; }; template<glm::length_t L, typename T, glm::qualifier Q> struct gl_traits<glm::vec<L, T, Q>> : public gl_traits<T> { static constexpr GLint size {L}; + static constexpr auto vertexArrayAttribFormat {[](GLuint vao, GLuint index, GLuint offset) { + return gl_traits<T>::template vertexAttribFormatFunc<gl_traits<T>::type, L>(vao, index, offset); + }}; }; template<glm::length_t C, glm::length_t R, typename T, glm::qualifier Q> struct gl_traits<glm::mat<C, R, T, Q>> : public gl_traits<T> { static constexpr GLint size {C * R}; - static constexpr auto vertexAttribFunc { - [](GLuint index, GLint, GLenum type, GLsizei stride, const void * pointer) -> GLuint { - const auto base = static_cast<const T *>(pointer); - for (GLuint r = 0; r < R; r++) { - glVertexAttribPointer(index + r, C, type, GL_FALSE, stride, base + (r * C)); - } - return R; - }}; + static constexpr auto vertexArrayAttribFormat {[](GLuint vao, GLuint index, GLuint offset) { + GLuint used = 0; + for (GLuint row = 0; row < R; row++) { + used += gl_traits<T>::template vertexAttribFormatFunc<gl_traits<T>::type, C>( + vao, index + row, offset + (C * row * static_cast<GLuint>(sizeof(T)))); + } + return used; + }}; }; template<typename T> |
