From 200b96d780598fe5ec59f2fc7e2e3eb6ac69d0de Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 15 Mar 2026 02:15:41 +0000 Subject: glAllocator revamp Remove the map of buffers, now a fat pointer containing the buffer's name. This is accessible via the container's begin/end iterator. Move the bulk of the logic out of the template, it's mostly void * from the mapping anyway. Add allocate_at_least support. --- lib/glAllocator.h | 191 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 132 insertions(+), 59 deletions(-) (limited to 'lib/glAllocator.h') diff --git a/lib/glAllocator.h b/lib/glAllocator.h index a9015da..02690c3 100644 --- a/lib/glAllocator.h +++ b/lib/glAllocator.h @@ -1,22 +1,124 @@ -#include -#include +#include "special_members.h" #include +#include #include -#include #include namespace Detail { - template class glAllocator; - template - concept IsGlBufferAllocated = requires(const C & container) { - { container.get_allocator() } -> std::same_as>; + template class glPointer { + public: + constexpr glPointer(const glPointer> & other) + requires(std::is_const_v) + : ptr {other.get()}, name {other.bufferName()} + { + } + + DEFAULT_MOVE_COPY(glPointer); + + constexpr glPointer() : ptr {nullptr}, name {0} { } + + constexpr glPointer(T * ptr, GLuint name) : ptr {ptr}, name {name} { } + + auto operator<=>(const glPointer &) const noexcept = default; + + operator T *() const noexcept + { + return ptr; + } + + operator bool() const noexcept + { + return ptr; + } + + std::ptrdiff_t + operator-(const glPointer & other) const noexcept + { + return ptr - other.ptr; + } + + T * + get() const noexcept + { + return ptr; + } + + T & + operator*() const noexcept + { + return *ptr; + } + + [[nodiscard]] + T & + operator[](std::unsigned_integral auto index) const noexcept + { + return ptr[index]; + } + + T * + operator->() const noexcept + { + return ptr; + } + + glPointer & + operator++() noexcept + { + ++ptr; + return *this; + } + + glPointer & + operator--() noexcept + { + --ptr; + return *this; + } + + [[nodiscard]] glPointer + operator+(std::integral auto offset) const noexcept + { + return {ptr + offset, name}; + } + + [[nodiscard]] glPointer + operator-(std::integral auto offset) const noexcept + { + return {ptr - offset, name}; + } + + [[nodiscard]] glPointer + operator+=(std::integral auto offset) const noexcept + { + return {ptr += offset, name}; + } + + [[nodiscard]] glPointer + operator-=(std::integral auto offset) const noexcept + { + return {ptr -= offset, name}; + } + + [[nodiscard]] GLuint + bufferName() const noexcept + { + return name; + } + + private: + T * ptr; + GLuint name; }; + std::pair allocateBuffer(size_t count, size_t objSize); + void deallocateBuffer(GLuint name); + template class glAllocator { public: // NOLINTBEGIN(readability-identifier-naming) - STL like - using pointer = T *; - using const_pointer = const T *; + using pointer = glPointer; + using const_pointer = glPointer; using value_type = T; // NOLINTEND(readability-identifier-naming) @@ -24,67 +126,38 @@ namespace Detail { 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(count * sizeof(T)); - glNamedBufferStorage(name, size, nullptr, STORAGE_FLAGS); - const auto data = static_cast(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); + auto allocated = allocateBuffer(count, sizeof(T)); + return {static_cast(allocated.first), allocated.second}; } - [[nodiscard]] GLuint - getNameFor(const_pointer ptr) const +#if (__cpp_lib_allocate_at_least >= 202302L) + std::allocation_result + allocate_at_least(size_t count) { - const auto itr = buffers->find(ptr); - if (itr != buffers->end()) { - return itr->second; - } - return 0; + count = std::min(count, 32ZU); + return {allocate(count), count}; } +#endif - template C> - [[nodiscard]] - GLuint - getNameFor(const C & container) const + void + deallocate(pointer ptr, size_t) { - return getNameFor(container.data()); + deallocateBuffer(ptr.bufferName()); } - bool operator==(const glAllocator &) const = default; - - private: - using BufferMap = std::flat_map; - std::shared_ptr buffers = std::make_shared(); + using is_always_equal = std::true_type; }; } +template struct std::iterator_traits> { + using iterator_category = std::random_access_iterator_tag; + using iterator_concept = std::contiguous_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using reference = T &; + using pointer = T *; +}; + template // NOLINTNEXTLINE(readability-identifier-naming) - OpenGL like using glVector = std::vector>::allocator_type>; - -template -GLuint -operator*(const C & container) - requires Detail::IsGlBufferAllocated -{ - return container.get_allocator().getNameFor(container); -} - -static_assert(Detail::IsGlBufferAllocated, int>); -- cgit v1.3