From 13cf33d75f60b8929e5d1794a3e597722d084ed0 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Wed, 2 Dec 2015 11:09:49 -1000 Subject: [PATCH] Internal dynamic buffer updating (OpenGL only) --- include/boo/graphicsdev/GL.hpp | 5 +- .../boo/graphicsdev/IGraphicsCommandQueue.hpp | 6 - .../boo/graphicsdev/IGraphicsDataFactory.hpp | 6 +- lib/graphicsdev/GL.cpp | 199 ++++++++++++------ 4 files changed, 137 insertions(+), 79 deletions(-) diff --git a/include/boo/graphicsdev/GL.hpp b/include/boo/graphicsdev/GL.hpp index ebf90df..b7cf795 100644 --- a/include/boo/graphicsdev/GL.hpp +++ b/include/boo/graphicsdev/GL.hpp @@ -12,9 +12,10 @@ namespace boo class GLDataFactory : public IGraphicsDataFactory { + friend struct GLCommandQueue; IGraphicsContext* m_parent; - IGraphicsData* m_deferredData = nullptr; - std::unordered_set m_committedData; + struct GLData* m_deferredData = nullptr; + std::unordered_set m_committedData; std::vector m_texUnis; public: GLDataFactory(IGraphicsContext* parent); diff --git a/include/boo/graphicsdev/IGraphicsCommandQueue.hpp b/include/boo/graphicsdev/IGraphicsCommandQueue.hpp index 584f5fe..648c423 100644 --- a/include/boo/graphicsdev/IGraphicsCommandQueue.hpp +++ b/include/boo/graphicsdev/IGraphicsCommandQueue.hpp @@ -25,12 +25,6 @@ struct IGraphicsCommandQueue virtual void setViewport(const SWindowRect& rect)=0; virtual void setScissor(const SWindowRect& rect)=0; - /** - * @brief Which dynamic buffer slot is being populated for pending command list - * @return Index [0,2] indicating the buffer slot - */ - virtual int pendingDynamicSlot()=0; - virtual void resizeRenderTexture(ITextureR* tex, size_t width, size_t height)=0; virtual void setClearColor(const float rgba[4])=0; diff --git a/include/boo/graphicsdev/IGraphicsDataFactory.hpp b/include/boo/graphicsdev/IGraphicsDataFactory.hpp index 3ece92e..916d261 100644 --- a/include/boo/graphicsdev/IGraphicsDataFactory.hpp +++ b/include/boo/graphicsdev/IGraphicsDataFactory.hpp @@ -127,12 +127,12 @@ ENABLE_BITWISE_ENUM(VertexSemantic) /** Used to create IVertexFormat */ struct VertexElementDescriptor { - const IGraphicsBuffer* vertBuffer = nullptr; - const IGraphicsBuffer* indexBuffer = nullptr; + IGraphicsBuffer* vertBuffer = nullptr; + IGraphicsBuffer* indexBuffer = nullptr; VertexSemantic semantic; int semanticIdx = 0; VertexElementDescriptor() = default; - VertexElementDescriptor(const IGraphicsBuffer* v, const IGraphicsBuffer* i, VertexSemantic s, int idx=0) + VertexElementDescriptor(IGraphicsBuffer* v, IGraphicsBuffer* i, VertexSemantic s, int idx=0) : vertBuffer(v), indexBuffer(i), semantic(s), semanticIdx(idx) {} }; diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp index da0e393..ee38d7e 100644 --- a/lib/graphicsdev/GL.cpp +++ b/lib/graphicsdev/GL.cpp @@ -65,14 +65,15 @@ class GLGraphicsBufferD : public IGraphicsBufferD struct GLCommandQueue* m_q; GLuint m_bufs[3]; GLenum m_target; - void* m_mappedBuf = nullptr; - size_t m_mappedSize = 0; - GLGraphicsBufferD(GLCommandQueue* q, BufferUse use) - : m_q(q) + std::unique_ptr m_cpuBuf; + size_t m_cpuSz = 0; + int m_validMask = 0; + GLGraphicsBufferD(GLCommandQueue* q, BufferUse use, size_t sz) + : m_q(q), m_target(USE_TABLE[int(use)]), m_cpuBuf(new uint8_t[sz]), m_cpuSz(sz) { - m_target = USE_TABLE[int(use)]; glGenBuffers(3, m_bufs); } + void update(int b); public: ~GLGraphicsBufferD() {glDeleteBuffers(3, m_bufs);} @@ -80,9 +81,9 @@ public: void* map(size_t sz); void unmap(); - void bindVertex(int b) const; - void bindIndex(int b) const; - void bindUniform(size_t idx, int b) const; + void bindVertex(int b); + void bindIndex(int b); + void bindUniform(size_t idx, int b); }; IGraphicsBufferS* @@ -117,15 +118,31 @@ class GLTextureS : public ITextureS glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); else glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - if (fmt == TextureFormat::RGBA8) + + GLenum intFormat, format; + int pxPitch; + switch (fmt) { - for (size_t i=0 ; i m_cpuBuf; + size_t m_cpuSz = 0; + GLenum m_intFormat, m_format; size_t m_width = 0; size_t m_height = 0; + int m_validMask = 0; GLTextureD(GLCommandQueue* q, size_t width, size_t height, TextureFormat fmt); + void update(int b); public: ~GLTextureD(); @@ -182,7 +202,7 @@ public: void* map(size_t sz); void unmap(); - void bind(size_t idx) const; + void bind(size_t idx, int b); }; class GLTextureR : public ITextureR @@ -498,7 +518,7 @@ struct GLShaderDataBinding : IShaderDataBinding switch (tex->type()) { case TextureType::Dynamic: - static_cast(tex)->bind(i); + static_cast(tex)->bind(i, b); break; case TextureType::Static: static_cast(tex)->bind(i); @@ -514,10 +534,10 @@ struct GLShaderDataBinding : IShaderDataBinding IShaderDataBinding* GLDataFactory::newShaderDataBinding(IShaderPipeline* pipeline, - IVertexFormat* vtxFormat, - IGraphicsBuffer*, IGraphicsBuffer*, IGraphicsBuffer*, - size_t ubufCount, IGraphicsBuffer** ubufs, - size_t texCount, ITexture** texs) + IVertexFormat* vtxFormat, + IGraphicsBuffer*, IGraphicsBuffer*, IGraphicsBuffer*, + size_t ubufCount, IGraphicsBuffer** ubufs, + size_t texCount, ITexture** texs) { GLShaderDataBinding* retval = new GLShaderDataBinding(pipeline, vtxFormat, ubufCount, ubufs, texCount, texs); @@ -536,7 +556,7 @@ void GLDataFactory::reset() IGraphicsData* GLDataFactory::commit() { - IGraphicsData* retval = m_deferredData; + GLData* retval = m_deferredData; m_deferredData = new struct GLData(); m_committedData.insert(retval); /* Let's go ahead and flush to ensure our data gets to the GPU @@ -693,8 +713,8 @@ struct GLCommandQueue : IGraphicsCommandQueue size_t offset = 0; size_t instOffset = 0; glBindVertexArray(fmt->m_vao[b]); - const IGraphicsBuffer* lastVBO = nullptr; - const IGraphicsBuffer* lastEBO = nullptr; + IGraphicsBuffer* lastVBO = nullptr; + IGraphicsBuffer* lastEBO = nullptr; for (size_t i=0 ; im_elementCount ; ++i) { const VertexElementDescriptor* desc = &fmt->m_elements[i]; @@ -702,17 +722,17 @@ struct GLCommandQueue : IGraphicsCommandQueue { lastVBO = desc->vertBuffer; if (lastVBO->dynamic()) - static_cast(lastVBO)->bindVertex(b); + static_cast(lastVBO)->bindVertex(b); else - static_cast(lastVBO)->bindVertex(); + static_cast(lastVBO)->bindVertex(); } if (desc->indexBuffer != lastEBO) { lastEBO = desc->indexBuffer; if (lastEBO->dynamic()) - static_cast(lastEBO)->bindIndex(b); + static_cast(lastEBO)->bindIndex(b); else - static_cast(lastEBO)->bindIndex(); + static_cast(lastEBO)->bindIndex(); } glEnableVertexAttribArray(i); int maskedSem = int(desc->semantic & VertexSemantic::SemanticMask); @@ -911,11 +931,6 @@ struct GLCommandQueue : IGraphicsCommandQueue cmds.emplace_back(Command::Op::SetScissor); cmds.back().rect = rect; } - - int pendingDynamicSlot() - { - return m_fillBuf; - } void resizeRenderTexture(ITextureR* tex, size_t width, size_t height) { @@ -1022,7 +1037,6 @@ struct GLCommandQueue : IGraphicsCommandQueue void execute() { - glFlush(); std::unique_lock lk(m_mt); m_completeBuf = m_fillBuf; for (size_t i=0 ; i<3 ; ++i) @@ -1032,44 +1046,67 @@ struct GLCommandQueue : IGraphicsCommandQueue m_fillBuf = i; break; } + + /* Update dynamic data here */ + GLDataFactory* gfxF = static_cast(m_parent->getDataFactory()); + for (GLData* d : gfxF->m_committedData) + { + for (std::unique_ptr& b : d->m_DBufs) + b->update(m_completeBuf); + for (std::unique_ptr& t : d->m_DTexs) + t->update(m_completeBuf); + } + for (std::unique_ptr& b : gfxF->m_deferredData->m_DBufs) + b->update(m_completeBuf); + for (std::unique_ptr& t : gfxF->m_deferredData->m_DTexs) + t->update(m_completeBuf); + glFlush(); + lk.unlock(); m_cv.notify_one(); m_cmdBufs[m_fillBuf].clear(); } }; +void GLGraphicsBufferD::update(int b) +{ + int slot = 1 << b; + if ((slot & m_validMask) == 0) + { + glBindBuffer(m_target, m_bufs[b]); + glBufferData(m_target, m_cpuSz, m_cpuBuf.get(), GL_DYNAMIC_DRAW); + m_validMask |= slot; + } +} + void GLGraphicsBufferD::load(const void* data, size_t sz) { - glBindBuffer(m_target, m_bufs[m_q->m_fillBuf]); - glBufferData(m_target, sz, data, GL_DYNAMIC_DRAW); + size_t bufSz = std::min(sz, m_cpuSz); + memcpy(m_cpuBuf.get(), data, bufSz); + m_validMask = 0; } void* GLGraphicsBufferD::map(size_t sz) { - if (m_mappedBuf) - free(m_mappedBuf); - m_mappedBuf = malloc(sz); - m_mappedSize = sz; - return m_mappedBuf; + if (sz < m_cpuSz) + return nullptr; + return m_cpuBuf.get(); } void GLGraphicsBufferD::unmap() { - glBindBuffer(m_target, m_bufs[m_q->m_fillBuf]); - glBufferData(m_target, m_mappedSize, m_mappedBuf, GL_DYNAMIC_DRAW); - free(m_mappedBuf); - m_mappedBuf = nullptr; + m_validMask = 0; } -void GLGraphicsBufferD::bindVertex(int b) const +void GLGraphicsBufferD::bindVertex(int b) {glBindBuffer(GL_ARRAY_BUFFER, m_bufs[b]);} -void GLGraphicsBufferD::bindIndex(int b) const +void GLGraphicsBufferD::bindIndex(int b) {glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_bufs[b]);} -void GLGraphicsBufferD::bindUniform(size_t idx, int b) const +void GLGraphicsBufferD::bindUniform(size_t idx, int b) {glBindBufferBase(GL_UNIFORM_BUFFER, idx, m_bufs[b]);} IGraphicsBufferD* GLDataFactory::newDynamicBuffer(BufferUse use, size_t stride, size_t count) { GLCommandQueue* q = static_cast(m_parent->getCommandQueue()); - GLGraphicsBufferD* retval = new GLGraphicsBufferD(q, use); + GLGraphicsBufferD* retval = new GLGraphicsBufferD(q, use, stride * count); static_cast(m_deferredData)->m_DBufs.emplace_back(retval); return retval; } @@ -1077,41 +1114,67 @@ GLDataFactory::newDynamicBuffer(BufferUse use, size_t stride, size_t count) GLTextureD::GLTextureD(GLCommandQueue* q, size_t width, size_t height, TextureFormat fmt) : m_q(q), m_width(width), m_height(height) { + int pxPitch; + switch (fmt) + { + case TextureFormat::RGBA8: + m_intFormat = GL_RGBA; + m_format = GL_RGBA; + pxPitch = 4; + break; + case TextureFormat::I8: + m_intFormat = GL_R8; + m_format = GL_RED; + pxPitch = 1; + break; + default: + Log.report(LogVisor::FatalError, "unsupported tex format"); + } + m_cpuSz = width * height * pxPitch; + m_cpuBuf.reset(new uint8_t[m_cpuSz]); + glGenTextures(3, m_texs); glBindTexture(GL_TEXTURE_2D, m_texs[0]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, width, height, 0, m_format, GL_UNSIGNED_BYTE, nullptr); glBindTexture(GL_TEXTURE_2D, m_texs[1]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, width, height, 0, m_format, GL_UNSIGNED_BYTE, nullptr); glBindTexture(GL_TEXTURE_2D, m_texs[2]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, width, height, 0, m_format, GL_UNSIGNED_BYTE, nullptr); } GLTextureD::~GLTextureD() {glDeleteTextures(3, m_texs);} +void GLTextureD::update(int b) +{ + int slot = 1 << b; + if ((slot & m_validMask) == 0) + { + glBindTexture(GL_TEXTURE_2D, m_texs[b]); + glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, m_width, m_height, 0, m_format, GL_UNSIGNED_BYTE, m_cpuBuf.get()); + m_validMask |= slot; + } +} + void GLTextureD::load(const void* data, size_t sz) { - glBindTexture(GL_TEXTURE_2D, m_texs[m_q->m_fillBuf]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + size_t bufSz = std::min(sz, m_cpuSz); + memcpy(m_cpuBuf.get(), data, bufSz); + m_validMask = 0; } void* GLTextureD::map(size_t sz) { - if (m_mappedBuf) - free(m_mappedBuf); - m_mappedBuf = malloc(sz); - m_mappedSize = sz; - return m_mappedBuf; + if (sz > m_cpuSz) + return nullptr; + return m_cpuBuf.get(); } void GLTextureD::unmap() { - glBindTexture(GL_TEXTURE_2D, m_texs[m_q->m_fillBuf]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_mappedBuf); - free(m_mappedBuf); - m_mappedBuf = nullptr; + m_validMask = 0; } -void GLTextureD::bind(size_t idx) const +void GLTextureD::bind(size_t idx, int b) { glActiveTexture(GL_TEXTURE0 + idx); - glBindTexture(GL_TEXTURE_2D, m_texs[0]); + glBindTexture(GL_TEXTURE_2D, m_texs[b]); } ITextureD*