1
/***************************************************************************
2
* Copyright (c) 2018 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
24
#include "PreCompiled.h"
27
# ifndef GL_GLEXT_PROTOTYPES
28
# define GL_GLEXT_PROTOTYPES 1
33
# include <OpenGL/gl.h>
34
# include <OpenGL/glu.h>
35
# include <OpenGL/glext.h>
42
#include <Inventor/elements/SoGLCacheContextElement.h>
43
#include <Inventor/errors/SoDebugError.h>
44
#include <Inventor/misc/SoContextHandler.h>
53
OpenGLBuffer::OpenGLBuffer(GLenum type)
60
SoContextHandler::addContextDestructionCallback(context_destruction_cb, this);
63
OpenGLBuffer::~OpenGLBuffer()
65
SoContextHandler::removeContextDestructionCallback(context_destruction_cb, this);
71
* \brief OpenGLBuffer::isVBOSupported returns if the OpenGL driver
72
* supports the VBO extension.
73
* When calling this function there must be a current OpenGL context.
76
bool OpenGLBuffer::isVBOSupported(uint32_t ctx)
78
auto glue = cc_glglue_instance(ctx);
79
if (!glue || !cc_glglue_has_vertex_buffer_object(glue))
81
const GLubyte * str = glGetString(GL_EXTENSIONS);
84
std::string ext = reinterpret_cast<const char*>(str);
85
return (ext.find("GL_ARB_vertex_buffer_object") != std::string::npos);
88
void OpenGLBuffer::setCurrentContext(uint32_t ctx)
91
glue = cc_glglue_instance(currentContext);
94
bool OpenGLBuffer::create()
99
if (!cc_glglue_has_vertex_buffer_object(glue))
102
cc_glglue_glGenBuffers(glue, 1, &bufferId);
103
context = currentContext;
107
bool OpenGLBuffer::isCreated() const
109
return (bufferId > 0);
112
void OpenGLBuffer::destroy()
114
// schedule delete for all allocated GL resources
116
void * ptr0 = (void*) ((uintptr_t) bufferId);
117
SoGLCacheContextElement::scheduleDeleteCallback(context, buffer_delete, ptr0);
122
void OpenGLBuffer::allocate(const void *data, int count)
125
cc_glglue_glBufferData(glue, target, count, data, GL_STATIC_DRAW);
129
bool OpenGLBuffer::bind()
132
if (context != currentContext) {
133
SoDebugError::postWarning("OpenGLBuffer::bind",
134
"buffer not created");
138
cc_glglue_glBindBuffer(glue, target, bufferId);
144
void OpenGLBuffer::release()
147
cc_glglue_glBindBuffer(glue, target, 0);
151
GLuint OpenGLBuffer::getBufferId() const
156
uint32_t OpenGLBuffer::getBoundContext() const
161
int OpenGLBuffer::size() const
165
cc_glglue_glGetBufferParameteriv(glue, target, GL_BUFFER_SIZE, &value);
170
void OpenGLBuffer::context_destruction_cb(uint32_t context, void * userdata)
172
auto self = static_cast<OpenGLBuffer*>(userdata);
174
if (self->context == context && self->bufferId) {
175
const cc_glglue * glue = cc_glglue_instance((int) context);
176
GLuint buffer = self->bufferId;
177
cc_glglue_glDeleteBuffers(glue, 1, &buffer);
183
void OpenGLBuffer::buffer_delete(void * closure, uint32_t contextid)
185
const cc_glglue * glue = cc_glglue_instance((int) contextid);
186
auto id = (GLuint) ((uintptr_t) closure);
187
cc_glglue_glDeleteBuffers(glue, 1, &id);
190
// ----------------------------------------------------------------------------
192
OpenGLMultiBuffer::OpenGLMultiBuffer(GLenum type)
194
, currentBuf(nullptr)
198
SoContextHandler::addContextDestructionCallback(context_destruction_cb, this);
201
OpenGLMultiBuffer::~OpenGLMultiBuffer()
203
SoContextHandler::removeContextDestructionCallback(context_destruction_cb, this);
208
void OpenGLMultiBuffer::setCurrentContext(uint32_t ctx)
210
currentContext = ctx;
211
glue = cc_glglue_instance(currentContext);
212
currentBuf = &bufs[ctx];
215
bool OpenGLMultiBuffer::create()
220
auto &bufferId = *currentBuf;
224
if (!cc_glglue_has_vertex_buffer_object(glue))
227
cc_glglue_glGenBuffers(glue, 1, &bufferId);
231
bool OpenGLMultiBuffer::isCreated(uint32_t context) const
233
auto it = bufs.find(context);
234
return (it != bufs.end()) && (it->second > 0);
237
void OpenGLMultiBuffer::destroy()
239
// schedule delete for all allocated GL resources
240
for (auto &v : bufs) {
242
void * ptr0 = (void*) ((uintptr_t) v.second);
243
SoGLCacheContextElement::scheduleDeleteCallback(v.first, buffer_delete, ptr0);
248
currentBuf = nullptr;
251
void OpenGLMultiBuffer::allocate(const void *data, int count)
253
if (currentBuf && *currentBuf) {
254
cc_glglue_glBufferData(glue, target, count, data, GL_STATIC_DRAW);
258
bool OpenGLMultiBuffer::bind()
260
if (currentBuf && *currentBuf) {
261
cc_glglue_glBindBuffer(glue, target, *currentBuf);
268
void OpenGLMultiBuffer::release()
270
if (currentBuf && *currentBuf) {
271
cc_glglue_glBindBuffer(glue, target, 0);
275
GLuint OpenGLMultiBuffer::getBufferId() const
277
return currentBuf ? *currentBuf : 0;
280
int OpenGLMultiBuffer::size() const
283
if (currentBuf && *currentBuf) {
284
cc_glglue_glGetBufferParameteriv(glue, target, GL_BUFFER_SIZE, &value);
289
void OpenGLMultiBuffer::context_destruction_cb(uint32_t context, void * userdata)
291
auto self = static_cast<OpenGLMultiBuffer*>(userdata);
293
auto it = self->bufs.find(context);
294
if (it != self->bufs.end() && it->second) {
295
const cc_glglue * glue = cc_glglue_instance((int) context);
296
GLuint buffer = it->second;
297
cc_glglue_glDeleteBuffers(glue, 1, &buffer);
298
if (self->currentBuf == &it->second)
299
self->currentBuf = nullptr;
300
self->bufs.erase(it);
304
void OpenGLMultiBuffer::buffer_delete(void * closure, uint32_t contextid)
306
const cc_glglue * glue = cc_glglue_instance((int) contextid);
307
auto id = (GLuint) ((uintptr_t) closure);
308
cc_glglue_glDeleteBuffers(glue, 1, &id);