0030483: Visualization, Path Tracing - make Tile Size configurable
authorkgv <kgv@opencascade.com>
Wed, 6 Feb 2019 16:21:23 +0000 (19:21 +0300)
committerapn <apn@opencascade.com>
Fri, 15 Feb 2019 14:14:19 +0000 (17:14 +0300)
OpenGl_TileSampler has been refactored to better describe its logic:
- Offset image now defines tile index instead of offset to tile origin.
- Added 2D array defining the number of times to sample tile for straight-forward debugging.

Graphic3d_RenderingParams has been extended with property
RayTracingTileSize for testing various tile configurations.
Default behavior is the following:
- Target number of tiles (e.g. upper limit per frame): 256
- Tile size: 32x32.

OpenGl_View::runPathtrace() has been split into two methods per rendering stage.
OpenGl_Texture::Init() now returns FALSE immediately on 0 input dimensions.

Added Image_PixMapTypedData template class allowing to work with image data of known pixel format.

17 files changed:
src/Graphic3d/Graphic3d_RenderingParams.hxx
src/Image/FILES
src/Image/Image_PixMapData.hxx
src/Image/Image_PixMapTypedData.hxx [new file with mode: 0644]
src/OpenGl/OpenGl_Texture.cxx
src/OpenGl/OpenGl_TileSampler.cxx
src/OpenGl/OpenGl_TileSampler.hxx
src/OpenGl/OpenGl_View.hxx
src/OpenGl/OpenGl_View_Raytrace.cxx
src/OpenGl/OpenGl_View_Redraw.cxx
src/Shaders/Display.fs
src/Shaders/RaytraceBase.fs
src/Shaders/RaytraceRender.fs
src/Shaders/Shaders_Display_fs.pxx
src/Shaders/Shaders_RaytraceBase_fs.pxx
src/Shaders/Shaders_RaytraceRender_fs.pxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx

index cbb8c82..9068b46 100644 (file)
@@ -113,6 +113,7 @@ public:
     TwoSidedBsdfModels          (Standard_False),
     RadianceClampingValue       (30.0),
     RebuildRayTracingShaders    (Standard_False),
+    RayTracingTileSize          (32),
     NbRayTracingTiles           (16 * 16),
     CameraApertureRadius        (0.0f),
     CameraFocalPlaneDist        (1.0f),
@@ -187,7 +188,10 @@ public:
   Standard_Boolean                  TwoSidedBsdfModels;          //!< forces path tracing to use two-sided versions of original one-sided scattering models
   Standard_ShortReal                RadianceClampingValue;       //!< maximum radiance value used for clamping radiance estimation.
   Standard_Boolean                  RebuildRayTracingShaders;    //!< forces rebuilding ray tracing shaders at the next frame
-  Standard_Integer                  NbRayTracingTiles;           //!< total number of screen tiles used in adaptive sampling mode (PT only)
+  Standard_Integer                  RayTracingTileSize;          //!< screen tile size, 32 by default (adaptive sampling mode of path tracing);
+  Standard_Integer                  NbRayTracingTiles;           //!< maximum number of screen tiles per frame, 256 by default (adaptive sampling mode of path tracing);
+                                                                 //!  this parameter limits the number of tiles to be rendered per redraw, increasing Viewer interactivity,
+                                                                 //!  but also increasing the time for achieving a good quality; -1 means no limit
   Standard_ShortReal                CameraApertureRadius;        //!< aperture radius of perspective camera used for depth-of-field, 0.0 by default (no DOF) (path tracing only)
   Standard_ShortReal                CameraFocalPlaneDist;        //!< focal  distance of perspective camera used for depth-of field, 1.0 by default (path tracing only)
   FrustumCulling                    FrustumCullingState;         //!< state of frustum culling optimization; FrustumCulling_On by default
index 3ca8be8..40118d5 100755 (executable)
@@ -7,5 +7,6 @@ Image_Format.hxx
 Image_PixMap.cxx
 Image_PixMap.hxx
 Image_PixMapData.hxx
+Image_PixMapTypedData.hxx
 Image_VideoRecorder.cxx
 Image_VideoRecorder.hxx
index e2bccbb..ec870b1 100644 (file)
@@ -38,7 +38,7 @@ public:
   }
 
   //! Initializer.
-  void Init (const Handle(NCollection_BaseAllocator)& theAlloc,
+  bool Init (const Handle(NCollection_BaseAllocator)& theAlloc,
              const Standard_Size                      theSizeBPP,
              const Standard_Size                      theSizeX,
              const Standard_Size                      theSizeY,
@@ -59,6 +59,16 @@ public:
       Allocate (mySize);
     }
     SetTopDown (TopToDown == 1);
+    return !IsEmpty();
+  }
+
+  //! Reset all values to zeros.
+  void ZeroData()
+  {
+    if (myData != NULL)
+    {
+      memset (myData, 0, mySize);
+    }
   }
 
   //! @return data pointer to requested row (first column).
diff --git a/src/Image/Image_PixMapTypedData.hxx b/src/Image/Image_PixMapTypedData.hxx
new file mode 100644 (file)
index 0000000..2f144bf
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// 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 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.
+
+#ifndef _Image_PixMapTypedData_Header
+#define _Image_PixMapTypedData_Header
+
+#include <Image_PixMapData.hxx>
+
+//! Structure to manage image buffer with predefined pixel type.
+template<typename PixelType_t>
+class Image_PixMapTypedData : public Image_PixMapData
+{
+public:
+  //! Empty constructor.
+  Image_PixMapTypedData() {}
+
+  //! Initializer.
+  bool Init (const Handle(NCollection_BaseAllocator)& theAlloc,
+             Standard_Size  theSizeX,
+             Standard_Size  theSizeY,
+             Standard_Size  theSizeRowBytes = 0,
+             Standard_Byte* theDataPtr = 0)
+  {
+    const Standard_Size aSizeBPP = sizeof(PixelType_t);
+    return Image_PixMapData::Init (theAlloc, aSizeBPP, theSizeX, theSizeY, theSizeRowBytes, theDataPtr);
+  }
+
+  //! Reset all values to specified one.
+  void Init (const PixelType_t& theValue)
+  {
+    for (Standard_Size aRowIter = 0; aRowIter < SizeY; ++aRowIter)
+    {
+      for (Standard_Size aColIter = 0; aColIter < SizeX; ++aColIter)
+      {
+        ChangeValue (aRowIter, aColIter) = theValue;
+      }
+    }
+  }
+
+  //! @return data pointer to requested row (first column).
+  const PixelType_t* Row (Standard_Size theRow) const { return (const PixelType_t* )Image_PixMapData::Row (theRow); }
+
+  //! @return data pointer to requested row (first column).
+  PixelType_t* ChangeRow (Standard_Size theRow) { return (PixelType_t* )Image_PixMapData::ChangeRow (theRow); }
+
+  //! @return data pointer to requested position.
+  const PixelType_t& Value (Standard_Size theRow, Standard_Size theCol) const { return *(const PixelType_t* )Image_PixMapData::Value (theRow, theCol); }
+
+  //! @return data pointer to requested position.
+  PixelType_t& ChangeValue (Standard_Size theRow, Standard_Size theCol) { return *(PixelType_t* )Image_PixMapData::ChangeValue (theRow, theCol); }
+
+};
+
+#endif // _Image_PixMapTypedData_Header
index 6256e1f..a87bb9f 100644 (file)
@@ -405,6 +405,15 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
                            const Graphic3d_TypeOfTexture theType,
                            const Image_PixMap*           theImage)
 {
+  if (theSizeX < 1
+   || theSizeY < 1)
+  {
+    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         "Error: texture of 0 size cannot be created.");
+    Release (theCtx.operator->());
+    return false;
+  }
+
 #if !defined(GL_ES_VERSION_2_0)
   const GLenum aTarget = theType == Graphic3d_TOT_1D
                        ? GL_TEXTURE_1D
index c9b9b88..9ccd4c9 100644 (file)
 
 #include <OpenGl_Context.hxx>
 #include <OpenGl_TileSampler.hxx>
+#include <Graphic3d_RenderingParams.hxx>
 #include <TCollection_ExtendedString.hxx>
 
-namespace
-{
-  //! Scale factor for estimating visual error.
-  static const float THE_SCALE_FACTOR = 1.0f / 1e6f;
-}
-
 //=======================================================================
 //function : OpenGl_TileSampler
 //purpose  :
 //=======================================================================
 OpenGl_TileSampler::OpenGl_TileSampler()
-: mySample (0),
-  mySizeX  (0),
-  mySizeY  (0),
-  myTilesX (0),
-  myTilesY (0)
+: myLastSample (0),
+  myScaleFactor(1.0f),
+  myTileSize   (0),
+  myViewSize   (0, 0)
 {
   mySampler.initFaure();
 }
@@ -41,156 +35,211 @@ OpenGl_TileSampler::OpenGl_TileSampler()
 //function : GrabVarianceMap
 //purpose  :
 //=======================================================================
-void OpenGl_TileSampler::GrabVarianceMap (const Handle(OpenGl_Context)& theContext)
+void OpenGl_TileSampler::GrabVarianceMap (const Handle(OpenGl_Context)& theContext,
+                                          const Handle(OpenGl_Texture)& theTexture)
 {
-#if !defined(GL_ES_VERSION_2_0)
-  std::vector<GLint> aRawData (NbTiles(), 0);
+  if (theTexture.IsNull())
+  {
+    return;
+  }
 
-  theContext->core11fwd->glGetTexImage (GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_INT, &aRawData.front());
+  myVarianceRaw.Init (0);
+#if !defined(GL_ES_VERSION_2_0)
+  theTexture->Bind (theContext);
+  theContext->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT,  1);
+  theContext->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
+  theContext->core11fwd->glGetTexImage (GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_INT, myVarianceRaw.ChangeData());
   const GLenum anErr = theContext->core11fwd->glGetError();
+  theTexture->Unbind (theContext);
   if (anErr != GL_NO_ERROR)
   {
     theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
                              "Error! Failed to fetch visual error map from the GPU");
+    return;
   }
-  else
-  {
-    for (int aTileIdx = 0, aNbTiles = NbTiles(); aTileIdx < aNbTiles; ++aTileIdx)
-    {
-      myVarianceMap[aTileIdx] = aRawData[aTileIdx] * THE_SCALE_FACTOR;
-    }
+#else
+  // glGetTexImage() is unavailable on OpenGL ES, FBO + glReadPixels() can be used instead
+  (void )theContext;
+#endif
 
-    for (int aX = 0; aX < myTilesX; ++aX)
+  const float aFactor = 1.0f / myScaleFactor;
+  for (Standard_Size aColIter = 0; aColIter < myVarianceMap.SizeX; ++aColIter)
+  {
+    for (Standard_Size aRowIter = 0; aRowIter < myVarianceMap.SizeY; ++aRowIter)
     {
-      for (int aY = 0; aY < myTilesY; ++aY)
+      const int aRawValue = myVarianceRaw.Value (aRowIter, aColIter);
+      float& aTile = myVarianceMap.ChangeValue (aRowIter, aColIter);
+      aTile = aFactor * float(aRawValue);
+      aTile *= 1.0f / tileArea ((int )aColIter, (int )aRowIter); // average error over the tile
+      if (aRowIter != 0)
       {
-        ChangeTile (aX, aY) *= 1.0f / TileArea (aX, aY); // average error over the tile
-
-        if (aY > 0)
-        {
-          ChangeTile (aX, aY) += Tile (aX, aY - 1);
-        }
+        aTile += myVarianceMap.Value (aRowIter - 1, aColIter);
       }
     }
+  }
 
-    myMarginalMap.resize (myTilesX); // build marginal distribution
-    for (int aX = 0; aX < myTilesX; ++aX)
+  // build marginal distribution
+  for (Standard_Size aX = 0; aX < myVarianceMap.SizeX; ++aX)
+  {
+    myMarginalMap[aX] = myVarianceMap.Value (myVarianceMap.SizeY - 1, aX);
+    if (aX != 0)
     {
-      myMarginalMap[aX] = Tile (aX, myTilesY - 1);
-
-      if (aX > 0)
-        myMarginalMap[aX] += myMarginalMap[aX - 1];
+      myMarginalMap[aX] += myMarginalMap[aX - 1];
     }
   }
-#else
-  // glGetTexImage() is unavailable on OpenGL ES, FBO + glReadPixels() can be used instead
-  (void )theContext;
-#endif
 }
 
 //=======================================================================
-//function : Sample
+//function : nextTileToSample
 //purpose  :
 //=======================================================================
-void OpenGl_TileSampler::Sample (int& theOffsetX,
-                                 int& theOffsetY)
+Graphic3d_Vec2i OpenGl_TileSampler::nextTileToSample()
 {
-  int aX = 0;
-  int aY = 0;
-
-  const float aKsiX = mySampler.sample (0, mySample) * myMarginalMap.back();
-  for (; aX < myTilesX - 1; ++aX)
+  Graphic3d_Vec2i aTile (0, 0);
+  const float aKsiX = mySampler.sample (0, myLastSample) * myMarginalMap.back();
+  for (; (size_t )aTile.x() < myMarginalMap.size() - 1; ++aTile.x())
   {
-    if (aKsiX <= myMarginalMap[aX])
+    if (aKsiX <= myMarginalMap[aTile.x()])
     {
       break;
     }
   }
 
-  const float aKsiY = mySampler.sample (1, mySample) * Tile (aX, myTilesY - 1);
-  for (; aY < myTilesY - 1; ++aY)
+  const float aKsiY = mySampler.sample (1, myLastSample) * myVarianceMap.Value (myVarianceMap.SizeY - 1, aTile.x());
+  for (; (size_t )aTile.y() < myVarianceMap.SizeY - 1; ++aTile.y())
   {
-    if (aKsiY <= Tile (aX, aY))
+    if (aKsiY <= myVarianceMap.Value (aTile.y(), aTile.x()))
     {
       break;
     }
   }
 
-  theOffsetX = aX * TileSize();
-  theOffsetY = aY * TileSize();
-
-  ++mySample;
+  ++myLastSample;
+  return aTile;
 }
 
 //=======================================================================
 //function : SetSize
 //purpose  :
 //=======================================================================
-void OpenGl_TileSampler::SetSize (const int theSizeX,
-                                  const int theSizeY)
+void OpenGl_TileSampler::SetSize (const Graphic3d_RenderingParams& theParams,
+                                  const Graphic3d_Vec2i& theSize)
 {
-  if (mySizeX == theSizeX
-   && mySizeY == theSizeY)
+  if (theSize.x() <= 0
+   || theSize.y() <= 0)
   {
     return;
   }
 
-  mySizeX = theSizeX;
-  mySizeY = theSizeY;
+  myViewSize = theSize;
 
-  myTilesX = static_cast<int> (ceilf (static_cast<float> (mySizeX) / TileSize()));
-  myTilesY = static_cast<int> (ceilf (static_cast<float> (mySizeY) / TileSize()));
+  const int aTileSize = Max (theParams.RayTracingTileSize, 1);
+  const int aNbTilesX = Max (1, static_cast<int> (ceilf (static_cast<float> (theSize.x()) / aTileSize)));
+  const int aNbTilesY = Max (1, static_cast<int> (ceilf (static_cast<float> (theSize.y()) / aTileSize)));
+  if (myTileSize != aTileSize
+   || (int )myTiles.SizeX != aNbTilesX
+   || (int )myTiles.SizeY != aNbTilesY)
+  {
+    myTileSize = aTileSize;
+    myScaleFactor = 1.0e6f * (1024.0f / float(myTileSize * myTileSize));
 
-  myVarianceMap.resize (myTilesX * myTilesY);
+    Handle(NCollection_BaseAllocator) anAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
+    myTiles.SetTopDown (true);
+    myTiles.Init (anAlloc, aNbTilesX, aNbTilesY);
+    myTiles.Init (1);
+
+    myVarianceMap.SetTopDown (true);
+    myVarianceMap.Init (myTiles.Allocator(), myTiles.SizeX, myTiles.SizeY);
+    myVarianceMap.Init (0.0f);
+
+    myVarianceRaw.SetTopDown (true);
+    myVarianceRaw.Init (myTiles.Allocator(), myTiles.SizeX, myTiles.SizeY);
+    myVarianceRaw.Init (0);
+
+    myOffsets.SetTopDown (true);
+    myOffsets.Init (myTiles.Allocator(), myTiles.SizeX, myTiles.SizeY);
+    myOffsets.Init (Graphic3d_Vec2i (-1, -1));
+
+    myMarginalMap.resize (myTiles.SizeX);
+    myMarginalMap.assign (myMarginalMap.size(), 0.0f);
+  }
+
+  // calculate a size of compact offsets texture optimal for rendering reduced number of tiles
+  Standard_Integer aNbShunkTilesX = (int )myTiles.SizeX, aNbShunkTilesY = (int )myTiles.SizeY;
+  if (theParams.NbRayTracingTiles > 0)
+  {
+    aNbShunkTilesX = 8;
+    aNbShunkTilesY = 8;
+    for (Standard_Integer anIdx = 0; aNbShunkTilesX * aNbShunkTilesY < theParams.NbRayTracingTiles; ++anIdx)
+    {
+      (anIdx % 2 == 0 ? aNbShunkTilesX : aNbShunkTilesY) <<= 1;
+    }
+  }
+  if ((int )myOffsetsShrunk.SizeX != aNbShunkTilesX
+   || (int )myOffsetsShrunk.SizeY != aNbShunkTilesY)
+  {
+    myOffsetsShrunk.SetTopDown (true);
+    myOffsetsShrunk.Init (myTiles.Allocator(), aNbShunkTilesX, aNbShunkTilesY);
+    myOffsetsShrunk.Init (Graphic3d_Vec2i (-1, -1));
+  }
 }
 
 //=======================================================================
-//function : Upload
+//function : UploadOffsets
 //purpose  :
 //=======================================================================
-void OpenGl_TileSampler::Upload (const Handle(OpenGl_Context)& theContext,
-                                 const Handle(OpenGl_Texture)& theTexture,
-                                 const int                     theNbTilesX,
-                                 const int                     theNbTilesY,
-                                 const bool                    theAdaptive)
+bool OpenGl_TileSampler::UploadOffsets (const Handle(OpenGl_Context)& theContext,
+                                        const Handle(OpenGl_Texture)& theOffsetsTexture,
+                                        const bool theAdaptive)
 {
-  if (theTexture.IsNull())
+  if (myTiles.IsEmpty())
   {
-    return;
+    return false;
   }
 
-  const int aNbTilesX = theAdaptive ? theNbTilesX : myTilesX;
-  const int aNbTilesY = theAdaptive ? theNbTilesY : myTilesY;
-
-  Standard_ASSERT_RAISE (aNbTilesX * aNbTilesY > 0,
-    "Error! Number of sampling tiles should be positive");
-
-  std::vector<GLint> aData (aNbTilesX * aNbTilesY * 2);
+  myTiles.Init (0);
+  Image_PixMapTypedData<Graphic3d_Vec2i>& anOffsets = theAdaptive ? myOffsetsShrunk : myOffsets;
+  anOffsets.Init (Graphic3d_Vec2i (-1, -1));
+  for (Standard_Size aRowIter = 0; aRowIter < anOffsets.SizeY; ++aRowIter)
+  {
+    for (Standard_Size aColIter = 0; aColIter < anOffsets.SizeX; ++aColIter)
+    {
+      Graphic3d_Vec2i& aRedirectTile = anOffsets.ChangeValue (aRowIter, aColIter);
+      aRedirectTile = theAdaptive ? nextTileToSample() : Graphic3d_Vec2i ((int )aColIter, (int )aRowIter);
+      myTiles.ChangeValue (aRedirectTile.y(), aRedirectTile.x()) += 1;
+    }
+  }
 
-  for (int aX = 0; aX < aNbTilesX; ++aX)
+  bool hasErrors = false;
+  if (!theOffsetsTexture.IsNull())
   {
-    for (int aY = 0; aY < aNbTilesY; ++aY)
+    if (theOffsetsTexture->SizeX() != (int )anOffsets.SizeX
+    ||  theOffsetsTexture->SizeY() != (int )anOffsets.SizeY
+    || !theOffsetsTexture->IsValid())
     {
-      if (!theAdaptive)
+      theOffsetsTexture->Release (theContext.operator->());
+      if (!theOffsetsTexture->Init (theContext, GL_RG32I, GL_RG_INTEGER, GL_INT,
+                                    (int )anOffsets.SizeX, (int )anOffsets.SizeY, Graphic3d_TOT_2D))
       {
-        aData[(aY * aNbTilesX + aX) * 2 + 0] = aX * TileSize();
-        aData[(aY * aNbTilesX + aX) * 2 + 1] = aY * TileSize();
+        hasErrors = true;
       }
-      else
+    }
+    if (theOffsetsTexture->IsValid())
+    {
+      theOffsetsTexture->Bind (theContext);
+      theContext->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT,  1);
+    #if !defined(GL_ES_VERSION_2_0)
+      theContext->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+    #endif
+      theContext->core11fwd->glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, (int )anOffsets.SizeX, (int )anOffsets.SizeY, GL_RG_INTEGER, GL_INT, anOffsets.Data());
+      if (theContext->core11fwd->glGetError() != GL_NO_ERROR)
       {
-        Sample (aData[(aY * aNbTilesX + aX) * 2 + 0],
-                aData[(aY * aNbTilesX + aX) * 2 + 1]);
+        hasErrors = true;
+        theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                                 "Error! Failed to upload tile offset map on the GPU");
       }
+      theOffsetsTexture->Unbind (theContext);
     }
   }
-
-  theTexture->Bind (theContext);
-
-  theContext->core11fwd->glTexImage2D (GL_TEXTURE_2D, 0, GL_RG32I, aNbTilesX, aNbTilesY, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, &aData.front());
-
-  if (theContext->core11fwd->glGetError() != GL_NO_ERROR)
-  {
-    theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
-                             "Error! Failed to upload tile offset map on the GPU");
-  }
+  return !hasErrors;
 }
index 9fc9753..f956507 100644 (file)
 #include <OpenGl_Texture.hxx>
 #include <OpenGl_HaltonSampler.hxx>
 
+#include <Image_PixMapTypedData.hxx>
+
 #include <vector>
 
+class Graphic3d_RenderingParams;
+
 //! Tool object used for sampling screen tiles according to estimated pixel variance (used in path tracing engine).
 //! To improve GPU thread coherency, rendering window is split into pixel blocks or tiles. The important feature of
 //! this approach is that it is possible to keep the same number of tiles for any screen resolution (e.g. 256 tiles
@@ -32,85 +36,87 @@ class OpenGl_TileSampler
 {
 public:
 
-  //! Size of individual tile in pixels.
-  static int TileSize() { return 32; }
-
-public:
-
   //! Creates new tile sampler.
   Standard_EXPORT OpenGl_TileSampler();
 
-  //! Returns width of ray-tracing viewport.
-  int SizeX() const { return mySizeX; }
+  //! Size of individual tile in pixels.
+  Graphic3d_Vec2i TileSize() const { return Graphic3d_Vec2i (myTileSize, myTileSize); }
 
-  //! Returns height of ray-tracing viewport.
-  int SizeY() const { return mySizeY; }
+  //! Scale factor for quantization of visual error (float) into signed integer.
+  float VarianceScaleFactor() const { return myScaleFactor; }
 
   //! Returns number of tiles in X dimension.
-  int NbTilesX() const { return myTilesX; }
+  int NbTilesX() const { return (int)myTiles.SizeX; }
 
   //! Returns number of tiles in Y dimension.
-  int NbTilesY() const { return myTilesY; }
+  int NbTilesY() const { return (int)myTiles.SizeY; }
 
   //! Returns total number of tiles in viewport.
-  int NbTiles() const { return myTilesX * myTilesY; }
+  int NbTiles() const { return int(myTiles.SizeX * myTiles.SizeY); }
 
-  //! Specifies size of ray-tracing viewport.
-  Standard_EXPORT void SetSize (const int theSizeX,
-                                const int theSizeY);
+  //! Returns ray-tracing viewport.
+  const Graphic3d_Vec2i& ViewSize() const { return myViewSize; }
 
-  //! Returns number of pixels in the given tile.
-  int TileArea (const int theX,
-                const int theY) const
+  //! Number of tiles within offsets texture.
+  Graphic3d_Vec2i NbOffsetTiles (bool theAdaptive) const
   {
-    return Min (TileSize(), mySizeX - theX * TileSize())
-         * Min (TileSize(), mySizeY - theY * TileSize());
+    return theAdaptive
+         ? Graphic3d_Vec2i ((int )myOffsetsShrunk.SizeX, (int )myOffsetsShrunk.SizeY)
+         : Graphic3d_Vec2i ((int )myOffsets.SizeX,       (int )myOffsets.SizeY);
   }
 
+  //! Maximum number of tiles within offsets texture.
+  Graphic3d_Vec2i NbOffsetTilesMax() const { return NbOffsetTiles (true).cwiseMax (NbOffsetTiles (false)); }
+
+  //! Viewport for rendering using offsets texture.
+  Graphic3d_Vec2i OffsetTilesViewport (bool theAdaptive) const { return NbOffsetTiles (theAdaptive) * myTileSize; }
+
+  //! Maximum viewport for rendering using offsets texture.
+  Graphic3d_Vec2i OffsetTilesViewportMax() const { return NbOffsetTilesMax() * myTileSize; }
+
+  //! Specifies size of ray-tracing viewport and recomputes tile size.
+  Standard_EXPORT void SetSize (const Graphic3d_RenderingParams& theParams,
+                                const Graphic3d_Vec2i& theSize);
+
   //! Fetches current error estimation from the GPU and
   //! builds 2D discrete distribution for tile sampling.
-  Standard_EXPORT void GrabVarianceMap (const Handle(OpenGl_Context)& theContext);
-
-  //! Samples tile location according to estimated error.
-  Standard_EXPORT void Sample (int& theOffsetX,
-                               int& theOffsetY);
+  Standard_EXPORT void GrabVarianceMap (const Handle(OpenGl_Context)& theContext,
+                                        const Handle(OpenGl_Texture)& theTexture);
 
-  //! Resets tile sampler to initial state.
-  void Reset() { mySample = 0; }
+  //! Resets (restart) tile sampler to initial state.
+  void Reset() { myLastSample = 0; }
 
   //! Uploads offsets of sampled tiles to the given OpenGL texture.
-  Standard_EXPORT void Upload (const Handle(OpenGl_Context)& theContext,
-                               const Handle(OpenGl_Texture)& theTexture,
-                               const int                     theNbTilesX,
-                               const int                     theNbTilesY,
-                               const bool                    theAdaptive);
+  Standard_EXPORT bool UploadOffsets (const Handle(OpenGl_Context)& theContext,
+                                      const Handle(OpenGl_Texture)& theOffsetsTexture,
+                                      const bool theAdaptive);
 
 protected:
 
-  //! Returns tile value (estimated error).
-  float Tile (const int theX,
-              const int theY) const
+  //! Returns number of pixels in the given tile.
+  int tileArea (int theX, int theY) const
   {
-    return myVarianceMap[theY * myTilesX + theX];
+    const int aSizeX = Min (myTileSize, myViewSize.x() - theX * myTileSize);
+    const int aSizeY = Min (myTileSize, myViewSize.y() - theY * myTileSize);
+    return aSizeX * aSizeY;
   }
 
-  //! Returns tile value (estimated error).
-  float& ChangeTile (const int theX,
-                     const int theY)
-  {
-    return myVarianceMap[theY * myTilesX + theX];
-  }
+  //! Samples tile location according to estimated error.
+  Standard_EXPORT Graphic3d_Vec2i nextTileToSample();
 
 protected:
 
-  std::vector<float>   myVarianceMap; //!< Estimation of visual error per tile
-  std::vector<float>   myMarginalMap; //!< Marginal distribution of 2D error map
-  OpenGl_HaltonSampler mySampler;     //!< Halton sequence generator
-  int                  mySample;      //!< Index of generated sample
-  int                  mySizeX;       //!< Width of ray-tracing viewport
-  int                  mySizeY;       //!< Height of ray-tracing viewport
-  int                  myTilesX;      //!< Number of tiles in X dimension
-  int                  myTilesY;      //!< Number of tiles in Y dimension
+  Image_PixMapTypedData<unsigned int>    myTiles;         //!< number of samples per tile (initially all 1)
+  Image_PixMapTypedData<float>           myVarianceMap;   //!< Estimation of visual error per tile
+  Image_PixMapTypedData<int>             myVarianceRaw;   //!< Estimation of visual error per tile (raw data)
+  Image_PixMapTypedData<Graphic3d_Vec2i> myOffsets;       //!< 2D array of tiles redirecting to another tile
+  Image_PixMapTypedData<Graphic3d_Vec2i> myOffsetsShrunk; //!< 2D array of tiles redirecting to another tile (shrunk)
+  std::vector<float>                     myMarginalMap;   //!< Marginal distribution of 2D error map
+  OpenGl_HaltonSampler                   mySampler;       //!< Halton sequence generator
+  unsigned int                           myLastSample;    //!< Index of generated sample
+  float                                  myScaleFactor;   //!< scale factor for quantization of visual error (float) into signed integer
+  int                                    myTileSize;      //!< tile size
+  Graphic3d_Vec2i                        myViewSize;      //!< ray-tracing viewport
 
 };
 
index b318974..cc9a564 100644 (file)
@@ -593,6 +593,8 @@ protected: //! @name data types related to ray-tracing
     // images used by ISS mode
     OpenGl_RT_uRenderImage,
     OpenGl_RT_uOffsetImage,
+    OpenGl_RT_uTileSize,
+    OpenGl_RT_uVarianceScaleFactor,
 
     // maximum radiance value
     OpenGl_RT_uMaxRadiance,
@@ -603,12 +605,9 @@ protected: //! @name data types related to ray-tracing
   //! Defines OpenGL image samplers.
   enum ShaderImageNames
   {
-    OpenGl_RT_OutputImageLft = 0,
-    OpenGl_RT_OutputImageRgh = 1,
-    OpenGl_RT_VisualErrorImageLft = 2,
-    OpenGl_RT_VisualErrorImageRgh = 3,
-    OpenGl_RT_TileOffsetsImageLft = 4,
-    OpenGl_RT_TileOffsetsImageRgh = 5
+    OpenGl_RT_OutputImage = 0,
+    OpenGl_RT_VisualErrorImage = 1,
+    OpenGl_RT_TileOffsetsImage = 2,
   };
 
   //! Tool class for management of shader sources.
@@ -697,12 +696,6 @@ protected: //! @name data types related to ray-tracing
 
     //! Maximum radiance value used for clamping radiance estimation.
     Standard_ShortReal RadianceClampingValue;
-
-    //! Number of tiles in X dimension (in adaptive sampling mode).
-    Standard_Integer NbTilesX;
-    
-    //! Number of tiles in Y dimension (in adaptive sampling mode).
-    Standard_Integer NbTilesY;
     
     //! Enables/disables depth-of-field effect (path tracing, perspective camera).
     Standard_Boolean DepthOfField;
@@ -721,8 +714,6 @@ protected: //! @name data types related to ray-tracing
       AdaptiveScreenSampling (Standard_False),
       UseEnvMapForBackground (Standard_False),
       RadianceClampingValue  (30.0),
-      NbTilesX               (16),
-      NbTilesY               (16),
       DepthOfField           (Standard_False),
       ToneMappingMethod      (Graphic3d_ToneMappingMethod_Disabled) { }
   };
@@ -854,7 +845,9 @@ protected: //! @name methods related to ray-tracing
                                             const Handle(OpenGl_ShaderObject)& theFragShader);
 
   //! Initializes OpenGL/GLSL shader programs.
-  Standard_Boolean initRaytraceResources (const Handle(OpenGl_Context)& theGlContext);
+  Standard_Boolean initRaytraceResources (const Standard_Integer theSizeX,
+                                          const Standard_Integer theSizeY,
+                                          const Handle(OpenGl_Context)& theGlContext);
 
   //! Releases OpenGL/GLSL shader programs.
   void releaseRaytraceResources (const Handle(OpenGl_Context)& theGlContext,
@@ -884,7 +877,8 @@ protected: //! @name methods related to ray-tracing
                            const int                    theWinSizeY);
 
   //! Binds ray-trace textures to corresponding texture units.
-  void bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext);
+  void bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext,
+                             int theStereoView);
 
   //! Unbinds ray-trace textures from corresponding texture unit.
   void unbindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext);
@@ -914,9 +908,13 @@ protected: //! @name methods related to ray-tracing
   Standard_Boolean runPathtrace (const Standard_Integer        theSizeX,
                                  const Standard_Integer        theSizeY,
                                  Graphic3d_Camera::Projection  theProjection,
-                                 OpenGl_FrameBuffer*           theReadDrawFbo,
                                  const Handle(OpenGl_Context)& theGlContext);
 
+  //! Runs path tracing (global illumination) kernel.
+  Standard_Boolean runPathtraceOut (Graphic3d_Camera::Projection  theProjection,
+                                    OpenGl_FrameBuffer*           theReadDrawFbo,
+                                    const Handle(OpenGl_Context)& theGlContext);
+
   //! Redraws the window using OpenGL/GLSL ray-tracing or path tracing.
   Standard_Boolean raytrace (const Standard_Integer        theSizeX,
                              const Standard_Integer        theSizeY,
index b0c528d..12177f3 100644 (file)
@@ -1139,8 +1139,7 @@ TCollection_AsciiString OpenGl_View::generateShaderPrefix (const Handle(OpenGl_C
       // to activate the feature we need OpenGL 4.4 and GL_NV_shader_atomic_float extension
       if (theGlContext->IsGlGreaterEqual (4, 4) && theGlContext->CheckExtension ("GL_NV_shader_atomic_float"))
       {
-        aPrefixString += TCollection_AsciiString ("\n#define ADAPTIVE_SAMPLING") +
-          TCollection_AsciiString ("\n#define BLOCK_SIZE ") + TCollection_AsciiString (OpenGl_TileSampler::TileSize());
+        aPrefixString += TCollection_AsciiString ("\n#define ADAPTIVE_SAMPLING");
       }
     }
 
@@ -1328,7 +1327,9 @@ Handle(OpenGl_ShaderProgram) OpenGl_View::initProgram (const Handle(OpenGl_Conte
 // function : initRaytraceResources
 // purpose  : Initializes OpenGL/GLSL shader programs
 // =======================================================================
-Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context)& theGlContext)
+Standard_Boolean OpenGl_View::initRaytraceResources (const Standard_Integer theSizeX,
+                                                     const Standard_Integer theSizeY,
+                                                     const Handle(OpenGl_Context)& theGlContext)
 {
   if (myRaytraceInitStatus == OpenGl_RT_FAIL)
   {
@@ -1372,40 +1373,17 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
       }
     }
 
-    Standard_Integer aNbTilesX = 8;
-    Standard_Integer aNbTilesY = 8;
-
-    for (Standard_Integer anIdx = 0; aNbTilesX * aNbTilesY < myRenderParams.NbRayTracingTiles; ++anIdx)
-    {
-      (anIdx % 2 == 0 ? aNbTilesX : aNbTilesY) <<= 1;
-    }
-
     if (myRenderParams.RaytracingDepth             != myRaytraceParameters.NbBounces
      || myRenderParams.IsTransparentShadowEnabled  != myRaytraceParameters.TransparentShadows
      || myRenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination
      || myRenderParams.TwoSidedBsdfModels          != myRaytraceParameters.TwoSidedBsdfModels
-     || myRaytraceGeometry.HasTextures()           != myRaytraceParameters.UseBindlessTextures
-     || aNbTilesX                                  != myRaytraceParameters.NbTilesX
-     || aNbTilesY                                  != myRaytraceParameters.NbTilesY)
+     || myRaytraceGeometry.HasTextures()           != myRaytraceParameters.UseBindlessTextures)
     {
       myRaytraceParameters.NbBounces           = myRenderParams.RaytracingDepth;
       myRaytraceParameters.TransparentShadows  = myRenderParams.IsTransparentShadowEnabled;
       myRaytraceParameters.GlobalIllumination  = myRenderParams.IsGlobalIlluminationEnabled;
       myRaytraceParameters.TwoSidedBsdfModels  = myRenderParams.TwoSidedBsdfModels;
       myRaytraceParameters.UseBindlessTextures = myRaytraceGeometry.HasTextures();
-
-#ifdef RAY_TRACE_PRINT_INFO
-      if (aNbTilesX != myRaytraceParameters.NbTilesX
-       || aNbTilesY != myRaytraceParameters.NbTilesY)
-      {
-        std::cout << "Number of tiles X: " << aNbTilesX << "\n";
-        std::cout << "Number of tiles Y: " << aNbTilesY << "\n";
-      }
-#endif
-
-      myRaytraceParameters.NbTilesX = aNbTilesX;
-      myRaytraceParameters.NbTilesY = aNbTilesY;
-
       aToRebuildShaders = Standard_True;
     }
 
@@ -1425,6 +1403,7 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
 
       aToRebuildShaders = Standard_True;
     }
+    myTileSampler.SetSize (myRenderParams, myRaytraceParameters.AdaptiveScreenSampling ? Graphic3d_Vec2i (theSizeX, theSizeY) : Graphic3d_Vec2i (0, 0));
 
     const bool toEnableDof = !myCamera->IsOrthographic() && myRaytraceParameters.GlobalIllumination;
     if (myRaytraceParameters.DepthOfField != toEnableDof)
@@ -1749,6 +1728,10 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
         aShaderProgram->GetUniformLocation (theGlContext, "uRenderImage");
       myUniformLocations[anIndex][OpenGl_RT_uOffsetImage] =
         aShaderProgram->GetUniformLocation (theGlContext, "uOffsetImage");
+      myUniformLocations[anIndex][OpenGl_RT_uTileSize] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uTileSize");
+      myUniformLocations[anIndex][OpenGl_RT_uVarianceScaleFactor] =
+        aShaderProgram->GetUniformLocation (theGlContext, "uVarianceScaleFactor");
 
       myUniformLocations[anIndex][OpenGl_RT_uBackColorTop] =
         aShaderProgram->GetUniformLocation (theGlContext, "uBackColorTop");
@@ -1875,107 +1858,76 @@ Standard_Boolean OpenGl_View::updateRaytraceBuffers (const Standard_Integer
 
   if (myRaytraceParameters.AdaptiveScreenSampling)
   {
-    const Standard_Integer aSizeX = std::max (myRaytraceParameters.NbTilesX * 64, theSizeX);
-    const Standard_Integer aSizeY = std::max (myRaytraceParameters.NbTilesY * 64, theSizeY);
-
-    myRaytraceFBO1[0]->InitLazy (theGlContext, aSizeX, aSizeY, GL_RGBA32F, myFboDepthFormat);
-    myRaytraceFBO2[0]->InitLazy (theGlContext, aSizeX, aSizeY, GL_RGBA32F, myFboDepthFormat);
-
+    Graphic3d_Vec2i aMaxViewport = myTileSampler.OffsetTilesViewportMax().cwiseMax (Graphic3d_Vec2i (theSizeX, theSizeY));
+    myRaytraceFBO1[0]->InitLazy (theGlContext, aMaxViewport.x(), aMaxViewport.y(), GL_RGBA32F, myFboDepthFormat);
+    myRaytraceFBO2[0]->InitLazy (theGlContext, aMaxViewport.x(), aMaxViewport.y(), GL_RGBA32F, myFboDepthFormat);
     if (myRaytraceFBO1[1]->IsValid()) // second FBO not needed
     {
       myRaytraceFBO1[1]->Release (theGlContext.operator->());
       myRaytraceFBO2[1]->Release (theGlContext.operator->());
     }
   }
-  else // non-adaptive mode
+
+  for (int aViewIter = 0; aViewIter < 2; ++aViewIter)
   {
-    if (myRaytraceFBO1[0]->GetSizeX() != theSizeX
-     || myRaytraceFBO1[0]->GetSizeY() != theSizeY)
+    if (myRaytraceTileOffsetsTexture[aViewIter].IsNull())
     {
-      myAccumFrames = 0; // accumulation should be restarted
+      myRaytraceOutputTexture[aViewIter] = new OpenGl_Texture();
+      myRaytraceVisualErrorTexture[aViewIter] = new OpenGl_Texture();
+      myRaytraceTileOffsetsTexture[aViewIter] = new OpenGl_Texture();
     }
 
-    myRaytraceFBO1[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
-    myRaytraceFBO2[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
-
-    // Init second set of buffers for stereographic rendering
-    if (myCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
-    {
-      myRaytraceFBO1[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
-      myRaytraceFBO2[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
-    }
-    else if (myRaytraceFBO1[1]->IsValid()) // second FBO not needed
+    if (aViewIter == 1
+     && myCamera->ProjectionType() != Graphic3d_Camera::Projection_Stereo)
     {
       myRaytraceFBO1[1]->Release (theGlContext.operator->());
       myRaytraceFBO2[1]->Release (theGlContext.operator->());
+      myRaytraceOutputTexture[1]->Release (theGlContext.operator->());
+      myRaytraceVisualErrorTexture[1]->Release (theGlContext.operator->());
+      myRaytraceTileOffsetsTexture[1]->Release (theGlContext.operator->());
+      continue;
     }
-  }
-
-  myTileSampler.SetSize (theSizeX, theSizeY);
-
-  if (myRaytraceTileOffsetsTexture[0].IsNull()
-   || myRaytraceTileOffsetsTexture[1].IsNull())
-  {
-    myRaytraceOutputTexture[0] = new OpenGl_Texture();
-    myRaytraceOutputTexture[1] = new OpenGl_Texture();
-
-    myRaytraceTileOffsetsTexture[0] = new OpenGl_Texture();
-    myRaytraceTileOffsetsTexture[1] = new OpenGl_Texture();
-    myRaytraceVisualErrorTexture[0] = new OpenGl_Texture();
-    myRaytraceVisualErrorTexture[1] = new OpenGl_Texture();
-  }
-
-  if (myRaytraceOutputTexture[0]->SizeX() / 3 != theSizeX
-   || myRaytraceOutputTexture[0]->SizeY() / 2 != theSizeY)
-  {
-    myAccumFrames = 0;
-
-    // Due to limitations of OpenGL image load-store extension
-    // atomic operations are supported only for single-channel
-    // images, so we define GL_R32F image. It is used as array
-    // of 6D floating point vectors:
-    // 0 - R color channel
-    // 1 - G color channel
-    // 2 - B color channel
-    // 3 - hit time transformed into OpenGL NDC space
-    // 4 - luminance accumulated for odd samples only
-    myRaytraceOutputTexture[0]->InitRectangle (theGlContext,
-      theSizeX * 3, theSizeY * 2, OpenGl_TextureFormat::Create<GLfloat, 1>());
-
-    // workaround for some NVIDIA drivers
-    myRaytraceVisualErrorTexture[0]->Release (theGlContext.operator->());
-    myRaytraceTileOffsetsTexture[0]->Release (theGlContext.operator->());
-
-    myRaytraceVisualErrorTexture[0]->Init (theGlContext,
-      GL_R32I, GL_RED_INTEGER, GL_INT, myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
 
-    myRaytraceTileOffsetsTexture[0]->Init (theGlContext,
-      GL_RG32I, GL_RG_INTEGER, GL_INT, myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
-  }
-
-  if (myCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
-  {
-    if (myRaytraceOutputTexture[1]->SizeX() / 3 != theSizeX
-     || myRaytraceOutputTexture[1]->SizeY() / 2 != theSizeY)
+    if (myRaytraceParameters.AdaptiveScreenSampling)
     {
-      myRaytraceOutputTexture[1]->InitRectangle (theGlContext,
-        theSizeX * 3, theSizeY * 2, OpenGl_TextureFormat::Create<GLfloat, 1>());
+      if (myRaytraceOutputTexture[aViewIter]->SizeX() / 3 == theSizeX
+       && myRaytraceOutputTexture[aViewIter]->SizeY() / 2 == theSizeY
+       && myRaytraceVisualErrorTexture[aViewIter]->SizeX() == myTileSampler.NbTilesX()
+       && myRaytraceVisualErrorTexture[aViewIter]->SizeY() == myTileSampler.NbTilesY())
+      {
+        continue;
+      }
 
-      myRaytraceVisualErrorTexture[1]->Release (theGlContext.operator->());
-      myRaytraceTileOffsetsTexture[1]->Release (theGlContext.operator->());
+      myAccumFrames = 0;
 
-      myRaytraceVisualErrorTexture[1]->Init (theGlContext,
-        GL_R32I, GL_RED_INTEGER, GL_INT, myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
+      // Due to limitations of OpenGL image load-store extension
+      // atomic operations are supported only for single-channel
+      // images, so we define GL_R32F image. It is used as array
+      // of 6D floating point vectors:
+      // 0 - R color channel
+      // 1 - G color channel
+      // 2 - B color channel
+      // 3 - hit time transformed into OpenGL NDC space
+      // 4 - luminance accumulated for odd samples only
+      myRaytraceOutputTexture[aViewIter]->InitRectangle (theGlContext, theSizeX * 3, theSizeY * 2, OpenGl_TextureFormat::Create<GLfloat, 1>());
+
+      // workaround for some NVIDIA drivers
+      myRaytraceVisualErrorTexture[aViewIter]->Release (theGlContext.operator->());
+      myRaytraceVisualErrorTexture[aViewIter]->Init (theGlContext, GL_R32I, GL_RED_INTEGER, GL_INT,
+                                                     myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
+    }
+    else // non-adaptive mode
+    {
+      if (myRaytraceFBO1[aViewIter]->GetSizeX() != theSizeX
+       || myRaytraceFBO1[aViewIter]->GetSizeY() != theSizeY)
+      {
+        myAccumFrames = 0; // accumulation should be restarted
+      }
 
-      myRaytraceTileOffsetsTexture[1]->Init (theGlContext,
-        GL_RG32I, GL_RG_INTEGER, GL_INT, myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
+      myRaytraceFBO1[aViewIter]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
+      myRaytraceFBO2[aViewIter]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
     }
   }
-  else
-  {
-    myRaytraceOutputTexture[1]->Release (theGlContext.operator->());
-  }
-
   return Standard_True;
 }
 
@@ -2721,25 +2673,22 @@ Standard_Boolean OpenGl_View::setUniformState (const Standard_Integer        the
 // function : bindRaytraceTextures
 // purpose  : Binds ray-trace textures to corresponding texture units
 // =======================================================================
-void OpenGl_View::bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext)
+void OpenGl_View::bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext,
+                                        int theStereoView)
 {
-  if (myRaytraceParameters.AdaptiveScreenSampling)
+  if (myRaytraceParameters.AdaptiveScreenSampling
+   && myRaytraceParameters.GlobalIllumination)
   {
   #if !defined(GL_ES_VERSION_2_0)
-    theGlContext->core42->glBindImageTexture (OpenGl_RT_OutputImageLft,
-      myRaytraceOutputTexture[0]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
-    theGlContext->core42->glBindImageTexture (OpenGl_RT_OutputImageRgh,
-      myRaytraceOutputTexture[1]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
-
-    theGlContext->core42->glBindImageTexture (OpenGl_RT_VisualErrorImageLft,
-      myRaytraceVisualErrorTexture[0]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32I);
-    theGlContext->core42->glBindImageTexture (OpenGl_RT_VisualErrorImageRgh,
-      myRaytraceVisualErrorTexture[1]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32I);
-    theGlContext->core42->glBindImageTexture (OpenGl_RT_TileOffsetsImageLft,
-      myRaytraceTileOffsetsTexture[0]->TextureId(), 0, GL_TRUE, 0, GL_READ_ONLY, GL_RG32I);
-    theGlContext->core42->glBindImageTexture (OpenGl_RT_TileOffsetsImageRgh,
-      myRaytraceTileOffsetsTexture[1]->TextureId(), 0, GL_TRUE, 0, GL_READ_ONLY, GL_RG32I);
-#endif
+    theGlContext->core42->glBindImageTexture (OpenGl_RT_OutputImage,
+                                              myRaytraceOutputTexture[theStereoView]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
+    theGlContext->core42->glBindImageTexture (OpenGl_RT_VisualErrorImage,
+                                              myRaytraceVisualErrorTexture[theStereoView]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32I);
+    theGlContext->core42->glBindImageTexture (OpenGl_RT_TileOffsetsImage,
+                                              myRaytraceTileOffsetsTexture[theStereoView]->TextureId(), 0, GL_TRUE, 0, GL_READ_ONLY, GL_RG32I);
+  #else
+    (void )theStereoView;
+  #endif
   }
 
   if (!myTextureEnv.IsNull()
@@ -2801,7 +2750,8 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Standard_Integer
 
   if (myRaytraceParameters.GlobalIllumination) // path tracing
   {
-    aResult &= runPathtrace (theSizeX, theSizeY, theProjection, theReadDrawFbo, theGlContext);
+    aResult &= runPathtrace    (theSizeX, theSizeY, theProjection, theGlContext);
+    aResult &= runPathtraceOut (theProjection, theReadDrawFbo, theGlContext);
   }
   else // Whitted-style ray-tracing
   {
@@ -2823,13 +2773,9 @@ Standard_Boolean OpenGl_View::runRaytrace (const Standard_Integer        theSize
 {
   Standard_Boolean aResult = Standard_True;
 
-  bindRaytraceTextures (theGlContext);
-
-  Handle(OpenGl_FrameBuffer) aRenderImageFramebuffer;
-  Handle(OpenGl_FrameBuffer) aDepthSourceFramebuffer;
-
   // Choose proper set of frame buffers for stereo rendering
-  const Standard_Integer aFBOIdx (theProjection == Graphic3d_Camera::Projection_MonoRightEye);
+  const Standard_Integer aFBOIdx = (theProjection == Graphic3d_Camera::Projection_MonoRightEye) ? 1 : 0;
+  bindRaytraceTextures (theGlContext, aFBOIdx);
 
   if (myRenderParams.IsAntialiasingEnabled) // if second FSAA pass is used
   {
@@ -2899,8 +2845,8 @@ Standard_Boolean OpenGl_View::runRaytrace (const Standard_Integer        theSize
       aFramebuffer->ColorTexture()->Bind (theGlContext, OpenGl_RT_FsaaInputTexture);
     }
 
-    aRenderImageFramebuffer = myRaytraceFBO2[aFBOIdx];
-    aDepthSourceFramebuffer = myRaytraceFBO1[aFBOIdx];
+    const Handle(OpenGl_FrameBuffer)& aRenderImageFramebuffer = myRaytraceFBO2[aFBOIdx];
+    const Handle(OpenGl_FrameBuffer)& aDepthSourceFramebuffer = myRaytraceFBO1[aFBOIdx];
 
     glEnable (GL_DEPTH_TEST);
 
@@ -2940,11 +2886,8 @@ Standard_Boolean OpenGl_View::runRaytrace (const Standard_Integer        theSize
 Standard_Boolean OpenGl_View::runPathtrace (const Standard_Integer              theSizeX,
                                             const Standard_Integer              theSizeY,
                                             const Graphic3d_Camera::Projection  theProjection,
-                                            OpenGl_FrameBuffer*                 theReadDrawFbo,
                                             const Handle(OpenGl_Context)&       theGlContext)
 {
-  Standard_Boolean aResult = Standard_True;
-
   if (myToUpdateEnvironmentMap) // check whether the map was changed
   {
     myAccumFrames = myToUpdateEnvironmentMap = 0;
@@ -2953,15 +2896,13 @@ Standard_Boolean OpenGl_View::runPathtrace (const Standard_Integer
   if (myRenderParams.CameraApertureRadius != myPrevCameraApertureRadius
    || myRenderParams.CameraFocalPlaneDist != myPrevCameraFocalPlaneDist)
   {
-
     myPrevCameraApertureRadius = myRenderParams.CameraApertureRadius;
     myPrevCameraFocalPlaneDist = myRenderParams.CameraFocalPlaneDist;
-
     myAccumFrames = 0;
   }
 
   // Choose proper set of frame buffers for stereo rendering
-  const Standard_Integer aFBOIdx (theProjection == Graphic3d_Camera::Projection_MonoRightEye);
+  const Standard_Integer aFBOIdx = (theProjection == Graphic3d_Camera::Projection_MonoRightEye) ? 1 : 0;
 
   if (myRaytraceParameters.AdaptiveScreenSampling)
   {
@@ -2970,106 +2911,88 @@ Standard_Boolean OpenGl_View::runPathtrace (const Standard_Integer
       myTileSampler.Reset(); // reset tile sampler to its initial state
 
       // Adaptive sampling is starting at the second frame
-      myTileSampler.Upload (theGlContext,
-                            myRaytraceTileOffsetsTexture[aFBOIdx],
-                            myRaytraceParameters.NbTilesX,
-                            myRaytraceParameters.NbTilesY,
-                            false);
-    }
-  }
-
-  bindRaytraceTextures (theGlContext);
-
-  Handle(OpenGl_FrameBuffer) aRenderImageFramebuffer;
-  Handle(OpenGl_FrameBuffer) aDepthSourceFramebuffer;
-  Handle(OpenGl_FrameBuffer) anAccumImageFramebuffer;
+      myTileSampler.UploadOffsets (theGlContext, myRaytraceTileOffsetsTexture[aFBOIdx], false);
 
-  const Standard_Integer anImageId = (aFBOIdx != 0)
-                                   ? OpenGl_RT_OutputImageRgh
-                                   : OpenGl_RT_OutputImageLft;
-
-  const Standard_Integer anErrorId = (aFBOIdx != 0)
-                                   ? OpenGl_RT_VisualErrorImageRgh
-                                   : OpenGl_RT_VisualErrorImageLft;
-
-  const Standard_Integer anOffsetId = (aFBOIdx != 0)
-                                    ? OpenGl_RT_TileOffsetsImageRgh
-                                    : OpenGl_RT_TileOffsetsImageLft;
+    #if !defined(GL_ES_VERSION_2_0)
+      theGlContext->core44->glClearTexImage (myRaytraceOutputTexture[aFBOIdx]->TextureId(), 0, GL_RED, GL_FLOAT, NULL);
+    #endif
+    }
 
-  aRenderImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO1[aFBOIdx] : myRaytraceFBO2[aFBOIdx];
-  anAccumImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO2[aFBOIdx] : myRaytraceFBO1[aFBOIdx];
+    // Clear adaptive screen sampling images
+  #if !defined(GL_ES_VERSION_2_0)
+    theGlContext->core44->glClearTexImage (myRaytraceVisualErrorTexture[aFBOIdx]->TextureId(), 0, GL_RED_INTEGER, GL_INT, NULL);
+  #endif
+  }
 
-  aDepthSourceFramebuffer = aRenderImageFramebuffer;
+  bindRaytraceTextures (theGlContext, aFBOIdx);
 
+  const Handle(OpenGl_FrameBuffer)& anAccumImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO2[aFBOIdx] : myRaytraceFBO1[aFBOIdx];
   anAccumImageFramebuffer->ColorTexture()->Bind (theGlContext, OpenGl_RT_PrevAccumTexture);
 
-  aRenderImageFramebuffer->BindBuffer (theGlContext);
+  // Set frame accumulation weight
+  myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uAccumSamples], myAccumFrames);
 
+  // Set random number generator seed
   if (myAccumFrames == 0)
   {
     myRNG.SetSeed(); // start RNG from beginning
   }
+  myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uFrameRndSeed], static_cast<Standard_Integer> (myRNG.NextInt() >> 2));
 
-  // Clear adaptive screen sampling images
+  // Set image uniforms for render program
   if (myRaytraceParameters.AdaptiveScreenSampling)
   {
-  #if !defined(GL_ES_VERSION_2_0)
-    if (myAccumFrames == 0 || (myAccumFrames == 1 && myCamera->IsStereo()))
-    {
-      theGlContext->core44->glClearTexImage (myRaytraceOutputTexture[aFBOIdx]->TextureId(), 0, GL_RED, GL_FLOAT, NULL);
-    }
-
-    theGlContext->core44->glClearTexImage (myRaytraceVisualErrorTexture[aFBOIdx]->TextureId(), 0, GL_RED_INTEGER, GL_INT, NULL);
-  #endif
+    myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uRenderImage], OpenGl_RT_OutputImage);
+    myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uOffsetImage], OpenGl_RT_TileOffsetsImage);
+    myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uTileSize], myTileSampler.TileSize());
   }
 
-  // Set frame accumulation weight
-  myRaytraceProgram->SetUniform (theGlContext,
-    myUniformLocations[0][OpenGl_RT_uAccumSamples], myAccumFrames);
-
-  // Set random number generator seed
-  myRaytraceProgram->SetUniform (theGlContext,
-    myUniformLocations[0][OpenGl_RT_uFrameRndSeed], static_cast<Standard_Integer> (myRNG.NextInt() >> 2));
-
-  // Set image uniforms for render program
-  myRaytraceProgram->SetUniform (theGlContext,
-    myUniformLocations[0][OpenGl_RT_uRenderImage], anImageId);
-  myRaytraceProgram->SetUniform (theGlContext,
-    myUniformLocations[0][OpenGl_RT_uOffsetImage], anOffsetId);
-
-  glDisable (GL_DEPTH_TEST);
-
-  if (myRaytraceParameters.AdaptiveScreenSampling
-   && ((myAccumFrames > 0 && !myCamera->IsStereo()) || myAccumFrames > 1))
+  const Handle(OpenGl_FrameBuffer)& aRenderImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO1[aFBOIdx] : myRaytraceFBO2[aFBOIdx];
+  aRenderImageFramebuffer->BindBuffer (theGlContext);
+  if (myRaytraceParameters.AdaptiveScreenSampling)
   {
-    glViewport (0,
-                0,
-                myTileSampler.TileSize() * myRaytraceParameters.NbTilesX,
-                myTileSampler.TileSize() * myRaytraceParameters.NbTilesY);
+    // extend viewport here, so that tiles at boundaries (cut tile size by target rendering viewport)
+    // redirected to inner tiles (full tile size) are drawn entirely
+    const Graphic3d_Vec2i anOffsetViewport = myTileSampler.OffsetTilesViewport (myAccumFrames > 1); // shrunk offsets texture will be uploaded since 3rd frame
+    glViewport (0, 0, anOffsetViewport.x(), anOffsetViewport.y());
   }
 
   // Generate for the given RNG seed
+  glDisable (GL_DEPTH_TEST);
   theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
 
-  if (myRaytraceParameters.AdaptiveScreenSampling
-   && ((myAccumFrames > 0 && !myCamera->IsStereo()) || myAccumFrames > 1))
+  aRenderImageFramebuffer->UnbindBuffer (theGlContext);
+
+  if (myRaytraceParameters.AdaptiveScreenSampling)
   {
-    glViewport (0,
-                0,
-                theSizeX,
-                theSizeY);
+    glViewport (0, 0, theSizeX, theSizeY);
   }
+  return true;
+}
 
+// =======================================================================
+// function : runPathtraceOut
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_View::runPathtraceOut (const Graphic3d_Camera::Projection  theProjection,
+                                               OpenGl_FrameBuffer*                 theReadDrawFbo,
+                                               const Handle(OpenGl_Context)&       theGlContext)
+{
   // Output accumulated path traced image
   theGlContext->BindProgram (myOutImageProgram);
 
+  // Choose proper set of frame buffers for stereo rendering
+  const Standard_Integer aFBOIdx = (theProjection == Graphic3d_Camera::Projection_MonoRightEye) ? 1 : 0;
+
   if (myRaytraceParameters.AdaptiveScreenSampling)
   {
     // Set uniforms for display program
-    myOutImageProgram->SetUniform (theGlContext, "uRenderImage",   anImageId);
+    myOutImageProgram->SetUniform (theGlContext, "uRenderImage",   OpenGl_RT_OutputImage);
     myOutImageProgram->SetUniform (theGlContext, "uAccumFrames",   myAccumFrames);
-    myOutImageProgram->SetUniform (theGlContext, "uVarianceImage", anErrorId);
+    myOutImageProgram->SetUniform (theGlContext, "uVarianceImage", OpenGl_RT_VisualErrorImage);
     myOutImageProgram->SetUniform (theGlContext, "uDebugAdaptive", myRenderParams.ShowSamplingTiles ?  1 : 0);
+    myOutImageProgram->SetUniform (theGlContext, "uTileSize",      myTileSampler.TileSize());
+    myOutImageProgram->SetUniform (theGlContext, "uVarianceScaleFactor", myTileSampler.VarianceScaleFactor());
   }
 
   if (myRaytraceParameters.GlobalIllumination)
@@ -3089,40 +3012,26 @@ Standard_Boolean OpenGl_View::runPathtrace (const Standard_Integer
   {
     theReadDrawFbo->BindBuffer (theGlContext);
   }
-  else
-  {
-    aRenderImageFramebuffer->UnbindBuffer (theGlContext);
-  }
 
+  const Handle(OpenGl_FrameBuffer)& aRenderImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO1[aFBOIdx] : myRaytraceFBO2[aFBOIdx];
   aRenderImageFramebuffer->ColorTexture()->Bind (theGlContext, OpenGl_RT_PrevAccumTexture);
 
-  glEnable (GL_DEPTH_TEST);
-
   // Copy accumulated image with correct depth values
+  glEnable (GL_DEPTH_TEST);
   theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
 
   aRenderImageFramebuffer->ColorTexture()->Unbind (theGlContext, OpenGl_RT_PrevAccumTexture);
 
   if (myRaytraceParameters.AdaptiveScreenSampling)
   {
-    myRaytraceVisualErrorTexture[aFBOIdx]->Bind (theGlContext);
-
-    // Download visual error map from the GPU and build
-    // adjusted tile offsets for optimal image sampling
-    myTileSampler.GrabVarianceMap (theGlContext);
-
-    myTileSampler.Upload (theGlContext,
-                          myRaytraceTileOffsetsTexture[aFBOIdx],
-                          myRaytraceParameters.NbTilesX,
-                          myRaytraceParameters.NbTilesY,
-                          myAccumFrames > 0);
+    // Download visual error map from the GPU and build adjusted tile offsets for optimal image sampling
+    myTileSampler.GrabVarianceMap (theGlContext, myRaytraceVisualErrorTexture[aFBOIdx]);
+    myTileSampler.UploadOffsets (theGlContext, myRaytraceTileOffsetsTexture[aFBOIdx], myAccumFrames != 0);
   }
 
   unbindRaytraceTextures (theGlContext);
-
   theGlContext->BindProgram (NULL);
-
-  return aResult;
+  return true;
 }
 
 // =======================================================================
@@ -3135,7 +3044,7 @@ Standard_Boolean OpenGl_View::raytrace (const Standard_Integer        theSizeX,
                                         OpenGl_FrameBuffer*           theReadDrawFbo,
                                         const Handle(OpenGl_Context)& theGlContext)
 {
-  if (!initRaytraceResources (theGlContext))
+  if (!initRaytraceResources (theSizeX, theSizeY, theGlContext))
   {
     return Standard_False;
   }
index 2a6c5d1..ceecfea 100644 (file)
@@ -1092,15 +1092,16 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
 
   if (!toRenderGL)
   {
-    toRenderGL = !initRaytraceResources (aCtx) ||
-      !updateRaytraceGeometry (OpenGl_GUM_CHECK, myId, aCtx);
+    const Standard_Integer aSizeX = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeX() : myWindow->Width();
+    const Standard_Integer aSizeY = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeY() : myWindow->Height();
+
+    toRenderGL = !initRaytraceResources (aSizeX, aSizeY, aCtx)
+              || !updateRaytraceGeometry (OpenGl_GUM_CHECK, myId, aCtx);
 
     toRenderGL |= !myIsRaytraceDataValid; // if no ray-trace data use OpenGL
 
     if (!toRenderGL)
     {
-      const Standard_Integer aSizeX = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeX() : myWindow->Width();
-      const Standard_Integer aSizeY = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeY() : myWindow->Height();
       myOpenGlFBO ->InitLazy (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, 0);
 
       if (theReadDrawFbo != NULL)
index ec949eb..ecb82cc 100644 (file)
   //! OpenGL image storing variance of sampled pixels blocks.
   volatile restrict layout(size1x32) uniform iimage2D uVarianceImage;
 
+  //! Scale factor used to quantize visual error (float) into signed integer.
+  uniform float uVarianceScaleFactor;
+
+  //! Screen space tile size.
+  uniform ivec2 uTileSize;
+
 #else // ADAPTIVE_SAMPLING
 
   //! Input image.
@@ -42,9 +48,6 @@ out vec4 OutColor;
 //! RGB weight factors to calculate luminance.
 #define LUMA vec3 (0.2126f, 0.7152f, 0.0722f)
 
-//! Scale factor used to quantize visual error.
-#define SCALE_FACTOR 1.0e6f
-
 // =======================================================================
 // function : ToneMappingFilmic
 // purpose  :
@@ -113,7 +116,8 @@ void main (void)
 
   // accumulate visual error to current block; estimated error is written only
   // after the first 40 samples and path length has reached 10 bounces or more
-  imageAtomicAdd (uVarianceImage, ivec2 (aPixel / vec2 (BLOCK_SIZE)), int (mix (SCALE_FACTOR, anError * SCALE_FACTOR, aColor.w > 40.f)));
+  imageAtomicAdd (uVarianceImage, aPixel / uTileSize,
+                  int (mix (uVarianceScaleFactor, anError * uVarianceScaleFactor, aColor.w > 40.f)));
 
   if (uDebugAdaptive == 0) // normal rendering
   {
index c9edddf..f9b9637 100644 (file)
@@ -101,6 +101,9 @@ uniform float uSceneEpsilon;
 
   //! OpenGL image storing offsets of sampled pixels blocks.
   coherent restrict layout(size2x32) uniform iimage2D uOffsetImage;
+
+  //! Screen space tile size.
+  uniform ivec2 uTileSize;
 #endif
 
 //! Top color of gradient background.
@@ -275,10 +278,9 @@ vec4 BackgroundColor()
 
   ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);
 
-  ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE,
-                                                  aFragCoord.y / BLOCK_SIZE)).xy;
+  ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;
 
-  aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, BLOCK_SIZE);
+  aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, uTileSize.y);
 
   return mix (uBackColorBot, uBackColorTop, float (aTileXY.y) / uWinSizeY);
 
index e3937ff..bc62690 100644 (file)
@@ -38,11 +38,11 @@ void main (void)
 
 #ifdef ADAPTIVE_SAMPLING
 
-  ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE,
-                                                  aFragCoord.y / BLOCK_SIZE)).xy;
+  ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;
+  if (aTileXY.x < 0) { discard; }
 
-  ivec2 aRealBlockSize = ivec2 (min (uWinSizeX - aTileXY.x, BLOCK_SIZE),
-                                min (uWinSizeY - aTileXY.y, BLOCK_SIZE));
+  ivec2 aRealBlockSize = ivec2 (min (uWinSizeX - aTileXY.x, uTileSize.x),
+                                min (uWinSizeY - aTileXY.y, uTileSize.y));
 
   aFragCoord.x = aTileXY.x + (aFragCoord.x % aRealBlockSize.x);
   aFragCoord.y = aTileXY.y + (aFragCoord.y % aRealBlockSize.y);
index 043f72b..281fdcc 100644 (file)
@@ -13,6 +13,12 @@ static const char Shaders_Display_fs[] =
   "  //! OpenGL image storing variance of sampled pixels blocks.\n"
   "  volatile restrict layout(size1x32) uniform iimage2D uVarianceImage;\n"
   "\n"
+  "  //! Scale factor used to quantize visual error (float) into signed integer.\n"
+  "  uniform float uVarianceScaleFactor;\n"
+  "\n"
+  "  //! Screen space tile size.\n"
+  "  uniform ivec2 uTileSize;\n"
+  "\n"
   "#else // ADAPTIVE_SAMPLING\n"
   "\n"
   "  //! Input image.\n"
@@ -45,9 +51,6 @@ static const char Shaders_Display_fs[] =
   "//! RGB weight factors to calculate luminance.\n"
   "#define LUMA vec3 (0.2126f, 0.7152f, 0.0722f)\n"
   "\n"
-  "//! Scale factor used to quantize visual error.\n"
-  "#define SCALE_FACTOR 1.0e6f\n"
-  "\n"
   "// =======================================================================\n"
   "// function : ToneMappingFilmic\n"
   "// purpose  :\n"
@@ -116,7 +119,8 @@ static const char Shaders_Display_fs[] =
   "\n"
   "  // accumulate visual error to current block; estimated error is written only\n"
   "  // after the first 40 samples and path length has reached 10 bounces or more\n"
-  "  imageAtomicAdd (uVarianceImage, ivec2 (aPixel / vec2 (BLOCK_SIZE)), int (mix (SCALE_FACTOR, anError * SCALE_FACTOR, aColor.w > 40.f)));\n"
+  "  imageAtomicAdd (uVarianceImage, aPixel / uTileSize,\n"
+  "                  int (mix (uVarianceScaleFactor, anError * uVarianceScaleFactor, aColor.w > 40.f)));\n"
   "\n"
   "  if (uDebugAdaptive == 0) // normal rendering\n"
   "  {\n"
index 81a2ae0..eeab5a9 100644 (file)
@@ -104,6 +104,9 @@ static const char Shaders_RaytraceBase_fs[] =
   "\n"
   "  //! OpenGL image storing offsets of sampled pixels blocks.\n"
   "  coherent restrict layout(size2x32) uniform iimage2D uOffsetImage;\n"
+  "\n"
+  "  //! Screen space tile size.\n"
+  "  uniform ivec2 uTileSize;\n"
   "#endif\n"
   "\n"
   "//! Top color of gradient background.\n"
@@ -278,10 +281,9 @@ static const char Shaders_RaytraceBase_fs[] =
   "\n"
   "  ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);\n"
   "\n"
-  "  ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE,\n"
-  "                                                  aFragCoord.y / BLOCK_SIZE)).xy;\n"
+  "  ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;\n"
   "\n"
-  "  aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, BLOCK_SIZE);\n"
+  "  aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, uTileSize.y);\n"
   "\n"
   "  return mix (uBackColorBot, uBackColorTop, float (aTileXY.y) / uWinSizeY);\n"
   "\n"
index 1d6e5bd..1fe09ac 100644 (file)
@@ -41,11 +41,11 @@ static const char Shaders_RaytraceRender_fs[] =
   "\n"
   "#ifdef ADAPTIVE_SAMPLING\n"
   "\n"
-  "  ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE,\n"
-  "                                                  aFragCoord.y / BLOCK_SIZE)).xy;\n"
+  "  ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;\n"
+  "  if (aTileXY.x < 0) { discard; }\n"
   "\n"
-  "  ivec2 aRealBlockSize = ivec2 (min (uWinSizeX - aTileXY.x, BLOCK_SIZE),\n"
-  "                                min (uWinSizeY - aTileXY.y, BLOCK_SIZE));\n"
+  "  ivec2 aRealBlockSize = ivec2 (min (uWinSizeX - aTileXY.x, uTileSize.x),\n"
+  "                                min (uWinSizeY - aTileXY.y, uTileSize.y));\n"
   "\n"
   "  aFragCoord.x = aTileXY.x + (aFragCoord.x % aRealBlockSize.x);\n"
   "  aFragCoord.y = aTileXY.y + (aFragCoord.y % aRealBlockSize.y);\n"
index f5c09e3..bc12b99 100644 (file)
@@ -10371,6 +10371,7 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
     theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
+    theDI << "tile size (iss):" <<  aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
     theDI << "shadingModel: ";
     switch (aView->ShadingModel())
     {
@@ -10812,6 +10813,27 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       }
       aParams.ShowSamplingTiles = toEnable;
     }
+    else if (aFlag == "-tilesize")
+    {
+      if (toPrint)
+      {
+        theDI << aParams.RayTracingTileSize << " ";
+        continue;
+      }
+      else if (++anArgIter >= theArgNb)
+      {
+        std::cerr << "Error: wrong syntax at argument '" << anArg << "'\n";
+        return 1;
+      }
+
+      const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
+      if (aTileSize < 1)
+      {
+        std::cerr << "Error: invalid size of ISS tile " << aTileSize << ".\n";
+        return 1;
+      }
+      aParams.RayTracingTileSize = aTileSize;
+    }
     else if (aFlag == "-nbtiles")
     {
       if (toPrint)
@@ -10826,17 +10848,18 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       }
 
       const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
-
-      if (aNbTiles < 64)
+      if (aNbTiles < -1)
       {
         std::cerr << "Error: invalid number of ISS tiles " << aNbTiles << ".\n";
-        std::cerr << "Specify value in range [64, 1024].\n";
         return 1;
       }
-      else
+      else if (aNbTiles > 0
+            && (aNbTiles < 64
+             || aNbTiles > 1024))
       {
-        aParams.NbRayTracingTiles = aNbTiles;
+        std::cerr << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].\n";
       }
+      aParams.NbRayTracingTiles = aNbTiles;
     }
     else if (aFlag == "-env")
     {
@@ -12826,7 +12849,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n      '-iss          on|off'      Enables/disables adaptive screen sampling (PT mode)"
     "\n      '-issd         on|off'      Shows screen sampling distribution in ISS mode"
     "\n      '-maxrad       > 0.0'       Value used for clamping radiance estimation (PT mode)"
-    "\n      '-nbtiles      64..1024'    Specifies number of screen tiles in ISS mode"
+    "\n      '-tileSize     1..4096'     Specifies   size of screen tiles in ISS mode (32 by default)"
+    "\n      '-nbtiles      64..1024'    Specifies number of screen tiles per Redraw in ISS mode (256 by default)"
     "\n      '-rebuildGlsl  on|off'      Rebuild Ray-Tracing GLSL programs (for debugging)"
     "\n      '-shadingModel model'       Controls shading model from enumeration"
     "\n                                  color, flat, gouraud, phong"