FreeCAD

Форк
0
/
GLBuffer.cpp 
309 строк · 8.1 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2018 Werner Mayer <wmayer[at]users.sourceforge.net>     *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include "PreCompiled.h"
25

26
#ifndef FC_OS_WIN32
27
# ifndef GL_GLEXT_PROTOTYPES
28
# define GL_GLEXT_PROTOTYPES 1
29
# endif
30
#endif
31

32
#ifdef FC_OS_MACOSX
33
# include <OpenGL/gl.h>
34
# include <OpenGL/glu.h>
35
# include <OpenGL/glext.h>
36
#else
37
# include <GL/gl.h>
38
# include <GL/glu.h>
39
# include <GL/glext.h>
40
#endif
41

42
#include <Inventor/elements/SoGLCacheContextElement.h>
43
#include <Inventor/errors/SoDebugError.h>
44
#include <Inventor/misc/SoContextHandler.h>
45

46
#include <string>
47

48
#include "GLBuffer.h"
49

50
using namespace Gui;
51

52

53
OpenGLBuffer::OpenGLBuffer(GLenum type)
54
  : target(type)
55
  , bufferId(0)
56
  , context(-1)
57
  , currentContext(-1)
58
  , glue(nullptr)
59
{
60
    SoContextHandler::addContextDestructionCallback(context_destruction_cb, this);
61
}
62

63
OpenGLBuffer::~OpenGLBuffer()
64
{
65
    SoContextHandler::removeContextDestructionCallback(context_destruction_cb, this);
66

67
    destroy();
68
}
69

70
/*!
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.
74
 * \return
75
 */
76
bool OpenGLBuffer::isVBOSupported(uint32_t ctx)
77
{
78
    auto glue = cc_glglue_instance(ctx);
79
    if (!glue || !cc_glglue_has_vertex_buffer_object(glue))
80
        return false;
81
    const GLubyte * str = glGetString(GL_EXTENSIONS);
82
    if (!str)
83
        return false;
84
    std::string ext = reinterpret_cast<const char*>(str);
85
    return (ext.find("GL_ARB_vertex_buffer_object") != std::string::npos);
86
}
87

88
void OpenGLBuffer::setCurrentContext(uint32_t ctx)
89
{
90
    currentContext = ctx;
91
    glue = cc_glglue_instance(currentContext);
92
}
93

94
bool OpenGLBuffer::create()
95
{
96
    if (bufferId > 0)
97
        return true;
98

99
    if (!cc_glglue_has_vertex_buffer_object(glue))
100
        return false;
101

102
    cc_glglue_glGenBuffers(glue, 1, &bufferId);
103
    context = currentContext;
104
    return true;
105
}
106

107
bool OpenGLBuffer::isCreated() const
108
{
109
    return (bufferId > 0);
110
}
111

112
void OpenGLBuffer::destroy()
113
{
114
    // schedule delete for all allocated GL resources
115
    if (bufferId > 0) {
116
        void * ptr0 = (void*) ((uintptr_t) bufferId);
117
        SoGLCacheContextElement::scheduleDeleteCallback(context, buffer_delete, ptr0);
118
        bufferId = 0;
119
    }
120
}
121

122
void OpenGLBuffer::allocate(const void *data, int count)
123
{
124
    if (bufferId > 0) {
125
        cc_glglue_glBufferData(glue, target, count, data, GL_STATIC_DRAW);
126
    }
127
}
128

129
bool OpenGLBuffer::bind()
130
{
131
    if (bufferId) {
132
        if (context != currentContext) {
133
            SoDebugError::postWarning("OpenGLBuffer::bind",
134
                                      "buffer not created");
135
            return false;
136
        }
137

138
        cc_glglue_glBindBuffer(glue, target, bufferId);
139
        return true;
140
    }
141
    return false;
142
}
143

144
void OpenGLBuffer::release()
145
{
146
    if (bufferId) {
147
        cc_glglue_glBindBuffer(glue, target, 0);
148
    }
149
}
150

151
GLuint OpenGLBuffer::getBufferId() const
152
{
153
    return bufferId;
154
}
155

156
uint32_t OpenGLBuffer::getBoundContext() const
157
{
158
    return context;
159
}
160

161
int OpenGLBuffer::size() const
162
{
163
    GLint value = -1;
164
    if (bufferId > 0) {
165
        cc_glglue_glGetBufferParameteriv(glue, target, GL_BUFFER_SIZE, &value);
166
    }
167
    return value;
168
}
169

170
void OpenGLBuffer::context_destruction_cb(uint32_t context, void * userdata)
171
{
172
    auto self = static_cast<OpenGLBuffer*>(userdata);
173

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);
178
        self->context = -1;
179
        self->bufferId = 0;
180
    }
181
}
182

183
void OpenGLBuffer::buffer_delete(void * closure, uint32_t contextid)
184
{
185
    const cc_glglue * glue = cc_glglue_instance((int) contextid);
186
    auto id = (GLuint) ((uintptr_t) closure);
187
    cc_glglue_glDeleteBuffers(glue, 1, &id);
188
}
189

190
// ----------------------------------------------------------------------------
191

192
OpenGLMultiBuffer::OpenGLMultiBuffer(GLenum type)
193
  : target(type)
194
  , currentBuf(nullptr)
195
  , currentContext(-1)
196
  , glue(nullptr)
197
{
198
    SoContextHandler::addContextDestructionCallback(context_destruction_cb, this);
199
}
200

201
OpenGLMultiBuffer::~OpenGLMultiBuffer()
202
{
203
    SoContextHandler::removeContextDestructionCallback(context_destruction_cb, this);
204

205
    destroy();
206
}
207

208
void OpenGLMultiBuffer::setCurrentContext(uint32_t ctx)
209
{
210
    currentContext = ctx;
211
    glue = cc_glglue_instance(currentContext);
212
    currentBuf = &bufs[ctx];
213
}
214

215
bool OpenGLMultiBuffer::create()
216
{
217
    if (!currentBuf)
218
        return false;
219

220
    auto &bufferId = *currentBuf;
221
    if (bufferId > 0)
222
        return true;
223

224
    if (!cc_glglue_has_vertex_buffer_object(glue))
225
        return false;
226

227
    cc_glglue_glGenBuffers(glue, 1, &bufferId);
228
    return true;
229
}
230

231
bool OpenGLMultiBuffer::isCreated(uint32_t context) const
232
{
233
    auto it = bufs.find(context);
234
    return (it != bufs.end()) && (it->second > 0);
235
}
236

237
void OpenGLMultiBuffer::destroy()
238
{
239
    // schedule delete for all allocated GL resources
240
    for (auto &v : bufs) {
241
        if (v.second > 0) {
242
            void * ptr0 = (void*) ((uintptr_t) v.second);
243
            SoGLCacheContextElement::scheduleDeleteCallback(v.first, buffer_delete, ptr0);
244
        }
245
    }
246

247
    bufs.clear();
248
    currentBuf = nullptr;
249
}
250

251
void OpenGLMultiBuffer::allocate(const void *data, int count)
252
{
253
    if (currentBuf && *currentBuf) {
254
        cc_glglue_glBufferData(glue, target, count, data, GL_STATIC_DRAW);
255
    }
256
}
257

258
bool OpenGLMultiBuffer::bind()
259
{
260
    if (currentBuf && *currentBuf) {
261
        cc_glglue_glBindBuffer(glue, target, *currentBuf);
262
        return true;
263
    }
264

265
    return false;
266
}
267

268
void OpenGLMultiBuffer::release()
269
{
270
    if (currentBuf && *currentBuf) {
271
        cc_glglue_glBindBuffer(glue, target, 0);
272
    }
273
}
274

275
GLuint OpenGLMultiBuffer::getBufferId() const
276
{
277
    return currentBuf ? *currentBuf : 0;
278
}
279

280
int OpenGLMultiBuffer::size() const
281
{
282
    GLint value = -1;
283
    if (currentBuf && *currentBuf) {
284
        cc_glglue_glGetBufferParameteriv(glue, target, GL_BUFFER_SIZE, &value);
285
    }
286
    return value;
287
}
288

289
void OpenGLMultiBuffer::context_destruction_cb(uint32_t context, void * userdata)
290
{
291
    auto self = static_cast<OpenGLMultiBuffer*>(userdata);
292

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);
301
    }
302
}
303

304
void OpenGLMultiBuffer::buffer_delete(void * closure, uint32_t contextid)
305
{
306
    const cc_glglue * glue = cc_glglue_instance((int) contextid);
307
    auto id = (GLuint) ((uintptr_t) closure);
308
    cc_glglue_glDeleteBuffers(glue, 1, &id);
309
}
310

311

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.