#include #include #include #include "VBOManager.hh" #include "common.hh" using namespace gl; template<> std::unique_ptr Singleton::instance{nullptr}; template<> std::once_flag Singleton::instance_flag{}; VBOManager::VBOManager() { } VBOManager::~VBOManager() { } VBOManager::VBOAlloc::~VBOAlloc() { if(_vbo) _vbo->free(*this); _vbo = nullptr; } VBOManager::VBOAlloc::VBOAlloc(VBOAlloc&& move) : _vbo(move._vbo), _ofs(move._ofs), _size(move._size) { move._vbo = nullptr; } VBOManager::VBOAlloc& VBOManager::VBOAlloc::operator=(VBOAlloc&& move) { _vbo = move._vbo; _ofs = move._ofs; _size = move._size; move._vbo = nullptr; return *this; } VBOManager::VBOAlloc::VBOAlloc() : _vbo(nullptr), _ofs(0), _size(0) { } VBOManager::VBOAlloc::VBOAlloc(VBO &vbo, size_t ofs, size_t size) : _vbo(&vbo), _ofs(ofs), _size(size) { } VBOManager::VBOAlloc VBOManager::alloc(size_t size, GLenum type) { for(auto& vbo : _vbos[type]) { try { return vbo.alloc(size); } catch (AllocFailed &ex) { continue; } } _vbos[type].emplace_back((size>default_size)?size:default_size, type); return _vbos[type].back().alloc(size); } VBOManager::VBO::VBO(size_t size, GLenum type) : _bufID(0) { glGenBuffers(1, &_bufID); glBindBuffer(GL_ARRAY_BUFFER, _bufID); glBufferData(GL_ARRAY_BUFFER, size, NULL, type); _allocs.emplace_back(_Entry{size, false}); } VBOManager::VBO::VBO(VBO&& move) : _bufID(move._bufID), _allocs(std::move(move._allocs)) { move._bufID = 0; } VBOManager::VBO& VBOManager::VBO::operator=(VBO&& move) { for (auto ent : _allocs) { assert(!ent.used); } if (_bufID) glDeleteBuffers(1, &_bufID); _bufID = move._bufID; move._bufID = 0; _allocs = std::move(move._allocs); return *this; } VBOManager::VBO::~VBO() { for (auto ent : _allocs) { assert(!ent.used); } if (_bufID) glDeleteBuffers(1, &_bufID); _bufID = 0; } VBOManager::VBOAlloc VBOManager::VBO::alloc(size_t size) { if (size%alignment != 0) size += (alignment - (size%alignment)); size_t pos = 0; for (auto it = _allocs.begin();it != _allocs.end();++it) { if (!it->used && (it->size >= size)) { size_t leftover = it->size - size; it->used = true; it->size = size; if (leftover > 0) _allocs.insert(++it, _Entry{leftover, false}); printf("DEBUG: VBO: Allocated %lu @ %lu in %u\n", size, pos, _bufID); return VBOAlloc(*this, pos, size); } pos += it->size; } throw AllocFailed(); } void VBOManager::VBO::free(VBOAlloc& alloc) { size_t pos = 0; for (auto it = _allocs.begin();it != _allocs.end();++it) { if (pos == alloc._ofs) { assert(it->size == alloc._size); printf("DEBUG: VBO: Freed %lu @ %lu in %u\n", alloc._size, pos, _bufID); it->used = false; if ((std::next(it) != _allocs.end()) && !std::next(it)->used) { it->size += std::next(it)->size; _allocs.erase(std::next(it)); } if ((it != _allocs.begin()) && !std::prev(it)->used) { it->size += std::prev(it)->size; _allocs.erase(std::prev(it)); } return; } pos += it->size; } }