OpenGL: encapsulate VBOs into a class

internal only for now but this will be handy
This commit is contained in:
sfan5 2024-12-08 18:02:45 +01:00
parent b087e2554f
commit bb550158fc
6 changed files with 147 additions and 58 deletions

@ -348,6 +348,7 @@ if(ENABLE_OPENGL3 OR ENABLE_GLES2)
OpenGL/FixedPipelineRenderer.cpp
OpenGL/MaterialRenderer.cpp
OpenGL/Renderer2D.cpp
OpenGL/VBO.cpp
)
endif()

@ -40,6 +40,8 @@ typedef COpenGLCoreTexture<COpenGL3DriverBase> COpenGL3Texture;
typedef COpenGLCoreRenderTarget<COpenGL3DriverBase, COpenGL3Texture> COpenGL3RenderTarget;
typedef COpenGLCoreCacheHandler<COpenGL3DriverBase, COpenGL3Texture> COpenGL3CacheHandler;
class OpenGLVBO;
enum OpenGLSpec : u8
{
Core,

@ -177,6 +177,8 @@ COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters &params
COpenGL3DriverBase::~COpenGL3DriverBase()
{
QuadIndexVBO.destroy();
deleteMaterialRenders();
CacheHandler->getTextureCache().clear();
@ -198,12 +200,16 @@ COpenGL3DriverBase::~COpenGL3DriverBase()
}
}
void COpenGL3DriverBase::initQuadsIndices(int max_vertex_count)
void COpenGL3DriverBase::initQuadsIndices(u32 max_vertex_count)
{
int max_quad_count = max_vertex_count / 4;
std::vector<GLushort> QuadsIndices;
QuadsIndices.reserve(6 * max_quad_count);
for (int k = 0; k < max_quad_count; k++) {
u32 max_quad_count = max_vertex_count / 4;
u32 indices_size = 6 * max_quad_count;
if (indices_size == QuadIndexVBO.getSize() * sizeof(u16))
return;
// initialize buffer contents
std::vector<u16> QuadsIndices;
QuadsIndices.reserve(indices_size);
for (u32 k = 0; k < max_quad_count; k++) {
QuadsIndices.push_back(4 * k + 0);
QuadsIndices.push_back(4 * k + 1);
QuadsIndices.push_back(4 * k + 2);
@ -211,11 +217,8 @@ void COpenGL3DriverBase::initQuadsIndices(int max_vertex_count)
QuadsIndices.push_back(4 * k + 2);
QuadsIndices.push_back(4 * k + 3);
}
GL.GenBuffers(1, &QuadIndexBuffer);
GL.BindBuffer(GL_ARRAY_BUFFER, QuadIndexBuffer);
GL.BufferData(GL_ARRAY_BUFFER, sizeof(QuadsIndices[0]) * QuadsIndices.size(), QuadsIndices.data(), GL_STATIC_DRAW);
GL.BindBuffer(GL_ARRAY_BUFFER, 0);
QuadIndexCount = QuadsIndices.size();
QuadIndexVBO.upload(QuadsIndices.data(), QuadsIndices.size() * sizeof(u16),
0, GL_STATIC_DRAW, true);
}
void COpenGL3DriverBase::initVersion()
@ -474,41 +477,18 @@ void COpenGL3DriverBase::setTransform(E_TRANSFORMATION_STATE state, const core::
Transformation3DChanged = true;
}
bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink_opengl *HWBuffer,
bool COpenGL3DriverBase::uploadHardwareBuffer(OpenGLVBO &vbo,
const void *buffer, size_t bufferSize, scene::E_HARDWARE_MAPPING hint)
{
assert(HWBuffer);
accountHWBufferUpload(bufferSize);
// get or create buffer
bool newBuffer = false;
if (!HWBuffer->vbo_ID) {
GL.GenBuffers(1, &HWBuffer->vbo_ID);
if (!HWBuffer->vbo_ID)
return false;
newBuffer = true;
} else if (HWBuffer->vbo_Size < bufferSize) {
newBuffer = true;
}
GLenum usage = GL_STATIC_DRAW;
if (hint == scene::EHM_STREAM)
usage = GL_STREAM_DRAW;
else if (hint == scene::EHM_DYNAMIC)
usage = GL_DYNAMIC_DRAW;
GL.BindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_ID);
// copy data to graphics card
if (!newBuffer)
GL.BufferSubData(GL_ARRAY_BUFFER, 0, bufferSize, buffer);
else {
HWBuffer->vbo_Size = bufferSize;
GLenum usage = GL_STATIC_DRAW;
if (hint == scene::EHM_STREAM)
usage = GL_STREAM_DRAW;
else if (hint == scene::EHM_DYNAMIC)
usage = GL_DYNAMIC_DRAW;
GL.BufferData(GL_ARRAY_BUFFER, bufferSize, buffer, usage);
}
GL.BindBuffer(GL_ARRAY_BUFFER, 0);
vbo.upload(buffer, bufferSize, 0, usage);
return (!TEST_GL_ERROR(this));
}
@ -525,7 +505,8 @@ bool COpenGL3DriverBase::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuff
const u32 vertexSize = getVertexPitchFromType(vb->getType());
const size_t bufferSize = vertexSize * vb->getCount();
return updateHardwareBuffer(HWBuffer, vb->getData(), bufferSize, vb->getHardwareMappingHint());
return uploadHardwareBuffer(HWBuffer->Vbo, vb->getData(),
bufferSize, vb->getHardwareMappingHint());
}
bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
@ -551,7 +532,8 @@ bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffe
const size_t bufferSize = ib->getCount() * indexSize;
return updateHardwareBuffer(HWBuffer, ib->getData(), bufferSize, ib->getHardwareMappingHint());
return uploadHardwareBuffer(HWBuffer->Vbo, ib->getData(),
bufferSize, ib->getHardwareMappingHint());
}
bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink *HWBuffer)
@ -563,14 +545,14 @@ bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink *HWBuffer)
if (b->IsVertex) {
assert(b->VertexBuffer);
if (b->ChangedID != b->VertexBuffer->getChangedID() || !b->vbo_ID) {
if (b->ChangedID != b->VertexBuffer->getChangedID() || !b->Vbo.exists()) {
if (!updateVertexHardwareBuffer(b))
return false;
b->ChangedID = b->VertexBuffer->getChangedID();
}
} else {
assert(b->IndexBuffer);
if (b->ChangedID != b->IndexBuffer->getChangedID() || !b->vbo_ID) {
if (b->ChangedID != b->IndexBuffer->getChangedID() || !b->Vbo.exists()) {
if (!updateIndexHardwareBuffer(b))
return false;
b->ChangedID = b->IndexBuffer->getChangedID();
@ -621,10 +603,7 @@ void COpenGL3DriverBase::deleteHardwareBuffer(SHWBufferLink *HWBuffer)
return;
auto *b = static_cast<SHWBufferLink_opengl *>(HWBuffer);
if (b->vbo_ID) {
GL.DeleteBuffers(1, &b->vbo_ID);
b->vbo_ID = 0;
}
b->Vbo.destroy();
CNullDriver::deleteHardwareBuffer(HWBuffer);
}
@ -644,14 +623,14 @@ void COpenGL3DriverBase::drawBuffers(const scene::IVertexBuffer *vb,
const void *vertices = vb->getData();
if (hwvert) {
assert(hwvert->IsVertex);
GL.BindBuffer(GL_ARRAY_BUFFER, hwvert->vbo_ID);
GL.BindBuffer(GL_ARRAY_BUFFER, hwvert->Vbo.getName());
vertices = nullptr;
}
const void *indexList = ib->getData();
if (hwidx) {
assert(!hwidx->IsVertex);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, hwidx->vbo_ID);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, hwidx->Vbo.getName());
indexList = nullptr;
}
@ -903,7 +882,7 @@ void COpenGL3DriverBase::draw2DImageBatch(const video::ITexture *texture,
}
const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
assert(6 * drawCount <= QuadIndexCount); // FIXME split the batch? or let it crash?
assert(6 * drawCount * sizeof(u16) <= QuadIndexVBO.getSize()); // FIXME split the batch? or let it crash?
std::vector<S3DVertex> vtx;
vtx.reserve(drawCount * 4);
@ -943,7 +922,7 @@ void COpenGL3DriverBase::draw2DImageBatch(const video::ITexture *texture,
tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
}
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, QuadIndexBuffer);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, QuadIndexVBO.getName());
drawElements(GL_TRIANGLES, vt2DImage, vtx.data(), vtx.size(), 0, 6 * drawCount);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

@ -8,6 +8,7 @@
#include "SIrrCreationParameters.h"
#include "Common.h"
#include "VBO.h"
#include "CNullDriver.h"
#include "IMaterialRendererServices.h"
#include "EDriverFeatures.h"
@ -49,8 +50,7 @@ public:
SHWBufferLink_opengl(const scene::IVertexBuffer *vb) : SHWBufferLink(vb) {}
SHWBufferLink_opengl(const scene::IIndexBuffer *ib) : SHWBufferLink(ib) {}
GLuint vbo_ID = 0;
u32 vbo_Size = 0;
OpenGLVBO Vbo;
};
bool updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer);
@ -300,7 +300,7 @@ protected:
LockRenderStateMode = false;
}
bool updateHardwareBuffer(SHWBufferLink_opengl *b, const void *buffer, size_t bufferSize, scene::E_HARDWARE_MAPPING hint);
bool uploadHardwareBuffer(OpenGLVBO &vbo, const void *buffer, size_t bufferSize, scene::E_HARDWARE_MAPPING hint);
void createMaterialRenderers();
@ -372,9 +372,8 @@ private:
bool EnableErrorTest;
unsigned QuadIndexCount;
GLuint QuadIndexBuffer = 0;
void initQuadsIndices(int max_vertex_count = 65536);
OpenGLVBO QuadIndexVBO;
void initQuadsIndices(u32 max_vertex_count = 65536);
void debugCb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message);
static void APIENTRY debugCb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam);

51
irr/src/OpenGL/VBO.cpp Normal file

@ -0,0 +1,51 @@
// Copyright (C) 2024 sfan5
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "VBO.h"
#include <cassert>
#include <mt_opengl.h>
namespace irr
{
namespace video
{
void OpenGLVBO::upload(const void *data, size_t size, size_t offset,
GLenum usage, bool mustShrink)
{
bool newBuffer = false;
if (!m_name) {
GL.GenBuffers(1, &m_name);
if (!m_name)
return;
newBuffer = true;
} else if (size > m_size || mustShrink) {
// note: mustShrink && offset > 0 is forbidden
newBuffer = size != m_size;
}
GL.BindBuffer(GL_ARRAY_BUFFER, m_name);
if (newBuffer) {
assert(offset == 0);
GL.BufferData(GL_ARRAY_BUFFER, size, data, usage);
m_size = size;
} else {
GL.BufferSubData(GL_ARRAY_BUFFER, offset, size, data);
}
GL.BindBuffer(GL_ARRAY_BUFFER, 0);
}
void OpenGLVBO::destroy()
{
if (m_name)
GL.DeleteBuffers(1, &m_name);
m_name = 0;
m_size = 0;
}
}
}

57
irr/src/OpenGL/VBO.h Normal file

@ -0,0 +1,57 @@
// Copyright (C) 2024 sfan5
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "Common.h"
#include <cstddef>
namespace irr
{
namespace video
{
class OpenGLVBO
{
public:
/// @note does not create on GL side
OpenGLVBO() = default;
/// @note does not free on GL side
~OpenGLVBO() = default;
/// @return "name" (ID) of this buffer in GL
GLuint getName() const { return m_name; }
/// @return does this refer to an existing GL buffer?
bool exists() const { return m_name != 0; }
/// @return size of this buffer in bytes
size_t getSize() const { return m_size; }
/**
* Upload buffer data to GL.
*
* Changing the size of the buffer is only possible when `offset == 0`.
* @param data data pointer
* @param size number of bytes
* @param offset offset to upload at
* @param usage usage pattern passed to GL (only if buffer is new)
* @param mustShrink force re-create of buffer if it became smaller
* @note modifies GL_ARRAY_BUFFER binding
*/
void upload(const void *data, size_t size, size_t offset,
GLenum usage, bool mustShrink = false);
/**
* Free buffer in GL.
* @note modifies GL_ARRAY_BUFFER binding
*/
void destroy();
private:
GLuint m_name = 0;
size_t m_size = 0;
};
}
}