0030748: Visualization - Marker displayed in immediate layer ruins QT Quick view...
[occt.git] / src / OpenGl / OpenGl_SceneGeometry.cxx
old mode 100755 (executable)
new mode 100644 (file)
index 0dcbb8a..530bf57
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
+#include <OSD_Timer.hxx>
+#include <OSD_Parallel.hxx>
 #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>
-
+#include <OpenGl_ArbTexBindless.hxx>
 #include <OpenGl_PrimitiveArray.hxx>
+#include <OpenGl_SceneGeometry.hxx>
 #include <OpenGl_Structure.hxx>
+#include <Graphic3d_GraphicDriver.hxx>
 
 //! Use this macro to output BVH profiling info
-//#define BVH_PRINT_INFO
-
-#ifdef BVH_PRINT_INFO
-  #include <OSD_Timer.hxx>
-#endif
+// #define RAY_TRACE_PRINT_INFO
 
 namespace
 {
   //! Useful constant for null floating-point 4D vector.
   static const BVH_Vec4f ZERO_VEC_4F;
-};
+}
+
+IMPLEMENT_STANDARD_RTTIEXT(OpenGl_TriangleSet, OpenGl_BVHTriangulation3f)
 
 // =======================================================================
 // function : OpenGl_RaytraceMaterial
@@ -120,24 +108,112 @@ OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
 }
 
 // =======================================================================
-// function : OpenGl_LightSource
+// function : OpenGl_RaytraceLight
 // purpose  : Creates new light source
 // =======================================================================
-OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
+OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theEmission,
                                             const BVH_Vec4f& thePosition)
-: Diffuse (theDiffuse),
+: Emission (theEmission),
   Position (thePosition)
 {
   //
 }
 
+// =======================================================================
+// function : QuadBVH
+// purpose  : Returns quad BVH (QBVH) tree produced from binary BVH
+// =======================================================================
+const QuadBvhHandle& OpenGl_TriangleSet::QuadBVH()
+{
+  if (!myIsDirty)
+  {
+    Standard_ASSERT_RAISE (!myQuadBVH.IsNull(), "Error! BVH was not collapsed into QBVH");
+  }
+  else
+  {
+    myQuadBVH = BVH()->CollapseToQuadTree(); // build binary BVH and collapse it
+
+    myBVH->Clear(); // erase binary BVH
+  }
+
+  return myQuadBVH;
+}
+
+// =======================================================================
+// 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
+{
+  BVH_BoxNt aBox = BVH_PrimitiveSet<Standard_ShortReal, 3>::Box();
+  const BVH_Transform<Standard_ShortReal, 4>* aTransform = dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (Properties().get());
+  if (aTransform == NULL)
+  {
+    return aBox;
+  }
+
+  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 (aCorner.xyz());
+      }
+    }
+  }
+  return aTransformedBox;
+}
+
+// =======================================================================
+// function : OpenGl_TriangleSet
+// purpose  : Creates new OpenGL element triangulation
+// =======================================================================
+OpenGl_TriangleSet::OpenGl_TriangleSet (const Standard_Size theArrayID,
+                                        const opencascade::handle<BVH_Builder<Standard_ShortReal, 3> >& theBuilder)
+: BVH_Triangulation<Standard_ShortReal, 3> (theBuilder),
+  myArrayID (theArrayID)
+{
+  //
+}
+
 // =======================================================================
 // 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;
@@ -150,60 +226,46 @@ void OpenGl_RaytraceGeometry::Clear()
   Materials.swap (anEmptyMaterials);
 }
 
-#ifdef HAVE_TBB
-
 struct OpenGL_BVHParallelBuilder
 {
-  BVH_ObjectSet<Standard_ShortReal, 4>* Set;
+  BVH_ObjectSet<Standard_ShortReal, 3>* Set;
 
-  OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 4>* theSet)
-    : Set (theSet)
+  OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 3>* theSet)
+  : Set (theSet)
   {
     //
   }
 
-  void operator() (const tbb::blocked_range<size_t>& theRange) const
+  void operator() (const Standard_Integer theObjectIdx) const
   {
-    for (size_t anObjectIdx = theRange.begin(); anObjectIdx != theRange.end(); ++anObjectIdx)
-    {
-      OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
-        Set->Objects().ChangeValue (static_cast<Standard_Integer> (anObjectIdx)).operator->());
+    OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
+      Set->Objects().ChangeValue (static_cast<Standard_Integer> (theObjectIdx)).operator->());
 
-      if (aTriangleSet != NULL)
-      {
-        aTriangleSet->BVH();
-      }
-    }
+    if (aTriangleSet != NULL)
+      aTriangleSet->QuadBVH();
   }
 };
 
-#endif
-
 // =======================================================================
 // function : ProcessAcceleration
 // purpose  : Performs post-processing of high-level BVH
 // =======================================================================
 Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
 {
-#ifdef BVH_PRINT_INFO
-    OSD_Timer aTimer;
+#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
 
-#ifdef HAVE_TBB
-  // If Intel TBB is available, perform the preliminary
-  // construction of bottom-level scene BVHs
-  tbb::parallel_for (tbb::blocked_range<size_t> (0, Size()),
-    OpenGL_BVHParallelBuilder (this));
-#endif
+  OSD_Parallel::For (0, Size(), OpenGL_BVHParallelBuilder (this));
 
-  myBottomLevelTreeDepth = 0;
+  myBotLevelTreeDepth = 1;
 
   for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
   {
@@ -213,79 +275,113 @@ 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(),
+    Standard_ASSERT_RETURN (!aTriangleSet->QuadBVH().IsNull(),
       "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
 
-    myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth());
+    QuadBvhHandle aBVH = aTriangleSet->QuadBVH();
+
+    // correct data array of bottom-level BVH to set special flag for outer
+    // nodes in order to distinguish them from outer nodes of top-level BVH
+    for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
+    {
+      if (aBVH->IsOuter (aNodeIdx))
+      {
+        aBVH->NodeInfoBuffer()[aNodeIdx].x() = -1;
+      }
+    }
+
+    myBotLevelTreeDepth = Max (myBotLevelTreeDepth, aTriangleSet->QuadBVH()->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();
+  QuadBvhHandle aBVH = QuadBVH();
 
-#ifdef BVH_PRINT_INFO
+  Standard_ASSERT_RETURN (!aBVH.IsNull(),
+    "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
+
+  myTopLevelTreeDepth = aBVH->Depth();
+
+#ifdef RAY_TRACE_PRINT_INFO
   aTimer.Stop();
 
   std::cout << "Updating high-level BVH (sec): " <<
     aTimer.ElapsedTime() << std::endl;
 #endif
 
-  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 = QuadBVH()->Length();
 
   for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
   {
-    if (!aBVH->IsOuter (aNodeIdx))
-      continue;
+    if (aBVH->IsOuter (aNodeIdx))
+    {
+      Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
+        "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
 
-    Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
-      "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
+      const Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
 
-    Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
+      Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
+        "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
 
-    Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
-      "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
+      OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (myObjects (anObjectIdx).get());
 
-    OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
-      myObjects.ChangeValue (anObjectIdx).operator->());
+      // Note: We overwrite node info record to store parameters
+      // of bottom-level BVH and triangulation of OpenGL element
 
-    // Note: We overwrite node info record to store parameters
-    // of bottom-level BVH and triangulation of OpenGL element
+      aBVH->NodeInfoBuffer()[aNodeIdx] = BVH_Vec4i (anObjectIdx + 1, // to keep leaf flag
+                                                    aBvhNodesOffset,
+                                                    aVerticesOffset,
+                                                    aElementsOffset);
 
-    aBVH->NodeInfoBuffer().at (aNodeIdx) = BVH_Vec4i (
-      anObjectIdx + 1 /* to keep leaf flag */, aBVHNodesOffset, aVerticesOffset, aElementsOffset);
+      aVerticesOffset += static_cast<Standard_Integer> (aTriangleSet->Vertices.size());
+      aElementsOffset += static_cast<Standard_Integer> (aTriangleSet->Elements.size());
 
-    aVerticesOffset += (int)aTriangleSet->Vertices.size();
-    aElementsOffset += (int)aTriangleSet->Elements.size();
-    aBVHNodesOffset += aTriangleSet->BVH()->Length();
+      aBvhNodesOffset += aTriangleSet->QuadBVH()->Length();
+    }
   }
 
   return Standard_True;
 }
 
+// =======================================================================
+// function : QuadBVH
+// purpose  : Returns quad BVH (QBVH) tree produced from binary BVH
+// =======================================================================
+const QuadBvhHandle& OpenGl_RaytraceGeometry::QuadBVH()
+{
+  if (!myIsDirty)
+  {
+    Standard_ASSERT_RAISE (!myQuadBVH.IsNull(), "Error! BVH was not collapsed into QBVH");
+  }
+  else
+  {
+    myQuadBVH = BVH()->CollapseToQuadTree(); // build binary BVH and collapse it
+
+    myBVH->Clear(); // erase binary BVH
+  }
+
+  return myQuadBVH;
+}
+
 // =======================================================================
 // function : AccelerationOffset
 // purpose  : Returns offset of bottom-level BVH for given leaf node
 // =======================================================================
 Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
 {
-  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
+  const QuadBvhHandle& aBVH = QuadBVH();
 
   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
     return INVALID_OFFSET;
@@ -299,7 +395,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 QuadBvhHandle& aBVH = QuadBVH();
 
   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
     return INVALID_OFFSET;
@@ -313,7 +409,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 QuadBvhHandle& aBVH = QuadBVH();
 
   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
     return INVALID_OFFSET;
@@ -327,7 +423,7 @@ 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 QuadBvhHandle& aBVH = QuadBVH();
 
   if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
     return NULL;
@@ -335,8 +431,160 @@ OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNo
   if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
     return NULL;
 
-  return dynamic_cast<OpenGl_TriangleSet*> (myObjects.ChangeValue (
-    aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).operator->());
+  return dynamic_cast<OpenGl_TriangleSet*> (
+    myObjects (aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).get());
+}
+
+// =======================================================================
+// function : AcquireTextures
+// purpose  : Makes the OpenGL texture handles resident
+// =======================================================================
+Standard_Boolean OpenGl_RaytraceGeometry::AcquireTextures (const Handle(OpenGl_Context)& theContext)
+{
+  if (theContext->arbTexBindless == NULL)
+  {
+    return Standard_True;
+  }
+
+#if !defined(GL_ES_VERSION_2_0)
+  Standard_Integer aTexIter = 0;
+  for (NCollection_Vector<Handle(OpenGl_Texture)>::Iterator aTexSrcIter (myTextures); aTexSrcIter.More(); aTexSrcIter.Next(), ++aTexIter)
+  {
+    GLuint64& aHandle = myTextureHandles[aTexIter];
+    const Handle(OpenGl_Texture)& aTexture = aTexSrcIter.Value();
+    if (!aTexture->Sampler()->IsValid()
+     || !aTexture->Sampler()->IsImmutable())
+    {
+      // need to recreate texture sampler handle
+      aHandle = GLuint64(-1); // specs do not define value for invalid handle, set -1 to initialize something
+      if (!aTexture->InitSamplerObject (theContext))
+      {
+        continue;
+      }
+
+      aTexture->Sampler()->SetImmutable();
+      aHandle = theContext->arbTexBindless->glGetTextureSamplerHandleARB (aTexture->TextureId(), aTexture->Sampler()->SamplerID());
+      const GLenum anErr = glGetError();
+      if (anErr != GL_NO_ERROR)
+      {
+        theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                                 TCollection_AsciiString ("Error: Failed to get 64-bit handle of OpenGL texture #") + int(anErr));
+        myTextureHandles.clear();
+        return Standard_False;
+      }
+    }
+
+    theContext->arbTexBindless->glMakeTextureHandleResidentARB (aHandle);
+    const GLenum anErr = glGetError();
+    if (anErr != GL_NO_ERROR)
+    {
+      theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                               TCollection_AsciiString ("Error: Failed to make OpenGL texture resident #") + int(anErr));
+      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 (size_t aTexIter = 0; aTexIter < myTextureHandles.size(); ++aTexIter)
+  {
+    theContext->arbTexBindless->glMakeTextureHandleNonResidentARB (myTextureHandles[aTexIter]);
+    const GLenum anErr = glGetError();
+    if (anErr != GL_NO_ERROR)
+    {
+      theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                               TCollection_AsciiString("Error: Failed to make OpenGL texture non-resident #") + int(anErr));
+      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)
+{
+  if (theTexture->TextureId() == OpenGl_Texture::NO_TEXTURE)
+  {
+    return -1;
+  }
+
+  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();
+  myTextureHandles.resize (myTextures.Size());
+
+#if !defined(GL_ES_VERSION_2_0)
+  Standard_Integer aTexIter = 0;
+  for (NCollection_Vector<Handle(OpenGl_Texture)>::Iterator aTexSrcIter (myTextures); aTexSrcIter.More(); aTexSrcIter.Next(), ++aTexIter)
+  {
+    GLuint64& aHandle = myTextureHandles[aTexIter];
+    aHandle = GLuint64(-1); // specs do not define value for invalid handle, set -1 to initialize something
+
+    const Handle(OpenGl_Texture)& aTexture = aTexSrcIter.Value();
+    if (!aTexture->Sampler()->IsValid()
+     && !aTexture->InitSamplerObject (theContext))
+    {
+      continue;
+    }
+
+    aTexture->Sampler()->SetImmutable();
+    aHandle = theContext->arbTexBindless->glGetTextureSamplerHandleARB (aTexture->TextureId(), aTexture->Sampler()->SamplerID());
+    const GLenum anErr = glGetError();
+    if (anErr != GL_NO_ERROR)
+    {
+      theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                               TCollection_AsciiString ("Error: Failed to get 64-bit handle of OpenGL texture #") + int(anErr));
+      myTextureHandles.clear();
+      return Standard_False;
+    }
+  }
+#endif
+
+  return Standard_True;
 }
 
 namespace OpenGl_Raytrace
@@ -347,7 +595,7 @@ namespace OpenGl_Raytrace
   // =======================================================================
   Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
   {
-    OpenGl_PrimitiveArray* anArray = dynamic_cast< OpenGl_PrimitiveArray* > (theNode->elem);
+    OpenGl_PrimitiveArray* anArray = dynamic_cast<OpenGl_PrimitiveArray*> (theNode->elem);
     return anArray != NULL
         && anArray->DrawMode() >= GL_TRIANGLES;
   }
@@ -367,10 +615,9 @@ namespace OpenGl_Raytrace
   // function : IsRaytracedGroup
   // purpose  : Checks to see if the group contains ray-trace geometry
   // =======================================================================
-  Standard_Boolean IsRaytracedGroup (const OpenGl_Group *theGroup)
+  Standard_Boolean IsRaytracedGroup (const OpenGl_GrouptheGroup)
   {
-    const OpenGl_ElementNode* aNode;
-    for (aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next)
+    for (const OpenGl_ElementNode* aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next)
     {
       if (IsRaytracedElement (aNode))
       {
@@ -379,25 +626,4 @@ namespace OpenGl_Raytrace
     }
     return Standard_False;
   }
-
-  // =======================================================================
-  // function : IsRaytracedStructure
-  // purpose  : Checks to see if the structure contains ray-trace geometry
-  // =======================================================================
-  Standard_Boolean IsRaytracedStructure (const OpenGl_Structure* theStructure)
-  {
-    for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups());
-         aGroupIter.More(); aGroupIter.Next())
-    {
-      if (aGroupIter.Value()->IsRaytracable())
-        return Standard_True;
-    }
-    for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures());
-         anIts.More(); anIts.Next())
-    {
-      if (IsRaytracedStructure (anIts.Value()))
-        return Standard_True;
-    }
-    return Standard_False;
-  }
 }