From bb09f5488fdeb4358b3d3a8a1c6eb52c3f9d65d4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 27 Oct 2018 09:07:26 +0200 Subject: [PATCH] - added an abstract base vertex buffer class. --- src/CMakeLists.txt | 1 + src/gl/data/gl_vertexbuffer.h | 9 +- src/gl/system/glsys_vertexbuffer.cpp | 143 +++++++++++++++++++++++++++ src/gl/system/glsys_vertexbuffer.h | 31 ++++++ src/hwrenderer/data/vertexbuffer.h | 50 ++++++++++ src/hwrenderer/scene/hw_walls.cpp | 2 + 6 files changed, 228 insertions(+), 8 deletions(-) create mode 100644 src/gl/system/glsys_vertexbuffer.cpp create mode 100644 src/gl/system/glsys_vertexbuffer.h create mode 100644 src/hwrenderer/data/vertexbuffer.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a798ad538..71aab5ad2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1055,6 +1055,7 @@ set (PCH_SOURCES gl_load/gl_interface.cpp gl/system/gl_framebuffer.cpp gl/system/gl_debug.cpp + gl/system/glsys_vertexbuffer.cpp gl/textures/gl_hwtexture.cpp gl/textures/gl_samplers.cpp hwrenderer/data/flatvertices.cpp diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index 2ecaff47b..7316585e2 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -32,6 +32,7 @@ #include "r_data/models/models.h" #include "hwrenderer/data/flatvertices.h" #include "hwrenderer/scene/hw_skydome.h" +#include "hwrenderer/data/vertexbuffer.h" struct vertex_t; struct secplane_t; @@ -39,14 +40,6 @@ struct subsector_t; struct sector_t; class FMaterial; -enum -{ - VATTR_VERTEX_BIT, - VATTR_TEXCOORD_BIT, - VATTR_COLOR_BIT, - VATTR_VERTEX2_BIT, - VATTR_NORMAL_BIT -}; class FVertexBuffer diff --git a/src/gl/system/glsys_vertexbuffer.cpp b/src/gl/system/glsys_vertexbuffer.cpp new file mode 100644 index 000000000..22685b539 --- /dev/null +++ b/src/gl/system/glsys_vertexbuffer.cpp @@ -0,0 +1,143 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2018 Christoph Oelckers +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** Low level vertex buffer class +** +**/ + +#include "gl_load/gl_system.h" +#include "glsys_vertexbuffer.h" +#include "gl/renderer/gl_renderstate.h" + +//========================================================================== +// +// Create / destroy the VBO +// +//========================================================================== + +GLVertexBuffer::GLVertexBuffer() +{ + glGenBuffers(1, &vbo_id); +} + +GLVertexBuffer::~GLVertexBuffer() +{ + if (vbo_id != 0) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glUnmapBuffer(GL_ARRAY_BUFFER); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &vbo_id); + } +} + +void GLVertexBuffer::SetData(size_t size, void *data, bool staticdata) +{ + if (data != nullptr) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBufferData(GL_ARRAY_BUFFER, size, data, staticdata? GL_STATIC_DRAW : GL_STREAM_DRAW); + } + else + { + mPersistent = screen->BuffersArePersistent(); + if (mPersistent) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBufferStorage(GL_ARRAY_BUFFER, size, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + map = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + } + else + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_STREAM_DRAW); + map = nullptr; + } + nomap = false; + } + buffersize = size; + gl_RenderState.ResetVertexBuffer(); // This is needed because glBindBuffer overwrites the setting stored in the render state. +} + +void GLVertexBuffer::Map() +{ + assert(nomap == false); + if (!mPersistent) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + gl_RenderState.ResetVertexBuffer(); + map = (FFlatVertex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, buffersize, GL_MAP_WRITE_BIT|GL_MAP_UNSYNCHRONIZED_BIT); + } +} + +void GLVertexBuffer::Unmap() +{ + assert(nomap == false); + if (!mPersistent) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + gl_RenderState.ResetVertexBuffer(); + glUnmapBuffer(GL_ARRAY_BUFFER); + map = nullptr; + } +} + +void GLVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, FVertexBufferAttribute *attrs) +{ + static int VFmtToGLFmt[] = { GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT_2_10_10_10_REV }; + static uint8_t VFmtToSize[] = {4, 3, 2, 1, 4, 4}; + + mStride = stride; + mNumBindingPoints = numBindingPoints; + + for(int i = 0; i < numAttributes; i++) + { + if (attrs[i].location >= 0 && attrs[i].location < VATTR_MAX) + { + auto & attrinf = mAttributeInfo[attrs[i].location]; + attrinf.format = VFmtToGLFmt[attrs[i].format]; + attrinf.size = VFmtToSize[attrs[i].format]; + attrinf.offset = attrs[i].offset; + } + } +} + +void GLVertexBuffer::Bind(size_t *offsets) +{ + int i = 0; + + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + for(auto &attrinf : mAttributeInfo) + { + if (attrinf.size == 0) + { + glDisableVertexAttribArray(i); + } + else + { + glEnableVertexAttribArray(i); + size_t ofs = offsets == nullptr? attrinf.offset : attrinf.offset + mStride * offsets[attrinf.bindingpoint]; + glVertexAttribPointer(i, attrinf.size, attrinf.format, attrinf.format != GL_FLOAT, (GLsizei)mStride, (void*)(intptr_t)ofs); + } + i++; + } +} diff --git a/src/gl/system/glsys_vertexbuffer.h b/src/gl/system/glsys_vertexbuffer.h new file mode 100644 index 000000000..eaf2b9730 --- /dev/null +++ b/src/gl/system/glsys_vertexbuffer.h @@ -0,0 +1,31 @@ +#pragma once + +#include "hwrenderer/data/vertexbuffer.h" + +class GLVertexBuffer : IVertexBuffer +{ + // If this could use the modern (since GL 4.3) binding system, things would be simpler... :( + struct GLVertexBufferAttribute + { + int bindingpoint; + int format; + int size; + int offset; + }; + + unsigned int vbo_id = 0; + int mNumBindingPoints; + bool mPersistent = false; + GLVertexBufferAttribute mAttributeInfo[VATTR_MAX] = {}; // Thanks to OpenGL's state system this needs to contain info about every attribute that may ever be in use throughout the entire renderer. + size_t mStride = 0; + +public: + GLVertexBuffer(); + ~GLVertexBuffer(); + void SetData(size_t size, void *data, bool staticdata) = 0; + void SetFormat(int numBindingPoints, int numAttributes, size_t stride, FVertexBufferAttribute *attrs) override; + void Bind(size_t *offsets); + void Map() override; + void Unmap() override; +}; + diff --git a/src/hwrenderer/data/vertexbuffer.h b/src/hwrenderer/data/vertexbuffer.h new file mode 100644 index 000000000..411f3e290 --- /dev/null +++ b/src/hwrenderer/data/vertexbuffer.h @@ -0,0 +1,50 @@ +#pragma once + +// The low level code needs to know which attributes exist. +// OpenGL needs to change the state of all of them per buffer binding. +// VAOs are mostly useless for this because they lump buffer and binding state together which the model code does not want. +enum +{ + VATTR_VERTEX_BIT, + VATTR_TEXCOORD_BIT, + VATTR_COLOR_BIT, + VATTR_VERTEX2_BIT, + VATTR_NORMAL_BIT, + VATTR_NORMAL2_BIT, + + VATTR_MAX +}; + +enum EVertexAttributeFormat +{ + VFmt_Float4, + VFmt_Float3, + VFmt_Float2, + VFmt_Float, + VFmt_Byte4, + VFmt_Packed_A2R10G10B10, +}; + +struct FVertexBufferAttribute +{ + int binding; + int location; + int format; + int offset; +}; + +class IVertexBuffer +{ +protected: + size_t buffersize = 0; + void *map = nullptr; + bool nomap = true; +public: + virtual ~IVertexBuffer() {} + virtual void SetData(size_t size, void *data, bool staticdata = true) = 0; + virtual void SetFormat(int numBindingPoints, int numAttributes, size_t stride, FVertexBufferAttribute *attrs) = 0; + virtual void Map() {} // Only needed by old OpenGL but this needs to be in the interface. + virtual void Unmap() {} + void *Memory() { assert(map); return map; } +}; + diff --git a/src/hwrenderer/scene/hw_walls.cpp b/src/hwrenderer/scene/hw_walls.cpp index 2c65db7ff..047c2dba6 100644 --- a/src/hwrenderer/scene/hw_walls.cpp +++ b/src/hwrenderer/scene/hw_walls.cpp @@ -511,6 +511,8 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) break; case PORTALTYPE_LINETOLINE: + if (!lineportal) + return; portal = di->FindPortal(lineportal); if (!portal) {