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