0032121: Draw Harness, ViewerTest - implement -reset option for vlight command
[occt.git] / src / OpenGl / OpenGl_Buffer.cxx
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
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
95 OpenGl_Buffer::~OpenGl_Buffer()
96 {
97   Release (NULL);
98 }
99
100 // =======================================================================
101 // function : Create
102 // purpose  :
103 // =======================================================================
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 // =======================================================================
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 // =======================================================================
140 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 // =======================================================================
149 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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
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 // =======================================================================
434 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 }