1220d98e |
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 | } |