163 lines
3.3 KiB
C++
163 lines
3.3 KiB
C++
#include <glbinding/gl/gl.h>
|
|
#include <cassert>
|
|
#include <mutex>
|
|
|
|
#include "VBOManager.hh"
|
|
#include "common.hh"
|
|
|
|
using namespace gl;
|
|
|
|
std::unique_ptr<VBOManager> VBOManager::instance{nullptr};
|
|
static std::once_flag instance_flag;
|
|
|
|
VBOManager& VBOManager::getInstance()
|
|
{
|
|
std::call_once(instance_flag, init);
|
|
return *instance;
|
|
}
|
|
|
|
void VBOManager::init()
|
|
{
|
|
instance.reset(new VBOManager{});
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|