1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2013-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <OpenGl_Buffer.hxx>
16
17 #include <OpenGl_GlCore30.hxx>
18 #include <OpenGl_Context.hxx>
19 #include <OpenGl_ShaderManager.hxx>
20 #include <Standard_Assert.hxx>
21
IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Buffer,OpenGl_Resource)22 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Buffer, OpenGl_Resource)
23
24 // =======================================================================
25 // function : sizeOfGlType
26 // purpose :
27 // =======================================================================
28 size_t OpenGl_Buffer::sizeOfGlType (unsigned int theType)
29 {
30 switch (theType)
31 {
32 case GL_BYTE:
33 case GL_UNSIGNED_BYTE: return sizeof(Standard_Byte);
34 case GL_SHORT:
35 case GL_UNSIGNED_SHORT: return sizeof(unsigned short);
36 #ifdef GL_INT
37 case GL_INT:
38 #endif
39 case GL_UNSIGNED_INT: return sizeof(unsigned int);
40 case GL_FLOAT: return sizeof(float);
41 #ifdef GL_DOUBLE
42 case GL_DOUBLE: return sizeof(double);
43 #endif
44 default: return 0;
45 }
46 }
47
48 // =======================================================================
49 // function : FormatTarget
50 // purpose :
51 // =======================================================================
FormatTarget(unsigned int theTarget)52 TCollection_AsciiString OpenGl_Buffer::FormatTarget (unsigned int theTarget)
53 {
54 switch (theTarget)
55 {
56 case GL_ARRAY_BUFFER: return "GL_ARRAY_BUFFER";
57 case GL_ELEMENT_ARRAY_BUFFER: return "GL_ELEMENT_ARRAY_BUFFER";
58 case GL_PIXEL_UNPACK_BUFFER: return "GL_PIXEL_UNPACK_BUFFER";
59 case GL_PIXEL_PACK_BUFFER: return "GL_PIXEL_PACK_BUFFER";
60 case GL_UNIFORM_BUFFER: return "GL_UNIFORM_BUFFER";
61 case GL_TEXTURE_BUFFER: return "GL_TEXTURE_BUFFER";
62 case GL_COPY_READ_BUFFER: return "GL_COPY_READ_BUFFER";
63 case GL_COPY_WRITE_BUFFER: return "GL_COPY_WRITE_BUFFER";
64 case GL_TRANSFORM_FEEDBACK_BUFFER: return "GL_TRANSFORM_FEEDBACK_BUFFER";
65 #ifdef GL_QUERY_BUFFER
66 case GL_QUERY_BUFFER: return "GL_QUERY_BUFFER";
67 case GL_DRAW_INDIRECT_BUFFER: return "GL_DRAW_INDIRECT_BUFFER";
68 case GL_ATOMIC_COUNTER_BUFFER: return "GL_ATOMIC_COUNTER_BUFFER";
69 case GL_DISPATCH_INDIRECT_BUFFER: return "GL_DISPATCH_INDIRECT_BUFFER";
70 case GL_SHADER_STORAGE_BUFFER: return "GL_SHADER_STORAGE_BUFFER";
71 #endif
72 }
73 return OpenGl_Context::FormatGlEnumHex (theTarget);
74 }
75
76 // =======================================================================
77 // function : OpenGl_Buffer
78 // purpose :
79 // =======================================================================
OpenGl_Buffer()80 OpenGl_Buffer::OpenGl_Buffer()
81 : OpenGl_Resource(),
82 myOffset (NULL),
83 myBufferId (NO_BUFFER),
84 myComponentsNb (4),
85 myElemsNb (0),
86 myDataType (GL_FLOAT)
87 {
88 //
89 }
90
91 // =======================================================================
92 // function : ~OpenGl_Buffer
93 // purpose :
94 // =======================================================================
~OpenGl_Buffer()95 OpenGl_Buffer::~OpenGl_Buffer()
96 {
97 Release (NULL);
98 }
99
100 // =======================================================================
101 // function : Create
102 // purpose :
103 // =======================================================================
Create(const Handle (OpenGl_Context)& theGlCtx)104 bool OpenGl_Buffer::Create (const Handle(OpenGl_Context)& theGlCtx)
105 {
106 if (myBufferId == NO_BUFFER && theGlCtx->core15fwd != NULL)
107 {
108 theGlCtx->core15fwd->glGenBuffers (1, &myBufferId);
109 }
110 return myBufferId != NO_BUFFER;
111 }
112
113 // =======================================================================
114 // function : Release
115 // purpose :
116 // =======================================================================
Release(OpenGl_Context * theGlCtx)117 void OpenGl_Buffer::Release (OpenGl_Context* theGlCtx)
118 {
119 if (myBufferId == NO_BUFFER)
120 {
121 return;
122 }
123
124 // application can not handle this case by exception - this is bug in code
125 Standard_ASSERT_RETURN (theGlCtx != NULL,
126 "OpenGl_Buffer destroyed without GL context! Possible GPU memory leakage...",);
127
128 if (theGlCtx->IsValid())
129 {
130 theGlCtx->core15fwd->glDeleteBuffers (1, &myBufferId);
131 }
132 myOffset = NULL;
133 myBufferId = NO_BUFFER;
134 }
135
136 // =======================================================================
137 // function : Bind
138 // purpose :
139 // =======================================================================
Bind(const Handle (OpenGl_Context)& theGlCtx) const140 void OpenGl_Buffer::Bind (const Handle(OpenGl_Context)& theGlCtx) const
141 {
142 theGlCtx->core15fwd->glBindBuffer (GetTarget(), myBufferId);
143 }
144
145 // =======================================================================
146 // function : Unbind
147 // purpose :
148 // =======================================================================
Unbind(const Handle (OpenGl_Context)& theGlCtx) const149 void OpenGl_Buffer::Unbind (const Handle(OpenGl_Context)& theGlCtx) const
150 {
151 theGlCtx->core15fwd->glBindBuffer (GetTarget(), NO_BUFFER);
152 }
153
154 // =======================================================================
155 // function : BindBufferBase
156 // purpose :
157 // =======================================================================
BindBufferBase(const Handle (OpenGl_Context)& theGlCtx,unsigned int theIndex)158 void OpenGl_Buffer::BindBufferBase (const Handle(OpenGl_Context)& theGlCtx,
159 unsigned int theIndex)
160 {
161 theGlCtx->core30->glBindBufferBase (GetTarget(), theIndex, myBufferId);
162 }
163
164 // =======================================================================
165 // function : UnbindBufferBase
166 // purpose :
167 // =======================================================================
UnbindBufferBase(const Handle (OpenGl_Context)& theGlCtx,unsigned int theIndex)168 void OpenGl_Buffer::UnbindBufferBase (const Handle(OpenGl_Context)& theGlCtx,
169 unsigned int theIndex)
170 {
171 theGlCtx->core30->glBindBufferBase (GetTarget(), theIndex, NO_BUFFER);
172 }
173
174 // =======================================================================
175 // function : BindBufferRange
176 // purpose :
177 // =======================================================================
BindBufferRange(const Handle (OpenGl_Context)& theGlCtx,unsigned int theIndex,const intptr_t theOffset,const size_t theSize)178 void OpenGl_Buffer::BindBufferRange (const Handle(OpenGl_Context)& theGlCtx,
179 unsigned int theIndex,
180 const intptr_t theOffset,
181 const size_t theSize)
182 {
183 theGlCtx->core30->glBindBufferRange (GetTarget(), theIndex, myBufferId, (GLintptr )theOffset, (GLsizeiptr )theSize);
184 }
185
186 // =======================================================================
187 // function : Init
188 // purpose :
189 // =======================================================================
Init(const Handle (OpenGl_Context)& theGlCtx,const unsigned int theComponentsNb,const Standard_Integer theElemsNb,const float * theData)190 bool OpenGl_Buffer::Init (const Handle(OpenGl_Context)& theGlCtx,
191 const unsigned int theComponentsNb,
192 const Standard_Integer theElemsNb,
193 const float* theData)
194 {
195 return init (theGlCtx, theComponentsNb, theElemsNb, theData, GL_FLOAT);
196 }
197
198 // =======================================================================
199 // function : Init
200 // purpose :
201 // =======================================================================
Init(const Handle (OpenGl_Context)& theGlCtx,const unsigned int theComponentsNb,const Standard_Integer theElemsNb,const unsigned int * theData)202 bool OpenGl_Buffer::Init (const Handle(OpenGl_Context)& theGlCtx,
203 const unsigned int theComponentsNb,
204 const Standard_Integer theElemsNb,
205 const unsigned int* theData)
206 {
207 return init (theGlCtx, theComponentsNb, theElemsNb, theData, GL_UNSIGNED_INT);
208 }
209
210 // =======================================================================
211 // function : Init
212 // purpose :
213 // =======================================================================
Init(const Handle (OpenGl_Context)& theGlCtx,const unsigned int theComponentsNb,const Standard_Integer theElemsNb,const unsigned short * theData)214 bool OpenGl_Buffer::Init (const Handle(OpenGl_Context)& theGlCtx,
215 const unsigned int theComponentsNb,
216 const Standard_Integer theElemsNb,
217 const unsigned short* theData)
218 {
219 return init (theGlCtx, theComponentsNb, theElemsNb, theData, GL_UNSIGNED_SHORT);
220 }
221
222 // =======================================================================
223 // function : Init
224 // purpose :
225 // =======================================================================
Init(const Handle (OpenGl_Context)& theGlCtx,const unsigned int theComponentsNb,const Standard_Integer theElemsNb,const Standard_Byte * theData)226 bool OpenGl_Buffer::Init (const Handle(OpenGl_Context)& theGlCtx,
227 const unsigned int theComponentsNb,
228 const Standard_Integer theElemsNb,
229 const Standard_Byte* theData)
230 {
231 return init (theGlCtx, theComponentsNb, theElemsNb, theData, GL_UNSIGNED_BYTE);
232 }
233
234 // =======================================================================
235 // function : init
236 // purpose :
237 // =======================================================================
init(const Handle (OpenGl_Context)& theGlCtx,const unsigned int theComponentsNb,const Standard_Integer theElemsNb,const void * theData,const unsigned int theDataType,const Standard_Integer theStride)238 bool OpenGl_Buffer::init (const Handle(OpenGl_Context)& theGlCtx,
239 const unsigned int theComponentsNb,
240 const Standard_Integer theElemsNb,
241 const void* theData,
242 const unsigned int theDataType,
243 const Standard_Integer theStride)
244 {
245 if (!Create (theGlCtx))
246 {
247 return false;
248 }
249
250 Bind (theGlCtx);
251 myDataType = theDataType;
252 myComponentsNb = theComponentsNb;
253 myElemsNb = theElemsNb;
254 theGlCtx->core15fwd->glBufferData (GetTarget(), GLsizeiptr(myElemsNb) * theStride, theData, GL_STATIC_DRAW);
255 const int anErr = theGlCtx->core15fwd->glGetError();
256 if (anErr != GL_NO_ERROR
257 && anErr != GL_OUT_OF_MEMORY) // pass-through out-of-memory error, but log unexpected errors
258 {
259 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
260 TCollection_AsciiString ("Error: glBufferData (")
261 + FormatTarget (GetTarget()) + ","
262 + OpenGl_Context::FormatSize (GLsizeiptr(myElemsNb) * theStride) + ","
263 + OpenGl_Context::FormatPointer (theData) + ") Id: " + (int )myBufferId
264 + " failed with " + OpenGl_Context::FormatGlError (anErr));
265 }
266 Unbind (theGlCtx);
267 return anErr == GL_NO_ERROR;
268 }
269
270 // =======================================================================
271 // function : SubData
272 // purpose :
273 // =======================================================================
SubData(const Handle (OpenGl_Context)& theGlCtx,const Standard_Integer theElemFrom,const Standard_Integer theElemsNb,const float * theData)274 bool OpenGl_Buffer::SubData (const Handle(OpenGl_Context)& theGlCtx,
275 const Standard_Integer theElemFrom,
276 const Standard_Integer theElemsNb,
277 const float* theData)
278 {
279 return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_FLOAT);
280 }
281
282 // =======================================================================
283 // function : SubData
284 // purpose :
285 // =======================================================================
SubData(const Handle (OpenGl_Context)& theGlCtx,const Standard_Integer theElemFrom,const Standard_Integer theElemsNb,const unsigned int * theData)286 bool OpenGl_Buffer::SubData (const Handle(OpenGl_Context)& theGlCtx,
287 const Standard_Integer theElemFrom,
288 const Standard_Integer theElemsNb,
289 const unsigned int* theData)
290 {
291 return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_INT);
292 }
293
294 // =======================================================================
295 // function : SubData
296 // purpose :
297 // =======================================================================
SubData(const Handle (OpenGl_Context)& theGlCtx,const Standard_Integer theElemFrom,const Standard_Integer theElemsNb,const unsigned short * theData)298 bool OpenGl_Buffer::SubData (const Handle(OpenGl_Context)& theGlCtx,
299 const Standard_Integer theElemFrom,
300 const Standard_Integer theElemsNb,
301 const unsigned short* theData)
302 {
303 return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_SHORT);
304 }
305
306 // =======================================================================
307 // function : SubData
308 // purpose :
309 // =======================================================================
SubData(const Handle (OpenGl_Context)& theGlCtx,const Standard_Integer theElemFrom,const Standard_Integer theElemsNb,const Standard_Byte * theData)310 bool OpenGl_Buffer::SubData (const Handle(OpenGl_Context)& theGlCtx,
311 const Standard_Integer theElemFrom,
312 const Standard_Integer theElemsNb,
313 const Standard_Byte* theData)
314 {
315 return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_BYTE);
316 }
317
318 // =======================================================================
319 // function : subData
320 // purpose :
321 // =======================================================================
subData(const Handle (OpenGl_Context)& theGlCtx,const Standard_Integer theElemFrom,const Standard_Integer theElemsNb,const void * theData,const unsigned int theDataType)322 bool OpenGl_Buffer::subData (const Handle(OpenGl_Context)& theGlCtx,
323 const Standard_Integer theElemFrom,
324 const Standard_Integer theElemsNb,
325 const void* theData,
326 const unsigned int theDataType)
327 {
328 if (!IsValid() || myDataType != theDataType ||
329 theElemFrom < 0 || ((theElemFrom + theElemsNb) > myElemsNb))
330 {
331 return false;
332 }
333
334 Bind (theGlCtx);
335 const size_t aDataSize = sizeOfGlType (theDataType);
336 theGlCtx->core15fwd->glBufferSubData (GetTarget(),
337 GLintptr(theElemFrom) * GLintptr (myComponentsNb) * aDataSize, // offset in bytes
338 GLsizeiptr(theElemsNb) * GLsizeiptr(myComponentsNb) * aDataSize, // size in bytes
339 theData);
340 const int anErr = theGlCtx->core15fwd->glGetError();
341 if (anErr != GL_NO_ERROR)
342 {
343 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
344 TCollection_AsciiString ("Error: glBufferSubData (")
345 + FormatTarget (GetTarget()) + ","
346 + OpenGl_Context::FormatSize (GLintptr(theElemFrom) * GLintptr (myComponentsNb) * aDataSize) + ","
347 + OpenGl_Context::FormatSize (GLsizeiptr(theElemsNb) * GLsizeiptr(myComponentsNb) * aDataSize) + ","
348 + OpenGl_Context::FormatPointer (theData) + ") Id: " + (int )myBufferId
349 + " failed with " + OpenGl_Context::FormatGlError (anErr));
350 }
351 Unbind (theGlCtx);
352 return anErr == GL_NO_ERROR;
353 }
354
355 // =======================================================================
356 // function : subData
357 // purpose :
358 // =======================================================================
GetSubData(const Handle (OpenGl_Context)& theGlCtx,const Standard_Integer theElemFrom,const Standard_Integer theElemsNb,float * theData)359 bool OpenGl_Buffer::GetSubData (const Handle(OpenGl_Context)& theGlCtx,
360 const Standard_Integer theElemFrom,
361 const Standard_Integer theElemsNb,
362 float* theData)
363 {
364 return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_FLOAT);
365 }
366
367 // =======================================================================
368 // function : GetSubData
369 // purpose :
370 // =======================================================================
GetSubData(const Handle (OpenGl_Context)& theGlCtx,const Standard_Integer theElemFrom,const Standard_Integer theElemsNb,unsigned short * theData)371 bool OpenGl_Buffer::GetSubData (const Handle(OpenGl_Context)& theGlCtx,
372 const Standard_Integer theElemFrom,
373 const Standard_Integer theElemsNb,
374 unsigned short* theData)
375 {
376 return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_SHORT);
377 }
378
379 // =======================================================================
380 // function : GetSubData
381 // purpose :
382 // =======================================================================
GetSubData(const Handle (OpenGl_Context)& theGlCtx,const Standard_Integer theElemFrom,const Standard_Integer theElemsNb,unsigned int * theData)383 bool OpenGl_Buffer::GetSubData (const Handle(OpenGl_Context)& theGlCtx,
384 const Standard_Integer theElemFrom,
385 const Standard_Integer theElemsNb,
386 unsigned int* theData)
387 {
388 return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_INT);
389 }
390
391 // =======================================================================
392 // function : GetSubData
393 // purpose :
394 // =======================================================================
GetSubData(const Handle (OpenGl_Context)& theGlCtx,const Standard_Integer theElemFrom,const Standard_Integer theElemsNb,Standard_Byte * theData)395 bool OpenGl_Buffer::GetSubData (const Handle(OpenGl_Context)& theGlCtx,
396 const Standard_Integer theElemFrom,
397 const Standard_Integer theElemsNb,
398 Standard_Byte* theData)
399 {
400 return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_BYTE);
401 }
402
403 // =======================================================================
404 // function : getSubData
405 // purpose :
406 // =======================================================================
getSubData(const Handle (OpenGl_Context)& theGlCtx,const Standard_Integer theElemFrom,const Standard_Integer theElemsNb,void * theData,const unsigned int theDataType)407 bool OpenGl_Buffer::getSubData (const Handle(OpenGl_Context)& theGlCtx,
408 const Standard_Integer theElemFrom,
409 const Standard_Integer theElemsNb,
410 void* theData,
411 const unsigned int theDataType)
412 {
413 if (!IsValid() || myDataType != theDataType
414 || theElemFrom < 0 || ((theElemFrom + theElemsNb) > myElemsNb)
415 || !theGlCtx->hasGetBufferData)
416 {
417 return false;
418 }
419
420 Bind (theGlCtx);
421 const size_t aDataSize = sizeOfGlType (theDataType);
422 const GLintptr anOffset = GLintptr (theElemFrom) * GLintptr (myComponentsNb) * aDataSize;
423 const GLsizeiptr aSize = GLsizeiptr(theElemsNb) * GLsizeiptr(myComponentsNb) * aDataSize;
424 bool isDone = theGlCtx->GetBufferSubData (GetTarget(), anOffset, aSize, theData);
425 isDone = isDone && (theGlCtx->core15fwd->glGetError() == GL_NO_ERROR);
426 Unbind (theGlCtx);
427 return isDone;
428 }
429
430 // =======================================================================
431 // function : DumpJson
432 // purpose :
433 // =======================================================================
DumpJson(Standard_OStream & theOStream,Standard_Integer theDepth) const434 void OpenGl_Buffer::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
435 {
436 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
437 OCCT_DUMP_BASE_CLASS (theOStream, theDepth, OpenGl_Resource)
438
439 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, GetTarget())
440 OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myOffset)
441
442 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myBufferId)
443 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myComponentsNb)
444 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myElemsNb)
445 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDataType)
446 }
447