0026292: Visualization - Parallelize queue-based BVH builders (subclasses of BVH_Queu...
[occt.git] / src / OpenGl / OpenGl_SceneGeometry.cxx
1 // Created on: 2013-08-27
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2013 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OSD_Timer.hxx>
17 #include <OSD_Parallel.hxx>
18 #include <Standard_Assert.hxx>
19 #include <OpenGl_ArbTexBindless.hxx>
20 #include <OpenGl_PrimitiveArray.hxx>
21 #include <OpenGl_SceneGeometry.hxx>
22 #include <OpenGl_Structure.hxx>
23 #include <Graphic3d_GraphicDriver.hxx>
24
25 //! Use this macro to output BVH profiling info
26 // #define RAY_TRACE_PRINT_INFO
27
28 namespace
29 {
30   //! Useful constant for null floating-point 4D vector.
31   static const BVH_Vec4f ZERO_VEC_4F;
32 }
33
34 // =======================================================================
35 // function : OpenGl_RaytraceMaterial
36 // purpose  : Creates new default material
37 // =======================================================================
38 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial()
39 : Ambient      (ZERO_VEC_4F),
40   Diffuse      (ZERO_VEC_4F),
41   Specular     (ZERO_VEC_4F),
42   Emission     (ZERO_VEC_4F),
43   Reflection   (ZERO_VEC_4F),
44   Refraction   (ZERO_VEC_4F),
45   Transparency (ZERO_VEC_4F)
46 { }
47
48 // =======================================================================
49 // function : OpenGl_RaytraceMaterial
50 // purpose  : Creates new material with specified properties
51 // =======================================================================
52 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
53                                                   const BVH_Vec4f& theDiffuse,
54                                                   const BVH_Vec4f& theSpecular)
55 : Ambient      (theAmbient),
56   Diffuse      (theDiffuse),
57   Specular     (theSpecular),
58   Emission     (ZERO_VEC_4F),
59   Reflection   (ZERO_VEC_4F),
60   Refraction   (ZERO_VEC_4F),
61   Transparency (ZERO_VEC_4F)
62 {
63   //
64 }
65
66 // =======================================================================
67 // function : OpenGl_RaytraceMaterial
68 // purpose  : Creates new material with specified properties
69 // =======================================================================
70 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
71                                                   const BVH_Vec4f& theDiffuse,
72                                                   const BVH_Vec4f& theSpecular,
73                                                   const BVH_Vec4f& theEmission,
74                                                   const BVH_Vec4f& theTranspar)
75 : Ambient      (theAmbient),
76   Diffuse      (theDiffuse),
77   Specular     (theSpecular),
78   Emission     (theEmission),
79   Reflection   (ZERO_VEC_4F),
80   Refraction   (ZERO_VEC_4F),
81   Transparency (theTranspar)
82 {
83   //
84 }
85
86 // =======================================================================
87 // function : OpenGl_RaytraceMaterial
88 // purpose  : Creates new material with specified properties
89 // =======================================================================
90 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
91                                                   const BVH_Vec4f& theDiffuse,
92                                                   const BVH_Vec4f& theSpecular,
93                                                   const BVH_Vec4f& theEmission,
94                                                   const BVH_Vec4f& theTranspar,
95                                                   const BVH_Vec4f& theReflection,
96                                                   const BVH_Vec4f& theRefraction)
97 : Ambient      (theAmbient),
98   Diffuse      (theDiffuse),
99   Specular     (theSpecular),
100   Emission     (theEmission),
101   Reflection   (theReflection),
102   Refraction   (theRefraction),
103   Transparency (theTranspar)
104 {
105   //
106 }
107
108 // =======================================================================
109 // function : OpenGl_LightSource
110 // purpose  : Creates new light source
111 // =======================================================================
112 OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
113                                             const BVH_Vec4f& thePosition)
114 : Diffuse (theDiffuse),
115   Position (thePosition)
116 {
117   //
118 }
119
120 // =======================================================================
121 // function : Center
122 // purpose  : Returns centroid position along the given axis
123 // =======================================================================
124 Standard_ShortReal OpenGl_TriangleSet::Center (
125   const Standard_Integer theIndex, const Standard_Integer theAxis) const
126 {
127   // Note: Experiments show that the use of the box centroid (instead
128   // of the triangle centroid) increases render performance up to 12%
129
130   const BVH_Vec4i& aTriangle = Elements[theIndex];
131
132   const Standard_ShortReal aVertex0 =
133     BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.x()], theAxis);
134   const Standard_ShortReal aVertex1 =
135     BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.y()], theAxis);
136   const Standard_ShortReal aVertex2 =
137     BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.z()], theAxis);
138
139   return (Min (Min (aVertex0, aVertex1), aVertex2) +
140           Max (Max (aVertex0, aVertex1), aVertex2)) * 0.5f;
141 }
142
143 // =======================================================================
144 // function : Box
145 // purpose  : Returns AABB of primitive set
146 // =======================================================================
147 OpenGl_TriangleSet::BVH_BoxNt OpenGl_TriangleSet::Box() const
148 {
149   const BVH_Transform<Standard_ShortReal, 4>* aTransform =
150     dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (Properties().operator->());
151
152   BVH_BoxNt aBox = BVH_PrimitiveSet<Standard_ShortReal, 3>::Box();
153
154   if (aTransform != NULL)
155   {
156     BVH_BoxNt aTransformedBox;
157
158     for (Standard_Integer aX = 0; aX <= 1; ++aX)
159     {
160       for (Standard_Integer aY = 0; aY <= 1; ++aY)
161       {
162         for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
163         {
164           BVH_Vec4f aCorner = aTransform->Transform() * BVH_Vec4f (
165             aX == 0 ? aBox.CornerMin().x() : aBox.CornerMax().x(),
166             aY == 0 ? aBox.CornerMin().y() : aBox.CornerMax().y(),
167             aZ == 0 ? aBox.CornerMin().z() : aBox.CornerMax().z(),
168             1.f);
169
170           aTransformedBox.Add (reinterpret_cast<BVH_Vec3f&> (aCorner));
171         }
172       }
173     }
174
175     return aTransformedBox;
176   }
177
178   return aBox;
179 }
180
181 // =======================================================================
182 // function : OpenGl_TriangleSet
183 // purpose  : Creates new OpenGL element triangulation
184 // =======================================================================
185 OpenGl_TriangleSet::OpenGl_TriangleSet (const Standard_Size theArrayID)
186 : BVH_Triangulation<Standard_ShortReal, 3>(),
187   myArrayID (theArrayID)
188 {
189   myBuilder = new BVH_BinnedBuilder<Standard_ShortReal, 3 /* dim */, 48 /* bins */>
190     (5 /* leaf size */, 32 /* max height */, Standard_False, OSD_Parallel::NbLogicalProcessors() + 1 /* threads */);
191 }
192
193 // =======================================================================
194 // function : Clear
195 // purpose  : Clears ray-tracing geometry
196 // =======================================================================
197 void OpenGl_RaytraceGeometry::Clear()
198 {
199   BVH_Geometry<Standard_ShortReal, 3>::BVH_Geometry::Clear();
200
201   std::vector<OpenGl_RaytraceLight,
202     NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
203
204   Sources.swap (anEmptySources);
205
206   std::vector<OpenGl_RaytraceMaterial,
207     NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
208
209   Materials.swap (anEmptyMaterials);
210 }
211
212 struct OpenGL_BVHParallelBuilder
213 {
214   BVH_ObjectSet<Standard_ShortReal, 3>* Set;
215
216   OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 3>* theSet)
217   : Set (theSet)
218   {
219     //
220   }
221
222   void operator() (const Standard_Integer theObjectIdx) const
223   {
224     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
225       Set->Objects().ChangeValue (static_cast<Standard_Integer> (theObjectIdx)).operator->());
226
227     if (aTriangleSet != NULL)
228       aTriangleSet->BVH();
229   }
230 };
231
232 // =======================================================================
233 // function : ProcessAcceleration
234 // purpose  : Performs post-processing of high-level BVH
235 // =======================================================================
236 Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
237 {
238 #ifdef RAY_TRACE_PRINT_INFO
239     OSD_Timer aTimer;
240 #endif
241
242   MarkDirty(); // force BVH rebuilding
243
244 #ifdef RAY_TRACE_PRINT_INFO
245   aTimer.Reset();
246   aTimer.Start();
247 #endif
248
249   OSD_Parallel::For(0, Size(), OpenGL_BVHParallelBuilder(this));
250
251   myBottomLevelTreeDepth = 0;
252
253   for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
254   {
255     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
256       myObjects.ChangeValue (anObjectIdx).operator->());
257
258     Standard_ASSERT_RETURN (aTriangleSet != NULL,
259       "Error! Failed to get triangulation of OpenGL element", Standard_False);
260
261     Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
262       "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
263
264     myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth());
265   }
266
267 #ifdef RAY_TRACE_PRINT_INFO
268   aTimer.Stop();
269
270   std::cout << "Updating bottom-level BVHs (sec): " <<
271     aTimer.ElapsedTime() << std::endl;
272 #endif
273
274 #ifdef RAY_TRACE_PRINT_INFO
275   aTimer.Reset();
276   aTimer.Start();
277 #endif
278
279   NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> > aBVH = BVH();
280
281 #ifdef RAY_TRACE_PRINT_INFO
282   aTimer.Stop();
283
284   std::cout << "Updating high-level BVH (sec): " <<
285     aTimer.ElapsedTime() << std::endl;
286 #endif
287
288   Standard_ASSERT_RETURN (!aBVH.IsNull(),
289     "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
290
291   myHighLevelTreeDepth = aBVH->Depth();
292
293   Standard_Integer aVerticesOffset = 0;
294   Standard_Integer aElementsOffset = 0;
295   Standard_Integer aBVHNodesOffset = BVH()->Length();
296
297   for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
298   {
299     if (!aBVH->IsOuter (aNodeIdx))
300       continue;
301
302     Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
303       "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
304
305     Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
306
307     Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
308       "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
309
310     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
311       myObjects.ChangeValue (anObjectIdx).operator->());
312
313     // Note: We overwrite node info record to store parameters
314     // of bottom-level BVH and triangulation of OpenGL element
315
316     aBVH->NodeInfoBuffer().at (aNodeIdx) = BVH_Vec4i (
317       anObjectIdx + 1 /* to keep leaf flag */, aBVHNodesOffset, aVerticesOffset, aElementsOffset);
318
319     aVerticesOffset += (int)aTriangleSet->Vertices.size();
320     aElementsOffset += (int)aTriangleSet->Elements.size();
321     aBVHNodesOffset += aTriangleSet->BVH()->Length();
322   }
323
324   return Standard_True;
325 }
326
327 // =======================================================================
328 // function : AccelerationOffset
329 // purpose  : Returns offset of bottom-level BVH for given leaf node
330 // =======================================================================
331 Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
332 {
333   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
334
335   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
336     return INVALID_OFFSET;
337
338   return aBVH->NodeInfoBuffer().at (theNodeIdx).y();
339 }
340
341 // =======================================================================
342 // function : VerticesOffset
343 // purpose  : Returns offset of triangulation vertices for given leaf node
344 // =======================================================================
345 Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx)
346 {
347   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
348
349   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
350     return INVALID_OFFSET;
351
352   return aBVH->NodeInfoBuffer().at (theNodeIdx).z();
353 }
354
355 // =======================================================================
356 // function : ElementsOffset
357 // purpose  : Returns offset of triangulation elements for given leaf node
358 // =======================================================================
359 Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx)
360 {
361   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
362
363   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
364     return INVALID_OFFSET;
365
366   return aBVH->NodeInfoBuffer().at (theNodeIdx).w();
367 }
368
369 // =======================================================================
370 // function : TriangleSet
371 // purpose  : Returns triangulation data for given leaf node
372 // =======================================================================
373 OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx)
374 {
375   const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
376
377   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
378     return NULL;
379
380   if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
381     return NULL;
382
383   return dynamic_cast<OpenGl_TriangleSet*> (myObjects.ChangeValue (
384     aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).operator->());
385 }
386
387 // =======================================================================
388 // function : AcquireTextures
389 // purpose  : Makes the OpenGL texture handles resident
390 // =======================================================================
391 Standard_Boolean OpenGl_RaytraceGeometry::AcquireTextures (const Handle(OpenGl_Context)& theContext) const
392 {
393   if (theContext->arbTexBindless == NULL)
394   {
395     return Standard_True;
396   }
397
398 #if !defined(GL_ES_VERSION_2_0)
399   for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
400   {
401     theContext->arbTexBindless->glMakeTextureHandleResidentARB (myTextureHandles[anIdx]);
402
403     if (glGetError() != GL_NO_ERROR)
404     {
405 #ifdef RAY_TRACE_PRINT_INFO
406       std::cout << "Error: Failed to make OpenGL texture resident" << std::endl;
407 #endif
408       return Standard_False;
409     }
410   }
411 #endif
412
413   return Standard_True;
414 }
415
416 // =======================================================================
417 // function : ReleaseTextures
418 // purpose  : Makes the OpenGL texture handles non-resident
419 // =======================================================================
420 Standard_Boolean OpenGl_RaytraceGeometry::ReleaseTextures (const Handle(OpenGl_Context)& theContext) const
421 {
422   if (theContext->arbTexBindless == NULL)
423   {
424     return Standard_True;
425   }
426
427 #if !defined(GL_ES_VERSION_2_0)
428   for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
429   {
430     theContext->arbTexBindless->glMakeTextureHandleNonResidentARB (myTextureHandles[anIdx]);
431
432     if (glGetError() != GL_NO_ERROR)
433     {
434 #ifdef RAY_TRACE_PRINT_INFO
435       std::cout << "Error: Failed to make OpenGL texture non-resident" << std::endl;
436 #endif
437       return Standard_False;
438     }
439   }
440 #endif
441
442   return Standard_True;
443 }
444
445 // =======================================================================
446 // function : AddTexture
447 // purpose  : Adds new OpenGL texture to the scene and returns its index
448 // =======================================================================
449 Standard_Integer OpenGl_RaytraceGeometry::AddTexture (const Handle(OpenGl_Texture)& theTexture)
450 {
451   NCollection_Vector<Handle (OpenGl_Texture)>::iterator anIter =
452     std::find (myTextures.begin(), myTextures.end(), theTexture);
453
454   if (anIter == myTextures.end())
455   {
456     if (myTextures.Size() >= MAX_TEX_NUMBER)
457     {
458       return -1;
459     }
460
461     myTextures.Append (theTexture);
462   }
463
464   return static_cast<Standard_Integer> (anIter - myTextures.begin());
465 }
466
467 // =======================================================================
468 // function : UpdateTextureHandles
469 // purpose  : Updates unique 64-bit texture handles to use in shaders
470 // =======================================================================
471 Standard_Boolean OpenGl_RaytraceGeometry::UpdateTextureHandles (const Handle(OpenGl_Context)& theContext)
472 {
473   if (theContext->arbTexBindless == NULL)
474   {
475     return Standard_False;
476   }
477
478   myTextureHandles.clear();
479
480 #if !defined(GL_ES_VERSION_2_0)
481   for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
482   {
483     const GLuint64 aHandle = theContext->arbTexBindless->glGetTextureHandleARB (
484       myTextures.Value (anIdx)->TextureId());
485
486     if (glGetError() != GL_NO_ERROR)
487     {
488 #ifdef RAY_TRACE_PRINT_INFO
489       std::cout << "Error: Failed to get 64-bit handle of OpenGL texture" << std::endl;
490 #endif
491       return Standard_False;
492     }
493
494     myTextureHandles.push_back (aHandle);
495   }
496 #endif
497
498   return Standard_True;
499 }
500
501 namespace OpenGl_Raytrace
502 {
503   // =======================================================================
504   // function : IsRaytracedElement
505   // purpose  : Checks to see if the element contains ray-trace geometry
506   // =======================================================================
507   Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
508   {
509     OpenGl_PrimitiveArray* anArray = dynamic_cast<OpenGl_PrimitiveArray*> (theNode->elem);
510     return anArray != NULL
511         && anArray->DrawMode() >= GL_TRIANGLES;
512   }
513
514   // =======================================================================
515   // function : IsRaytracedElement
516   // purpose  : Checks to see if the element contains ray-trace geometry
517   // =======================================================================
518   Standard_Boolean IsRaytracedElement (const OpenGl_Element* theElement)
519   {
520     const OpenGl_PrimitiveArray* anArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
521     return anArray != NULL
522         && anArray->DrawMode() >= GL_TRIANGLES;
523   }
524
525   // =======================================================================
526   // function : IsRaytracedGroup
527   // purpose  : Checks to see if the group contains ray-trace geometry
528   // =======================================================================
529   Standard_Boolean IsRaytracedGroup (const OpenGl_Group* theGroup)
530   {
531     for (const OpenGl_ElementNode* aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next)
532     {
533       if (IsRaytracedElement (aNode))
534       {
535         return Standard_True;
536       }
537     }
538     return Standard_False;
539   }
540
541   // =======================================================================
542   // function : IsRaytracedStructure
543   // purpose  : Checks to see if the structure contains ray-trace geometry
544   // =======================================================================
545   Standard_Boolean IsRaytracedStructure (const OpenGl_Structure* theStructure)
546   {
547     for (OpenGl_Structure::GroupIterator anIter (theStructure->DrawGroups()); anIter.More(); anIter.Next())
548     {
549       if (anIter.Value()->IsRaytracable())
550       {
551         return Standard_True;
552       }
553     }
554     return Standard_False;
555   }
556 }