Skip to content

Instantly share code, notes, and snippets.

@KoKuToru
Last active August 8, 2020 07:50
Show Gist options
  • Save KoKuToru/63baa17cffbd3e89f044102dcab5f8e0 to your computer and use it in GitHub Desktop.
Save KoKuToru/63baa17cffbd3e89f044102dcab5f8e0 to your computer and use it in GitHub Desktop.
OpenGL Buffer (4.5?!)
//g++ test.cpp `sdl2-config --cflags --libs` -lGLEW -lGL
#define NO_SDL_GLEXT
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <stdexcept>
#include <iostream>
template<typename T> struct Vec2 {
T x;
T y;
};
template<typename T> struct Vec3 {
T x;
T y;
T z;
};
template<typename T> struct Vec4 {
T x;
T y;
T z;
T w;
};
namespace GL {
void CreateBuffers(GLsizei n, GLuint *buffers) {
if (glCreateBuffers) {
glCreateBuffers(n, buffers);
return;
}
glGenBuffers(n, buffers);
for (auto i = 0; i < n; ++i) {
glBindBuffer(GL_ARRAY_BUFFER, buffers[i]);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void NamedBufferData(GLuint buffer, GLsizeiptr size, const void *data, GLenum usage) {
if (glNamedBufferData) {
glNamedBufferData(buffer, size, data, usage);
return;
}
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, size, data, usage);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void* MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) {
if (glMapNamedBufferRange) {
return glMapNamedBufferRange(buffer, offset, length, access);
}
glBindBuffer(GL_ARRAY_BUFFER, buffer);
auto tmp = glMapBufferRange(GL_ARRAY_BUFFER, offset, length, access);
glBindBuffer(GL_ARRAY_BUFFER, 0);
return tmp;
}
void UnmapNamedBuffer(GLuint buffer) {
if (glUnmapNamedBuffer) {
glUnmapNamedBuffer(buffer);
return;
}
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void DeleteBuffers(GLsizei n, const GLuint * buffers) {
glDeleteBuffers(n, buffers);
}
void FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length) {
if (glFlushMappedNamedBufferRange) {
glFlushMappedNamedBufferRange(buffer, offset, length);
return;
}
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glFlushMappedBufferRange(GL_ARRAY_BUFFER, offset, length);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void NamedBufferStorage(GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags) {
if (glNamedBufferStorage) {
glNamedBufferStorage(buffer, size, data, flags);
return;
}
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferStorage(GL_ARRAY_BUFFER, size, data, flags);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
class BufferBaseDeleter {
GLuint _bufferId = 0;
public:
BufferBaseDeleter(GLuint bufferId) {
this->_bufferId = bufferId;
}
void operator()(void* p) const {
p;
GL::UnmapNamedBuffer(this->_bufferId);
GL::DeleteBuffers(1, &this->_bufferId);
}
};
#include <memory>
class BufferBase {
protected:
GLuint _bufferId = 0;
int _size_byte = 0;
std::shared_ptr<void> _ptr = nullptr;
public:
BufferBase(int size_byte) {
this->_size_byte = size_byte;
GL::CreateBuffers(1, &this->_bufferId);
auto flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
GL::NamedBufferStorage(this->_bufferId, this->_size_byte, nullptr, flags);
// map buffer
auto raw_ptr = GL::MapNamedBufferRange(this->_bufferId, 0, this->_size_byte, flags | GL_MAP_FLUSH_EXPLICIT_BIT);
this->_ptr = std::shared_ptr<void>(raw_ptr, BufferBaseDeleter(this->_bufferId));
}
virtual ~BufferBase() {}
void flush() {
GL::FlushMappedNamedBufferRange(this->_bufferId, 0, this->_size_byte);
}
};
template<typename T> class Buffer: public BufferBase {
int _size = 0;
public:
Buffer(int size): BufferBase(_size * sizeof(T)) {
this->_size = size;
}
~Buffer() {
}
const T& at(int index) const {
if (index >= this._size || index < 0) {
throw std::out_of_range("OUT OF RANGE");
}
return this->operator[](index);
}
T& at(int index) {
if (index >= this._size || index < 0) {
throw std::out_of_range("OUT OF RANGE");
}
return this->operator[](index);
}
const T& operator[](int index) const {
return *((T*)this->_ptr.get() + index);
}
T& operator[](int index) {
return *((T*)this->_ptr.get() + index);
}
const T& front() const {
return this->operator[](0);
}
T& front() {
return this->operator[](0);
}
const T& back() const {
return this->operator[](this->size() - 1);
}
T& back() {
return this->operator[](this->size() - 1);
}
const T* data() const {
return (T*)this->_ptr.get();
}
T* data() {
return (T*)this->_ptr.get();
}
T* begin() {
return &this->front();
}
const T* begin() const {
return &this->front();
}
const T* cbegin(){
return &this->front();
}
const T* cbegin() const {
return &this->front();
}
T* end() {
return &this->back();
}
const T* end() const {
return &this->back();
}
const T* cend(){
return &this->back();
}
const T* cend() const {
return &this->back();
}
int size() const {
return this->_size;
}
};
#include <signal.h>
#include <iostream>
void debugOutput(unsigned int source, unsigned int type, unsigned int id,
unsigned int severity, int length,
const char* message, const void* userParam)
{
if (std::string(message, std::string("Buffer detailed info").size()) == "Buffer detailed info")
{
//filter it
return;
}
std::string error_source, error_type, error_severity;
switch(source)
{
case GL_DEBUG_SOURCE_API_ARB:
error_source = "OpenGL";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
error_source = "Windows";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
error_source = "Shader Compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
error_source = "Third Party";
break;
case GL_DEBUG_SOURCE_APPLICATION_ARB:
error_source = "Application";
break;
case GL_DEBUG_SOURCE_OTHER_ARB:
error_source = "Other";
break;
default:
error_source = "UNKNOW";
break;
}
switch (type)
{
case GL_DEBUG_TYPE_ERROR_ARB:
error_type = "Error";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
error_type = "Deprecated behavior";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
error_type = "Undefined behavior";
break;
case GL_DEBUG_TYPE_PORTABILITY_ARB:
error_type = "Portability";
break;
case GL_DEBUG_TYPE_PERFORMANCE_ARB:
error_type = "Performance";
break;
case GL_DEBUG_TYPE_OTHER_ARB:
error_type = "Other";
default:
error_type = "UNKNOW";
break;
}
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH_ARB:
error_severity = "High";
break;
case GL_DEBUG_SEVERITY_MEDIUM_ARB:
error_severity = "Medium";
break;
case GL_DEBUG_SEVERITY_LOW_ARB:
error_severity = "Low";
break;
default:
error_severity = "UNKNOW";
break;
}
std::cout << "Source: " << error_source << " Type: " << error_type << " Severity: " << error_severity << " Message: " << message << std::endl;
if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
{
raise(SIGTRAP);
}
}
#include <algorithm>
#include <vector>
int main() {
auto win = SDL_CreateWindow("test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
//OpenGL 4.2
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
auto ctx = SDL_GL_CreateContext(win);
glewExperimental=true;
glewInit();
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
glDebugMessageCallbackARB(debugOutput, NULL);
Buffer<Vec2<GLfloat>> buffer(30);
std::fill(buffer.begin(), buffer.end(), Vec2<GLfloat>{ 0., 0.}); // zero init
buffer[0] = { 10., 0. };
buffer[1] = { 0., 10. };
buffer[2] = { 0., 0. };
buffer.flush();
std::vector<BufferBase> tmp;
tmp.push_back(buffer);
// .. nothing more..
while (true) {
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch(e.type) {
case SDL_QUIT:
SDL_Quit();
return 0;
}
}
SDL_GL_SwapWindow(win);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment