0025703: Visualization - Decrease number of samplers used in ray-tracing mode
[occt.git] / src / OpenGl / OpenGl_SceneGeometry.cxx
index ede32b5..512bb22 100755 (executable)
@@ -4,8 +4,8 @@
 //
 // This file is part of Open CASCADE Technology software library.
 //
-// This library is free software; you can redistribute it and / or modify it
-// under the terms of the GNU Lesser General Public version 2.1 as published
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
 // by the Free Software Foundation, with special exception defined in the file
 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
 // distribution for complete text of the license and disclaimer of any warranty.
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
-#ifdef HAVE_CONFIG_H
-  #include <config.h>
-#endif
-
-#ifdef HAVE_OPENCL
-
-#include <Standard_Assert.hxx>
-
 #ifdef HAVE_TBB
+  // On Windows, function TryEnterCriticalSection has appeared in Windows NT
+  // and is surrounded by #ifdef in MS VC++ 7.1 headers.
+  // Thus to use it we need to define appropriate macro saying that we will
+  // run on Windows NT 4.0 at least
+  #if defined(_WIN32) && !defined(_WIN32_WINNT)
+    #define _WIN32_WINNT 0x0501
+  #endif
+
   #include <tbb/tbb.h>
 #endif
 
 #include <OpenGl_SceneGeometry.hxx>
 
-//! Use this macro to output BVH profiling info
-//#define BVH_PRINT_INFO
+#include <OpenGl_ArbTexBindless.hxx>
+#include <OpenGl_PrimitiveArray.hxx>
+#include <OpenGl_Structure.hxx>
+#include <OSD_Timer.hxx>
+#include <Standard_Assert.hxx>
 
-#ifdef BVH_PRINT_INFO
-  #include <OSD_Timer.hxx>
-#endif
+//! Use this macro to output BVH profiling info
+// #define RAY_TRACE_PRINT_INFO
 
 namespace
 {
   //! Useful constant for null floating-point 4D vector.
   static const BVH_Vec4f ZERO_VEC_4F;
-};
+}
 
 // =======================================================================
 // function : OpenGl_RaytraceMaterial
@@ -126,13 +128,74 @@ OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
   //
 }
 
+// =======================================================================
+// function : Center
+// purpose  : Returns centroid position along the given axis
+// =======================================================================
+Standard_ShortReal OpenGl_TriangleSet::Center (
+  const Standard_Integer theIndex, const Standard_Integer theAxis) const
+{
+  // Note: Experiments show that the use of the box centroid (instead
+  // of the triangle centroid) increases render performance up to 12%
+
+  const BVH_Vec4i& aTriangle = Elements[theIndex];
+
+  const Standard_ShortReal aVertex0 =
+    BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.x()], theAxis);
+  const Standard_ShortReal aVertex1 =
+    BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.y()], theAxis);
+  const Standard_ShortReal aVertex2 =
+    BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.z()], theAxis);
+
+  return (Min (Min (aVertex0, aVertex1), aVertex2) +
+          Max (Max (aVertex0, aVertex1), aVertex2)) * 0.5f;
+}
+
+// =======================================================================
+// function : Box
+// purpose  : Returns AABB of primitive set
+// =======================================================================
+OpenGl_TriangleSet::BVH_BoxNt OpenGl_TriangleSet::Box() const
+{
+  const BVH_Transform<Standard_ShortReal, 4>* aTransform =
+    dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (Properties().operator->());
+
+  BVH_BoxNt aBox = BVH_PrimitiveSet<Standard_ShortReal, 3>::Box();
+
+  if (aTransform != NULL)
+  {
+    BVH_BoxNt aTransformedBox;
+
+    for (Standard_Integer aX = 0; aX <= 1; ++aX)
+    {
+      for (Standard_Integer aY = 0; aY <= 1; ++aY)
+      {
+        for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
+        {
+          BVH_Vec4f aCorner = aTransform->Transform() * BVH_Vec4f (
+            aX == 0 ? aBox.CornerMin().x() : aBox.CornerMax().x(),
+            aY == 0 ? aBox.CornerMin().y() : aBox.CornerMax().y(),
+            aZ == 0 ? aBox.CornerMin().z() : aBox.CornerMax().z(),
+            1.f);
+
+          aTransformedBox.Add (reinterpret_cast<BVH_Vec3f&> (aCorner));
+        }
+      }
+    }
+
+    return aTransformedBox;
+  }
+
+  return aBox;
+}
+
 // =======================================================================
 // function : Clear
 // purpose  : Clears ray-tracing geometry
 // =======================================================================
 void OpenGl_RaytraceGeometry::Clear()
 {
-  BVH_Geometry<Standard_ShortReal, 4>::BVH_Geometry::Clear();
+  BVH_Geometry<Standard_ShortReal, 3>::BVH_Geometry::Clear();
 
   std::vector<OpenGl_RaytraceLight,
     NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
@@ -149,9 +212,9 @@ void OpenGl_RaytraceGeometry::Clear()
 
 struct OpenGL_BVHParallelBuilder
 {
-  BVH_ObjectSet<Standard_ShortReal, 4>* Set;
+  BVH_ObjectSet<Standard_ShortReal, 3>* Set;
 
-  OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 4>* theSet)
+  OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 3>* theSet)
     : Set (theSet)
   {
     //
@@ -163,7 +226,7 @@ struct OpenGL_BVHParallelBuilder
     {
       OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
         Set->Objects().ChangeValue (static_cast<Standard_Integer> (anObjectIdx)).operator->());
-      
+
       if (aTriangleSet != NULL)
       {
         aTriangleSet->BVH();
@@ -180,13 +243,13 @@ struct OpenGL_BVHParallelBuilder
 // =======================================================================
 Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
 {
-#ifdef BVH_PRINT_INFO
+#ifdef RAY_TRACE_PRINT_INFO
     OSD_Timer aTimer;
 #endif
-    
+
   MarkDirty(); // force BVH rebuilding
 
-#ifdef BVH_PRINT_INFO
+#ifdef RAY_TRACE_PRINT_INFO
   aTimer.Reset();
   aTimer.Start();
 #endif
@@ -197,7 +260,9 @@ Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
   tbb::parallel_for (tbb::blocked_range<size_t> (0, Size()),
     OpenGL_BVHParallelBuilder (this));
 #endif
-  
+
+  myBottomLevelTreeDepth = 0;
+
   for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
   {
     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
@@ -205,26 +270,28 @@ Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
 
     Standard_ASSERT_RETURN (aTriangleSet != NULL,
       "Error! Failed to get triangulation of OpenGL element", Standard_False);
-    
+
     Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
       "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
+
+    myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth());
   }
 
-#ifdef BVH_PRINT_INFO
+#ifdef RAY_TRACE_PRINT_INFO
   aTimer.Stop();
 
   std::cout << "Updating bottom-level BVHs (sec): " <<
     aTimer.ElapsedTime() << std::endl;
 #endif
 
-#ifdef BVH_PRINT_INFO
+#ifdef RAY_TRACE_PRINT_INFO
   aTimer.Reset();
   aTimer.Start();
 #endif
 
-  NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVH = BVH();
+  NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> > aBVH = BVH();
 
-#ifdef BVH_PRINT_INFO
+#ifdef RAY_TRACE_PRINT_INFO
   aTimer.Stop();
 
   std::cout << "Updating high-level BVH (sec): " <<
@@ -234,9 +301,11 @@ Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
   Standard_ASSERT_RETURN (!aBVH.IsNull(),
     "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
 
+  myHighLevelTreeDepth = aBVH->Depth();
+
   Standard_Integer aVerticesOffset = 0;
   Standard_Integer aElementsOffset = 0;
-  Standard_Integer aBVHNodesOffset = 0;
+  Standard_Integer aBVHNodesOffset = BVH()->Length();
 
   for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
   {
@@ -260,8 +329,8 @@ Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
     aBVH->NodeInfoBuffer().at (aNodeIdx) = BVH_Vec4i (
       anObjectIdx + 1 /* to keep leaf flag */, aBVHNodesOffset, aVerticesOffset, aElementsOffset);
 
-    aVerticesOffset += aTriangleSet->Vertices.size();
-    aElementsOffset += aTriangleSet->Elements.size();
+    aVerticesOffset += (int)aTriangleSet->Vertices.size();
+    aElementsOffset += (int)aTriangleSet->Elements.size();
     aBVHNodesOffset += aTriangleSet->BVH()->Length();
   }
 
@@ -274,7 +343,7 @@ Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
 // =======================================================================
 Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
 {
-  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
+  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
 
   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
     return INVALID_OFFSET;
@@ -288,7 +357,7 @@ Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer t
 // =======================================================================
 Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx)
 {
-  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
+  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
 
   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
     return INVALID_OFFSET;
@@ -302,7 +371,7 @@ Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNo
 // =======================================================================
 Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx)
 {
-  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
+  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
 
   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
     return INVALID_OFFSET;
@@ -316,18 +385,132 @@ Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNo
 // =======================================================================
 OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx)
 {
-  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
+  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
 
   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
     return NULL;
 
   if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
     return NULL;
-  
+
   return dynamic_cast<OpenGl_TriangleSet*> (myObjects.ChangeValue (
     aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).operator->());
 }
 
+// =======================================================================
+// function : AcquireTextures
+// purpose  : Makes the OpenGL texture handles resident
+// =======================================================================
+Standard_Boolean OpenGl_RaytraceGeometry::AcquireTextures (const Handle(OpenGl_Context)& theContext) const
+{
+  if (theContext->arbTexBindless == NULL)
+  {
+    return Standard_True;
+  }
+
+#if !defined(GL_ES_VERSION_2_0)
+  for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
+  {
+    theContext->arbTexBindless->glMakeTextureHandleResidentARB (myTextureHandles[anIdx]);
+
+    if (glGetError() != GL_NO_ERROR)
+    {
+#ifdef RAY_TRACE_PRINT_INFO
+      std::cout << "Error: Failed to make OpenGL texture resident" << std::endl;
+#endif
+      return Standard_False;
+    }
+  }
+#endif
+
+  return Standard_True;
+}
+
+// =======================================================================
+// function : ReleaseTextures
+// purpose  : Makes the OpenGL texture handles non-resident
+// =======================================================================
+Standard_Boolean OpenGl_RaytraceGeometry::ReleaseTextures (const Handle(OpenGl_Context)& theContext) const
+{
+  if (theContext->arbTexBindless == NULL)
+  {
+    return Standard_True;
+  }
+
+#if !defined(GL_ES_VERSION_2_0)
+  for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
+  {
+    theContext->arbTexBindless->glMakeTextureHandleNonResidentARB (myTextureHandles[anIdx]);
+
+    if (glGetError() != GL_NO_ERROR)
+    {
+#ifdef RAY_TRACE_PRINT_INFO
+      std::cout << "Error: Failed to make OpenGL texture non-resident" << std::endl;
+#endif
+      return Standard_False;
+    }
+  }
+#endif
+
+  return Standard_True;
+}
+
+// =======================================================================
+// function : AddTexture
+// purpose  : Adds new OpenGL texture to the scene and returns its index
+// =======================================================================
+Standard_Integer OpenGl_RaytraceGeometry::AddTexture (const Handle(OpenGl_Texture)& theTexture)
+{
+  NCollection_Vector<Handle (OpenGl_Texture)>::iterator anIter =
+    std::find (myTextures.begin(), myTextures.end(), theTexture);
+
+  if (anIter == myTextures.end())
+  {
+    if (myTextures.Size() >= MAX_TEX_NUMBER)
+    {
+      return -1;
+    }
+
+    myTextures.Append (theTexture);
+  }
+
+  return static_cast<Standard_Integer> (anIter - myTextures.begin());
+}
+
+// =======================================================================
+// function : UpdateTextureHandles
+// purpose  : Updates unique 64-bit texture handles to use in shaders
+// =======================================================================
+Standard_Boolean OpenGl_RaytraceGeometry::UpdateTextureHandles (const Handle(OpenGl_Context)& theContext)
+{
+  if (theContext->arbTexBindless == NULL)
+  {
+    return Standard_False;
+  }
+
+  myTextureHandles.clear();
+
+#if !defined(GL_ES_VERSION_2_0)
+  for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
+  {
+    const GLuint64 aHandle = theContext->arbTexBindless->glGetTextureHandleARB (
+      myTextures.Value (anIdx)->TextureId());
+
+    if (glGetError() != GL_NO_ERROR)
+    {
+#ifdef RAY_TRACE_PRINT_INFO
+      std::cout << "Error: Failed to get 64-bit handle of OpenGL texture" << std::endl;
+#endif
+      return Standard_False;
+    }
+
+    myTextureHandles.push_back (aHandle);
+  }
+#endif
+
+  return Standard_True;
+}
+
 namespace OpenGl_Raytrace
 {
   // =======================================================================
@@ -336,12 +519,20 @@ namespace OpenGl_Raytrace
   // =======================================================================
   Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
   {
-    if (TelParray == theNode->type)
-    {
-      OpenGl_PrimitiveArray* anArray = dynamic_cast< OpenGl_PrimitiveArray* > (theNode->elem);
-      return anArray->PArray()->type >= TelPolygonsArrayType;
-    }
-    return Standard_False;
+    OpenGl_PrimitiveArray* anArray = dynamic_cast<OpenGl_PrimitiveArray*> (theNode->elem);
+    return anArray != NULL
+        && anArray->DrawMode() >= GL_TRIANGLES;
+  }
+
+  // =======================================================================
+  // function : IsRaytracedElement
+  // purpose  : Checks to see if the element contains ray-trace geometry
+  // =======================================================================
+  Standard_Boolean IsRaytracedElement (const OpenGl_Element* theElement)
+  {
+    const OpenGl_PrimitiveArray* anArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
+    return anArray != NULL
+        && anArray->DrawMode() >= GL_TRIANGLES;
   }
 
   // =======================================================================
@@ -365,12 +556,12 @@ namespace OpenGl_Raytrace
   // function : IsRaytracedStructure
   // purpose  : Checks to see if the structure contains ray-trace geometry
   // =======================================================================
-  Standard_Boolean IsRaytracedStructure (const OpenGl_Structure *theStructure)
+  Standard_Boolean IsRaytracedStructure (const OpenGl_StructuretheStructure)
   {
-    for (OpenGl_ListOfGroup::Iterator anItg (theStructure->Groups());
-         anItg.More(); anItg.Next())
+    for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups());
+         aGroupIter.More(); aGroupIter.Next())
     {
-      if (anItg.Value()->IsRaytracable())
+      if (aGroupIter.Value()->IsRaytracable())
         return Standard_True;
     }
     for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures());
@@ -382,5 +573,3 @@ namespace OpenGl_Raytrace
     return Standard_False;
   }
 }
-
-#endif