diff --git a/src/Gui/GLBuffer.cpp b/src/Gui/GLBuffer.cpp index 2abc8d0ad8..a218073730 100644 --- a/src/Gui/GLBuffer.cpp +++ b/src/Gui/GLBuffer.cpp @@ -184,3 +184,125 @@ void OpenGLBuffer::buffer_delete(void * closure, uint32_t contextid) GLuint id = (GLuint) ((uintptr_t) closure); cc_glglue_glDeleteBuffers(glue, 1, &id); } + +// ---------------------------------------------------------------------------- + +OpenGLMultiBuffer::OpenGLMultiBuffer(GLenum type) + : target(type) + , currentBuf(0) + , currentContext(-1) + , glue(0) +{ + SoContextHandler::addContextDestructionCallback(context_destruction_cb, this); +} + +OpenGLMultiBuffer::~OpenGLMultiBuffer() +{ + SoContextHandler::removeContextDestructionCallback(context_destruction_cb, this); + + destroy(); +} + +void OpenGLMultiBuffer::setCurrentContext(uint32_t ctx) +{ + currentContext = ctx; + glue = cc_glglue_instance(currentContext); + currentBuf = &bufs[ctx]; +} + +bool OpenGLMultiBuffer::create() +{ + if (!currentBuf) + return false; + + auto &bufferId = *currentBuf; + if (bufferId > 0) + return true; + + if (!cc_glglue_has_vertex_buffer_object(glue)) + return false; + + cc_glglue_glGenBuffers(glue, 1, &bufferId); + return true; +} + +bool OpenGLMultiBuffer::isCreated(uint32_t context) const +{ + auto it = bufs.find(context); + return (it != bufs.end()) && (it->second > 0); +} + +void OpenGLMultiBuffer::destroy() +{ + // schedule delete for all allocated GL resources + for (auto &v : bufs) { + if (v.second > 0) { + void * ptr0 = (void*) ((uintptr_t) v.second); + SoGLCacheContextElement::scheduleDeleteCallback(v.first, buffer_delete, ptr0); + } + } + + bufs.clear(); + currentBuf = 0; +} + +void OpenGLMultiBuffer::allocate(const void *data, int count) +{ + if (currentBuf && *currentBuf) { + cc_glglue_glBufferData(glue, target, count, data, GL_STATIC_DRAW); + } +} + +bool OpenGLMultiBuffer::bind() +{ + if (currentBuf && *currentBuf) { + cc_glglue_glBindBuffer(glue, target, *currentBuf); + return true; + } + + return false; +} + +void OpenGLMultiBuffer::release() +{ + if (currentBuf && *currentBuf) { + cc_glglue_glBindBuffer(glue, target, 0); + } +} + +GLuint OpenGLMultiBuffer::getBufferId() const +{ + return currentBuf ? *currentBuf : 0; +} + +int OpenGLMultiBuffer::size() const +{ + GLint value = -1; + if (currentBuf && *currentBuf) { + cc_glglue_glGetBufferParameteriv(glue, target, GL_BUFFER_SIZE, &value); + } + return value; +} + +void OpenGLMultiBuffer::context_destruction_cb(uint32_t context, void * userdata) +{ + OpenGLMultiBuffer * self = static_cast(userdata); + + auto it = self->bufs.find(context); + if (it != self->bufs.end() && it->second) { + const cc_glglue * glue = cc_glglue_instance((int) context); + GLuint buffer = it->second; + cc_glglue_glDeleteBuffers(glue, 1, &buffer); + if (self->currentBuf == &it->second) + self->currentBuf = 0; + self->bufs.erase(it); + } +} + +void OpenGLMultiBuffer::buffer_delete(void * closure, uint32_t contextid) +{ + const cc_glglue * glue = cc_glglue_instance((int) contextid); + GLuint id = (GLuint) ((uintptr_t) closure); + cc_glglue_glDeleteBuffers(glue, 1, &id); +} + diff --git a/src/Gui/GLBuffer.h b/src/Gui/GLBuffer.h index f4f9dfe793..c0d1c0812d 100644 --- a/src/Gui/GLBuffer.h +++ b/src/Gui/GLBuffer.h @@ -24,6 +24,7 @@ #ifndef GUI_GLBUFFER_H #define GUI_GLBUFFER_H +#include #include namespace Gui { @@ -59,6 +60,35 @@ private: const cc_glglue* glue; }; +class GuiExport OpenGLMultiBuffer +{ +public: + OpenGLMultiBuffer(GLenum type); + ~OpenGLMultiBuffer(); + + void setCurrentContext(uint32_t ctx); + bool create(); + bool isCreated(uint32_t ctx) const; + + void destroy(); + void allocate(const void *data, int count); + bool bind(); + void release(); + GLuint getBufferId() const; + int size() const; + +private: + static void context_destruction_cb(uint32_t context, void * userdata); + static void buffer_delete(void * closure, uint32_t contextid); + + GLenum target; + // map context to buffer id + std::map bufs; + GLuint *currentBuf; + uint32_t currentContext; + const cc_glglue* glue; +}; + } // namespace Gui #endif // GUI_GLBUFFER_H diff --git a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp index 07030bacfc..35c7d55a3f 100644 --- a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp +++ b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp @@ -70,8 +70,8 @@ using namespace MeshGui; class MeshRenderer::Private { public: - Gui::OpenGLBuffer vertices; - Gui::OpenGLBuffer indices; + Gui::OpenGLMultiBuffer vertices; + Gui::OpenGLMultiBuffer indices; const SbColor * pcolors; SoMaterialBindingElement::Binding matbinding; bool initialized; @@ -84,6 +84,8 @@ public: std::vector& vertex, std::vector& index); void renderFacesGLArray(SoGLRenderAction*); void renderCoordsGLArray(SoGLRenderAction *); + void update(); + bool needUpdate(SoGLRenderAction *); private: void renderGLArray(SoGLRenderAction *, GLenum); @@ -115,13 +117,7 @@ bool MeshRenderer::Private::canRenderGLArray(SoGLRenderAction *action) const init = true; } - if (!vboAvailable) - return false; - - // if no buffer is created we must pass here in order to create it afterwards - if (!indices.isCreated()) - return true; - return indices.getBoundContext() == action->getCacheContext(); + return vboAvailable; } void MeshRenderer::Private::generateGLArrays(SoGLRenderAction* action, @@ -135,11 +131,9 @@ void MeshRenderer::Private::generateGLArrays(SoGLRenderAction* action, vertices.setCurrentContext(action->getCacheContext()); indices.setCurrentContext(action->getCacheContext()); - if (!initialized) { - vertices.create(); - indices.create(); - initialized = true; - } + initialized = true; + vertices.create(); + indices.create(); vertices.bind(); vertices.allocate(&(vertex[0]), @@ -196,6 +190,18 @@ void MeshRenderer::Private::renderCoordsGLArray(SoGLRenderAction *action) { renderGLArray(action, GL_POINTS); } + +void MeshRenderer::Private::update() +{ + vertices.destroy(); + indices.destroy(); +} + +bool MeshRenderer::Private::needUpdate(SoGLRenderAction *action) +{ + return !vertices.isCreated(action->getCacheContext()) || + !indices.isCreated(action->getCacheContext()); +} #elif defined RENDER_GLARRAYS class MeshRenderer::Private { public: @@ -216,6 +222,13 @@ public: std::vector& vertex, std::vector& index); void renderFacesGLArray(SoGLRenderAction *action); void renderCoordsGLArray(SoGLRenderAction *action); + void update() + { + } + bool needUpdate(SoGLRenderAction *) + { + return false; + } }; bool MeshRenderer::Private::canRenderGLArray(SoGLRenderAction *) const @@ -323,6 +336,13 @@ public: void renderCoordsGLArray(SoGLRenderAction *) { } + void update() + { + } + bool needUpdate(SoGLRenderAction *) + { + return false; + } }; #endif @@ -336,6 +356,16 @@ MeshRenderer::~MeshRenderer() delete p; } +void MeshRenderer::update() +{ + p->update(); +} + +bool MeshRenderer::needUpdate(SoGLRenderAction *action) +{ + return p->needUpdate(action); +} + void MeshRenderer::generateGLArrays(SoGLRenderAction* action, SoMaterialBindingElement::Binding matbind, std::vector& vertex, std::vector& index) { @@ -499,6 +529,10 @@ void SoFCIndexedFaceSet::GLRender(SoGLRenderAction *action) if (useVBO) { if (updateGLArray.getValue()) { updateGLArray.setValue(false); + render.update(); + generateGLArrays(action); + } + else if (render.needUpdate(action)) { generateGLArrays(action); } diff --git a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h index 375d169dca..2f85b74d18 100644 --- a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h +++ b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h @@ -49,6 +49,8 @@ public: void renderCoordsGLArray(SoGLRenderAction *action); bool canRenderGLArray(SoGLRenderAction *action) const; bool matchMaterial(SoState*) const; + void update(); + bool needUpdate(SoGLRenderAction *action); static bool shouldRenderDirectly(bool); private: