From bb550158fc27d19a53bec595aac153bc77c38c1c Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 8 Dec 2024 18:02:45 +0100 Subject: [PATCH] OpenGL: encapsulate VBOs into a class internal only for now but this will be handy --- irr/src/CMakeLists.txt | 1 + irr/src/OpenGL/Common.h | 2 + irr/src/OpenGL/Driver.cpp | 83 +++++++++++++++------------------------ irr/src/OpenGL/Driver.h | 11 +++--- irr/src/OpenGL/VBO.cpp | 51 ++++++++++++++++++++++++ irr/src/OpenGL/VBO.h | 57 +++++++++++++++++++++++++++ 6 files changed, 147 insertions(+), 58 deletions(-) create mode 100644 irr/src/OpenGL/VBO.cpp create mode 100644 irr/src/OpenGL/VBO.h diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index 7e0a3a3fa..5ac78a17e 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -348,6 +348,7 @@ if(ENABLE_OPENGL3 OR ENABLE_GLES2) OpenGL/FixedPipelineRenderer.cpp OpenGL/MaterialRenderer.cpp OpenGL/Renderer2D.cpp + OpenGL/VBO.cpp ) endif() diff --git a/irr/src/OpenGL/Common.h b/irr/src/OpenGL/Common.h index 75c213bb0..7049f6f65 100644 --- a/irr/src/OpenGL/Common.h +++ b/irr/src/OpenGL/Common.h @@ -40,6 +40,8 @@ typedef COpenGLCoreTexture COpenGL3Texture; typedef COpenGLCoreRenderTarget COpenGL3RenderTarget; typedef COpenGLCoreCacheHandler COpenGL3CacheHandler; +class OpenGLVBO; + enum OpenGLSpec : u8 { Core, diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index 5df87861d..150b80e7c 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -177,6 +177,8 @@ COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters ¶ms 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 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 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(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_(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 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); diff --git a/irr/src/OpenGL/Driver.h b/irr/src/OpenGL/Driver.h index e0787e560..d5ce7eab6 100644 --- a/irr/src/OpenGL/Driver.h +++ b/irr/src/OpenGL/Driver.h @@ -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); diff --git a/irr/src/OpenGL/VBO.cpp b/irr/src/OpenGL/VBO.cpp new file mode 100644 index 000000000..01e278437 --- /dev/null +++ b/irr/src/OpenGL/VBO.cpp @@ -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 +#include + +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; +} + +} +} diff --git a/irr/src/OpenGL/VBO.h b/irr/src/OpenGL/VBO.h new file mode 100644 index 000000000..85c005df2 --- /dev/null +++ b/irr/src/OpenGL/VBO.h @@ -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 + +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; +}; + +} +}