From c89a633f59d0e393695c10f28c4ba8635eadffba Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 7 Mar 2026 11:42:46 +0000 Subject: Replace glContainer with glAllocator glContainer is no longer required, as we can use std::vector with a custom allocator which uses OpenGL buffers for storage. Minor irritation is that the mapped buffers aren't guaranteed to be flushed in the tests, so sometimes we're missing bits in a test render. --- lib/glAllocator.h | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 lib/glAllocator.h (limited to 'lib/glAllocator.h') 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 +#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 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(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); + } + + [[nodiscard]] GLuint + getNameFor(const_pointer ptr) const + { + const auto itr = buffers->find(ptr); + if (itr != buffers->end()) { + return itr->second; + } + return 0; + } + + template C> + [[nodiscard]] + GLuint + getNameFor(const C & container) const + { + return getNameFor(container.data()); + } + + bool operator==(const glAllocator &) const = default; + + private: + using BufferMap = std::flat_map; + std::shared_ptr buffers = std::make_shared(); + }; +} + +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