Add an untested vbo class and helpers

This commit is contained in:
rexy712 2020-08-30 09:41:26 -07:00
parent dd57ac2c71
commit 74700fcf18
6 changed files with 650 additions and 6 deletions

View File

@ -0,0 +1,93 @@
/**
This file is a part of our_dick
Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OUR_DICK_GRAPHICS_GL_BUFFERS_HPP
#define OUR_DICK_GRAPHICS_GL_BUFFERS_HPP
#include "gl_include.hpp"
namespace graphics{
class gl_buffer;
class buffer_iface
{
protected:
mutable gl_buffer* m_bound = nullptr;
public:
buffer_iface() = default;
buffer_iface(const buffer_iface&);
buffer_iface(buffer_iface&&);
~buffer_iface();
buffer_iface& operator=(const buffer_iface&);
buffer_iface& operator=(buffer_iface&&);
bool bind(gl_buffer& b)const;
bool bind_lock(gl_buffer& b)const;
void unlock()const;
void unbind()const;
bool is_locked()const;
GLenum get_bound_id()const;
gl_buffer* get_bound_buffer()const;
};
class gl_buffer
{
friend class buffer; //access to constructor/destructor
friend class buffer_iface; //access to bind
private:
const buffer_iface* bound = nullptr; //vbo bound to this buffer
const GLenum m_buffer;
bool m_lock = false;
private:
gl_buffer(GLenum buf);
~gl_buffer() = default;
void bind(const buffer_iface* newbind);
void lock(bool b);
bool is_locked()const;
public:
GLenum get_buffer_id()const;
};
class buffer //glorified namespace for added access control
{
public:
static inline gl_buffer array{GL_ARRAY_BUFFER};
static inline gl_buffer atomic_counter{GL_ATOMIC_COUNTER_BUFFER};
static inline gl_buffer copy_read{GL_COPY_READ_BUFFER};
static inline gl_buffer copy_write{GL_COPY_WRITE_BUFFER};
static inline gl_buffer dispatch_indirect{GL_DISPATCH_INDIRECT_BUFFER};
static inline gl_buffer draw_indirect{GL_DRAW_INDIRECT_BUFFER};
static inline gl_buffer element_array{GL_ELEMENT_ARRAY_BUFFER};
static inline gl_buffer pixel_pack{GL_PIXEL_PACK_BUFFER};
static inline gl_buffer pixel_unpack{GL_PIXEL_UNPACK_BUFFER};
static inline gl_buffer query{GL_QUERY_BUFFER};
static inline gl_buffer shader_storage{GL_SHADER_STORAGE_BUFFER};
static inline gl_buffer texture{GL_TEXTURE_BUFFER};
static inline gl_buffer transform_feedback{GL_TRANSFORM_FEEDBACK_BUFFER};
static inline gl_buffer uniform{GL_UNIFORM_BUFFER};
private:
buffer() = default;
~buffer() = default;
};
}
#endif

257
include/graphics/vbo.hpp Normal file
View File

@ -0,0 +1,257 @@
/**
This file is a part of our_dick
Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OUR_DICK_GRAPHICS_VBO_HPP
#define OUR_DICK_GRAPHICS_VBO_HPP
#include "gl_include.hpp"
#include "gl_buffers.hpp"
#include <cstdlib> //size_t, ptrdiff_t
#include <utility> //exchange, swap
namespace graphics{
template<typename T>
class scoped_vbo_map;
class vbo
{
public:
enum class drawtype : GLenum{
STATIC_DRAW = GL_STATIC_DRAW,
DYNAMIC_DRAW = GL_DYNAMIC_DRAW,
STREAM_DRAW = GL_STREAM_DRAW,
STATIC_READ = GL_STATIC_READ,
DYNAMIC_READ = GL_DYNAMIC_READ,
STREAM_READ = GL_STREAM_READ,
STATIC_COPY = GL_STATIC_COPY,
DYNAMIC_COPY = GL_DYNAMIC_COPY,
STREAM_COPY = GL_STREAM_COPY,
};
enum class maptype : GLenum{
READ = GL_READ_ONLY,
WRITE = GL_WRITE_ONLY,
RW = GL_READ_WRITE,
};
private:
GLuint m_buffer;
size_t m_buffer_size;
drawtype m_buffer_type;
buffer_iface m_bi;
public:
vbo(size_t size, drawtype t);
vbo(const vbo&);
vbo(vbo&&);
~vbo();
vbo& operator=(const vbo&);
vbo& operator=(vbo&&);
bool bind(gl_buffer& b)const;
bool bind_lock(gl_buffer& b)const;
void bind_unlock()const;
void unbind()const;
void buffer(const void* data, size_t datasize);
void resize(size_t newcap);
scoped_vbo_map<void> map(gl_buffer& target, maptype m)const;
void clear();
size_t get_size()const;
size_t get_cap()const;
drawtype get_usage()const;
gl_buffer* get_bound_buffer()const;
GLenum get_bound_id()const;
private:
static void copy_buffer(const vbo& src, vbo& dest);
};
template<typename T>
class scoped_vbo_map
{
public:
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using reference = T&;
using const_reference = const T&;
using pointer = T*;
using const_pointer = const T*;
private:
pointer m_data = nullptr;
const vbo* m_owner;
public:
explicit scoped_vbo_map(const vbo& v, gl_buffer& targ, vbo::maptype m);
scoped_vbo_map(const scoped_vbo_map&) = delete;
scoped_vbo_map(scoped_vbo_map&&);
~scoped_vbo_map();
scoped_vbo_map& operator=(const scoped_vbo_map&) = delete;
scoped_vbo_map& operator=(scoped_vbo_map&&);
size_type length()const;
pointer release();
operator pointer();
operator const_pointer()const;
pointer raw();
const_pointer raw()const;
reference operator[](size_type i);
const_reference operator[](size_type i)const;
};
template<>
class scoped_vbo_map<void>
{
public:
using value_type = void;
using size_type = size_t;
using difference_type = ptrdiff_t;
using reference = void;
using const_reference = void;
using pointer = void*;
using const_pointer = const void*;
private:
pointer m_data = nullptr;
const vbo* m_owner;
public:
explicit scoped_vbo_map(const vbo& v, gl_buffer& targ, vbo::maptype m);
scoped_vbo_map(const scoped_vbo_map&) = delete;
scoped_vbo_map(scoped_vbo_map&&);
~scoped_vbo_map();
scoped_vbo_map& operator=(const scoped_vbo_map&) = delete;
scoped_vbo_map& operator=(scoped_vbo_map&&);
size_type length()const;
pointer release();
operator pointer();
operator const_pointer()const;
pointer raw();
const_pointer raw()const;
};
template<typename T>
scoped_vbo_map<T>::scoped_vbo_map(const vbo& v, gl_buffer& targ, vbo::maptype m):
m_owner(&v)
{
m_owner->bind(targ);
m_data = reinterpret_cast<pointer>(glMapBuffer(m_owner->get_bound_id(), static_cast<GLenum>(m)));
}
template<typename T>
scoped_vbo_map<T>::scoped_vbo_map(scoped_vbo_map&& m):
m_data(std::exchange(m.m_data, nullptr)),
m_owner(m.m_owner){}
template<typename T>
scoped_vbo_map<T>::~scoped_vbo_map(){
if(m_data){
glUnmapBuffer(m_owner->get_bound_id());
m_owner->bind_unlock();
}
}
template<typename T>
scoped_vbo_map<T>& scoped_vbo_map<T>::operator=(scoped_vbo_map&& m){
std::swap(m_data, m.m_data);
std::swap(m_owner, m.m_owner);
return *this;
}
template<typename T>
auto scoped_vbo_map<T>::length()const -> size_type{
GLint64 retval;
glGetBufferParameteri64v(m_owner->get_bound_id(), GL_BUFFER_MAP_LENGTH, &retval);
return retval;
}
template<typename T>
auto scoped_vbo_map<T>::release() -> pointer{
return std::exchange(m_data, nullptr);
}
template<typename T>
scoped_vbo_map<T>::operator pointer(){
return m_data;
}
template<typename T>
scoped_vbo_map<T>::operator const_pointer()const{
return m_data;
}
template<typename T>
auto scoped_vbo_map<T>::raw() -> pointer{
return m_data;
}
template<typename T>
auto scoped_vbo_map<T>::raw()const -> const_pointer{
return m_data;
}
template<typename T>
auto scoped_vbo_map<T>::operator[](size_type i) -> reference{
return m_data[i];
}
template<typename T>
auto scoped_vbo_map<T>::operator[](size_type i)const -> const_reference{
return m_data[i];
}
scoped_vbo_map<void>::scoped_vbo_map(const vbo& v, gl_buffer& targ, vbo::maptype m):
m_owner(&v)
{
m_owner->bind_lock(targ);
m_data = reinterpret_cast<pointer>(glMapBuffer(m_owner->get_bound_id(), static_cast<GLenum>(m)));
}
scoped_vbo_map<void>::scoped_vbo_map(scoped_vbo_map&& m):
m_data(std::exchange(m.m_data, nullptr)),
m_owner(m.m_owner){}
scoped_vbo_map<void>::~scoped_vbo_map(){
if(m_data){
glUnmapBuffer(m_owner->get_bound_id());
m_owner->bind_unlock();
}
}
scoped_vbo_map<void>& scoped_vbo_map<void>::operator=(scoped_vbo_map&& m){
std::swap(m_data, m.m_data);
std::swap(m_owner, m.m_owner);
return *this;
}
auto scoped_vbo_map<void>::length()const -> size_type{
GLint64 retval;
glGetBufferParameteri64v(m_owner->get_bound_id(), GL_BUFFER_MAP_LENGTH, &retval);
return retval;
}
auto scoped_vbo_map<void>::release() -> pointer{
return std::exchange(m_data, nullptr);
}
scoped_vbo_map<void>::operator pointer(){
return m_data;
}
scoped_vbo_map<void>::operator const_pointer()const{
return m_data;
}
auto scoped_vbo_map<void>::raw() -> pointer{
return m_data;
}
auto scoped_vbo_map<void>::raw()const -> const_pointer{
return m_data;
}
}
#endif

59
include/util/minmax.hpp Normal file
View File

@ -0,0 +1,59 @@
/**
This file is a part of our_dick
Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OUR_DICK_UTIL_MINMAX_HPP
#define OUR_DICK_UTIL_MINMAX_HPP
//prevents inclusion of <algorithm> which triples compile times
namespace util{
template<typename T>
struct greater {
constexpr bool operator()(const T& left, const T& right)const{
return left > right;
}
};
template<typename T>
struct less {
constexpr bool operator()(const T& left, const T& right)const{
return left < right;
}
};
template<typename T>
static constexpr T max(const T& left, const T& right){
return left > right ? left : right;
}
template<typename T>
static constexpr T min(const T& left, const T& right){
return left < right ? left : right;
}
template<typename T, typename Compare>
static constexpr T max(const T& left, const T& right, Compare cmp){
return cmp(left, right) ? left : right;
}
template<typename T, typename Compare>
static constexpr T min(const T& left, const T& right, Compare cmp){
return cmp(left, right) ? left : right;
}
}
#endif

View File

@ -22,12 +22,6 @@
namespace audio::impl{
//prevent inclusion of <algorithm> since that kills compile times
template<typename T>
static constexpr T& min(T& left, T& right){
return (left < right) ? left : right;
}
mixer::mixer(int output_channels, size_t channel_count, size_t samplerate):
m_paused(false),
m_exit(false),

111
src/graphics/gl_buffers.cpp Normal file
View File

@ -0,0 +1,111 @@
/**
This file is a part of our_dick
Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "graphics/gl_buffers.hpp"
#include "graphics/gl_include.hpp"
namespace graphics{
buffer_iface::buffer_iface(const buffer_iface&):
m_bound(nullptr){}
buffer_iface::buffer_iface(buffer_iface&& b){
if(b.m_bound)
bind(*b.m_bound);
}
buffer_iface::~buffer_iface(){
unbind();
}
buffer_iface& buffer_iface::operator=(const buffer_iface& b){
gl_buffer* tmp1 = m_bound;
gl_buffer* tmp2 = b.m_bound;
if(tmp2)
bind(*tmp2);
if(tmp1)
b.bind(*tmp1);
return *this;
}
buffer_iface& buffer_iface::operator=(buffer_iface&& b){
gl_buffer* tmp1 = m_bound;
gl_buffer* tmp2 = b.m_bound;
if(tmp2)
bind(*tmp2);
if(tmp1)
b.bind(*tmp1);
return *this;
}
bool buffer_iface::bind(gl_buffer& b)const{
if(b.is_locked())
return false;
if(m_bound)
m_bound->bind(nullptr);
m_bound = &b;
m_bound->bind(this);
return true;
}
bool buffer_iface::bind_lock(gl_buffer& b)const{
if(!bind(b))
return false;
m_bound->lock(true);
return true;
}
void buffer_iface::unlock()const{
if(m_bound)
m_bound->lock(false);
}
void buffer_iface::unbind()const{
if(m_bound){
m_bound->lock(false);
m_bound->bind(nullptr);
}
m_bound = nullptr;
}
bool buffer_iface::is_locked()const{
return m_bound && m_bound->is_locked();
}
GLenum buffer_iface::get_bound_id()const{
if(m_bound)
return m_bound->get_buffer_id();
return 0;
}
gl_buffer* buffer_iface::get_bound_buffer()const{
if(m_bound)
return m_bound;
return nullptr;
}
gl_buffer::gl_buffer(GLenum buf):
m_buffer(buf){}
void gl_buffer::bind(const buffer_iface* newbind){
if(bound)
bound->unbind();
bound = newbind;
}
void gl_buffer::lock(bool b){
m_lock = b;
}
bool gl_buffer::is_locked()const{
return m_lock;
}
GLenum gl_buffer::get_buffer_id()const{
return m_buffer;
}
}

130
src/graphics/vbo.cpp Normal file
View File

@ -0,0 +1,130 @@
/**
This file is a part of our_dick
Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "graphics/vbo.hpp"
#include "util/minmax.hpp"
#include <utility> //exchange, swap, move
namespace graphics{
vbo::vbo(size_t size, drawtype t):
m_buffer_size(size)
{
glGenBuffers(1, &m_buffer);
bind(buffer::copy_write);
glBufferData(m_bi.get_bound_id(), m_buffer_size, NULL, static_cast<GLenum>(t));
}
vbo::vbo(const vbo& v):
m_buffer_size(v.m_buffer_size),
m_bi(v.m_bi)
{
glGenBuffers(1, &m_buffer);
bind(buffer::copy_write);
scoped_vbo_map<void> data = v.map(buffer::copy_read, maptype::READ);
if(!data)
return;
glBufferData(m_bi.get_bound_id(), v.get_size(), data, static_cast<GLenum>(v.get_usage()));
}
vbo::vbo(vbo&& v):
m_buffer(std::exchange(v.m_buffer, 0)),
m_buffer_size(v.m_buffer_size),
m_bi(std::move(v.m_bi)){}
vbo::~vbo(){
if(m_buffer)
glDeleteBuffers(1, &m_buffer);
}
vbo& vbo::operator=(const vbo& v){
return (*this = vbo(v));
}
vbo& vbo::operator=(vbo&& v){
std::swap(m_buffer, v.m_buffer);
m_buffer_size = v.m_buffer_size;
return *this;
}
bool vbo::bind(gl_buffer& buf)const{
if(!m_bi.bind(buf))
return false;
glBindBuffer(buf.get_buffer_id(), m_buffer);
return true;
}
bool vbo::bind_lock(gl_buffer& buf)const{
if(!m_bi.bind_lock(buf))
return false;
glBindBuffer(buf.get_buffer_id(), m_buffer);
return true;
}
void vbo::bind_unlock()const{
m_bi.unlock();
}
void vbo::unbind()const{
glBindBuffer(m_bi.get_bound_id(), 0);
m_bi.unbind();
}
gl_buffer* vbo::get_bound_buffer()const{
return m_bi.get_bound_buffer();
}
GLenum vbo::get_bound_id()const{
return m_bi.get_bound_id();
}
void vbo::buffer(const void* data, size_t datasize){
if(datasize + m_buffer_size > get_cap()){
resize(util::max(datasize + m_buffer_size, get_cap() * 2));
}
bind(buffer::copy_write);
glBufferSubData(get_bound_id(), get_size(), datasize, data);
m_buffer_size += datasize;
}
void vbo::resize(size_t newsize){
vbo tmp(newsize, get_usage());
copy_buffer(tmp, *this);
*this = std::move(tmp);
}
scoped_vbo_map<void> vbo::map(gl_buffer& target, maptype m)const{
return scoped_vbo_map<void>(*this, target, m);
}
void vbo::clear(){
m_buffer_size = 0;
}
size_t vbo::get_size()const{
return m_buffer_size;
}
size_t vbo::get_cap()const{
GLint retval;
bind(buffer::copy_read);
glGetBufferParameteriv(get_bound_id(), GL_BUFFER_SIZE, &retval);
return retval;
}
auto vbo::get_usage()const -> drawtype{
GLint retval;
bind(buffer::copy_read);
glGetBufferParameteriv(get_bound_id(), GL_BUFFER_USAGE, &retval);
return static_cast<drawtype>(retval);
}
void vbo::copy_buffer(const vbo& src, vbo& dest){
size_t bytes = util::min(dest.get_cap(), src.get_size());
dest.bind(buffer::copy_write);
scoped_vbo_map<void> data(src, buffer::copy_read, maptype::READ);
dest.buffer(data, bytes);
}
}