- added an abstract base vertex buffer class.

This commit is contained in:
Christoph Oelckers 2018-10-27 09:07:26 +02:00
parent 5cce310f11
commit bb09f5488f
6 changed files with 228 additions and 8 deletions

View file

@ -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

View file

@ -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

View file

@ -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++;
}
}

View file

@ -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;
};

View file

@ -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; }
};

View file

@ -511,6 +511,8 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype)
break;
case PORTALTYPE_LINETOLINE:
if (!lineportal)
return;
portal = di->FindPortal(lineportal);
if (!portal)
{