Mesh: support multiple context in OpenGLMultiBuffer
This commit is contained in:
@@ -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<OpenGLMultiBuffer*>(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);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#ifndef GUI_GLBUFFER_H
|
||||
#define GUI_GLBUFFER_H
|
||||
|
||||
#include <map>
|
||||
#include <Inventor/C/glue/gl.h>
|
||||
|
||||
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<uint32_t, GLuint> bufs;
|
||||
GLuint *currentBuf;
|
||||
uint32_t currentContext;
|
||||
const cc_glglue* glue;
|
||||
};
|
||||
|
||||
} // namespace Gui
|
||||
|
||||
#endif // GUI_GLBUFFER_H
|
||||
|
||||
@@ -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<float>& vertex, std::vector<int32_t>& 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<float>& vertex, std::vector<int32_t>& 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<float>& vertex, std::vector<int32_t>& 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user