UseEnvironmentMapBackground (Standard_False),
CoherentPathTracingMode (Standard_False),
AdaptiveScreenSampling (Standard_False),
+ AdaptiveScreenSamplingAtomic(Standard_False),
ShowSamplingTiles (Standard_False),
TwoSidedBsdfModels (Standard_False),
RadianceClampingValue (30.0),
Standard_Boolean UseEnvironmentMapBackground; //!< enables/disables environment map background
Standard_Boolean CoherentPathTracingMode; //!< enables/disables 'coherent' tracing mode (single RNG seed within 16x16 image blocks)
Standard_Boolean AdaptiveScreenSampling; //!< enables/disables adaptive screen sampling mode for path tracing, FALSE by default
+ Standard_Boolean AdaptiveScreenSamplingAtomic;//!< enables/disables usage of atomic float operations within adaptive screen sampling, FALSE by default
Standard_Boolean ShowSamplingTiles; //!< enables/disables debug mode for adaptive screen sampling, FALSE by default
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.
Graphic3d_TypeOfLimit_HasRayTracing, //!< indicates whether ray tracing is supported
Graphic3d_TypeOfLimit_HasRayTracingTextures, //!< indicates whether ray tracing textures are supported
Graphic3d_TypeOfLimit_HasRayTracingAdaptiveSampling, //!< indicates whether adaptive screen sampling is supported
+ Graphic3d_TypeOfLimit_HasRayTracingAdaptiveSamplingAtomic,//!< indicates whether optimized adaptive screen sampling is supported (hardware supports atomic float operations)
Graphic3d_TypeOfLimit_HasBlendedOit, //!< indicates whether necessary GL extensions for Weighted, Blended OIT available (without MSAA).
Graphic3d_TypeOfLimit_HasBlendedOitMsaa, //!< indicates whether necessary GL extensions for Weighted, Blended OIT available (with MSAA).
Graphic3d_TypeOfLimit_HasFlatShading, //!< indicates whether Flat shading (Graphic3d_TOSM_FACET) is supported
myHasRayTracing (Standard_False),
myHasRayTracingTextures (Standard_False),
myHasRayTracingAdaptiveSampling (Standard_False),
+ myHasRayTracingAdaptiveSamplingAtomic (Standard_False),
myFrameStats (new OpenGl_FrameStats()),
#if !defined(GL_ES_VERSION_2_0)
myPointSpriteOrig (GL_UPPER_LEFT),
// check whether adaptive screen sampling in ray tracing mode is supported
myHasRayTracingAdaptiveSampling = myHasRayTracing
- && has44
- && CheckExtension ("GL_NV_shader_atomic_float");
+ && has44;
+ myHasRayTracingAdaptiveSamplingAtomic = myHasRayTracingAdaptiveSampling
+ && CheckExtension ("GL_NV_shader_atomic_float");
if (!has32)
{
//! @return TRUE if adaptive screen sampling in ray tracing mode is supported
Standard_Boolean HasRayTracingAdaptiveSampling() const { return myHasRayTracingAdaptiveSampling; }
+ //! @return TRUE if atomic adaptive screen sampling in ray tracing mode is supported
+ Standard_Boolean HasRayTracingAdaptiveSamplingAtomic() const { return myHasRayTracingAdaptiveSamplingAtomic; }
+
//! Returns true if VBO is supported and permitted.
inline bool ToUseVbo() const
{
Standard_Boolean myIsGlNormalizeEnabled; //!< GL_NORMALIZE flag
//!< Used to tell OpenGl that normals should be normalized
- Standard_Boolean myHasRayTracing; //! indicates whether ray tracing mode is supported
- Standard_Boolean myHasRayTracingTextures; //! indicates whether textures in ray tracing mode are supported
- Standard_Boolean myHasRayTracingAdaptiveSampling; //! indicates whether adaptive screen sampling in ray tracing mode is supported
+ Standard_Boolean myHasRayTracing; //! indicates whether ray tracing mode is supported
+ Standard_Boolean myHasRayTracingTextures; //! indicates whether textures in ray tracing mode are supported
+ Standard_Boolean myHasRayTracingAdaptiveSampling; //! indicates whether adaptive screen sampling in ray tracing mode is supported
+ Standard_Boolean myHasRayTracingAdaptiveSamplingAtomic; //! indicates whether atomic adaptive screen sampling in ray tracing mode is supported
Handle(OpenGl_ShaderManager) myShaderManager; //! support object for managing shader programs
aMemFbos += estimatedDataSize (aView->myRaytraceVisualErrorTexture[1]);
aMemFbos += estimatedDataSize (aView->myRaytraceTileOffsetsTexture[0]);
aMemFbos += estimatedDataSize (aView->myRaytraceTileOffsetsTexture[1]);
+ aMemFbos += estimatedDataSize (aView->myRaytraceTileSamplesTexture[0]);
+ aMemFbos += estimatedDataSize (aView->myRaytraceTileSamplesTexture[1]);
}
{
// Ray Tracing geometry
return (!aCtx.IsNull() && aCtx->HasRayTracingTextures()) ? 1 : 0;
case Graphic3d_TypeOfLimit_HasRayTracingAdaptiveSampling:
return (!aCtx.IsNull() && aCtx->HasRayTracingAdaptiveSampling()) ? 1 : 0;
+ case Graphic3d_TypeOfLimit_HasRayTracingAdaptiveSamplingAtomic:
+ return (!aCtx.IsNull() && aCtx->HasRayTracingAdaptiveSamplingAtomic()) ? 1 : 0;
case Graphic3d_TypeOfLimit_HasBlendedOit:
return (!aCtx.IsNull()
&& aCtx->hasDrawBuffers != OpenGl_FeatureNotAvailable
#include <Graphic3d_RenderingParams.hxx>
#include <TCollection_ExtendedString.hxx>
+// define to debug algorithm values
+//#define RAY_TRACE_PRINT_DEBUG_INFO
+
//=======================================================================
//function : OpenGl_TileSampler
//purpose :
for (Standard_Size aRowIter = 0; aRowIter < myVarianceMap.SizeY; ++aRowIter)
{
const int aRawValue = myVarianceRaw.Value (aRowIter, aColIter);
+ Standard_RangeError_Raise_if (aRawValue < 0, "Internal Error: signed integer overflow within OpenGl_TileSampler");
+
float& aTile = myVarianceMap.ChangeValue (aRowIter, aColIter);
aTile = aFactor * float(aRawValue);
aTile *= 1.0f / tileArea ((int )aColIter, (int )aRowIter); // average error over the tile
myMarginalMap[aX] += myMarginalMap[aX - 1];
}
}
+
+#ifdef RAY_TRACE_PRINT_DEBUG_INFO
+ dumpMap (std::cerr, myVarianceRaw, "OpenGl_TileSampler, Variance map");
+#endif
+}
+
+//=======================================================================
+//function : dumpMap
+//purpose :
+//=======================================================================
+void OpenGl_TileSampler::dumpMap (std::ostream& theStream,
+ const Image_PixMapTypedData<int>& theMap,
+ const char* theTitle) const
+{
+ theStream << theTitle << " " << theMap.SizeX << "x" << theMap.SizeY << " (tile " << myTileSize << "x" << myTileSize << ")" << ":\n";
+ for (Standard_Size aRowIter = 0; aRowIter < theMap.SizeY; ++aRowIter)
+ {
+ for (Standard_Size aColIter = 0; aColIter < theMap.SizeX; ++aColIter)
+ {
+ theStream << " [" << theMap.Value (aRowIter, aColIter) << "]";
+ }
+ theStream << "\n";
+ }
}
//=======================================================================
myTiles.Init (anAlloc, aNbTilesX, aNbTilesY);
myTiles.Init (1);
+ myTileSamples.SetTopDown (true);
+ myTileSamples.Init (myTiles.Allocator(), aNbTilesX, aNbTilesY);
+ myTileSamples.Init (1);
+
myVarianceMap.SetTopDown (true);
myVarianceMap.Init (myTiles.Allocator(), myTiles.SizeX, myTiles.SizeY);
myVarianceMap.Init (0.0f);
}
//=======================================================================
-//function : UploadOffsets
+//function : upload
//purpose :
//=======================================================================
-bool OpenGl_TileSampler::UploadOffsets (const Handle(OpenGl_Context)& theContext,
- const Handle(OpenGl_Texture)& theOffsetsTexture,
- const bool theAdaptive)
+bool OpenGl_TileSampler::upload (const Handle(OpenGl_Context)& theContext,
+ const Handle(OpenGl_Texture)& theSamplesTexture,
+ const Handle(OpenGl_Texture)& theOffsetsTexture,
+ const bool theAdaptive)
{
if (myTiles.IsEmpty())
{
return false;
}
+ // Fill in myTiles map with a number of passes (samples) per tile.
+ // By default, all tiles receive 1 sample, but basing on visual error level (myVarianceMap),
+ // this amount is re-distributed from tiles having smallest error take 0 samples to tiles having larger error.
+ // This redistribution is smoothed by Halton sampler.
+ //
+ // myOffsets map is filled as redirection of currently rendered tile to another one
+ // so that tiles having smallest error level have 0 tiles redirected from,
+ // while tiles with great error level might be rendered more than 1.
+ // This map is used within single-pass rendering method requiring atomic float operation support from hardware.
myTiles.Init (0);
Image_PixMapTypedData<Graphic3d_Vec2i>& anOffsets = theAdaptive ? myOffsetsShrunk : myOffsets;
anOffsets.Init (Graphic3d_Vec2i (-1, -1));
}
}
+#ifdef RAY_TRACE_PRINT_DEBUG_INFO
+ dumpMap (std::cerr, myTiles, "OpenGl_TileSampler, Samples");
+#endif
+
+ // Fill in myTileSamples map from myTiles with an actual number of Samples per Tile as multiple of Tile Area
+ // (e.g. tile that should be rendered ones will have amount of samples equal to its are 4x4=16).
+ // This map is used for discarding tile fragments having <=0 of samples left within multi-pass rendering.
+ myTileSamples.Init (0);
+ for (Standard_Size aRowIter = 0; aRowIter < myTiles.SizeY; ++aRowIter)
+ {
+ for (Standard_Size aColIter = 0; aColIter < myTiles.SizeX; ++aColIter)
+ {
+ myTileSamples.ChangeValue (aRowIter, aColIter) = tileArea ((int )aColIter, (int )aRowIter) * myTiles.Value (aRowIter, aColIter);
+ }
+ }
+
bool hasErrors = false;
+
+ if (!theSamplesTexture.IsNull())
+ {
+ theSamplesTexture->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
+ if (theSamplesTexture->SizeX() == (int )myTileSamples.SizeX
+ && theSamplesTexture->SizeY() == (int )myTileSamples.SizeY)
+ {
+ theContext->core11fwd->glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, (int )myTileSamples.SizeX, (int )myTileSamples.SizeY, GL_RED_INTEGER, GL_INT, myTileSamples.Data());
+ if (theContext->core11fwd->glGetError() != GL_NO_ERROR)
+ {
+ hasErrors = true;
+ theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
+ "Error! Failed to upload tile samples map on the GPU");
+ }
+ }
+ else
+ {
+ hasErrors = true;
+ }
+ theSamplesTexture->Unbind (theContext);
+ }
+
if (!theOffsetsTexture.IsNull())
{
if (theOffsetsTexture->SizeX() != (int )anOffsets.SizeX
//! Maximum viewport for rendering using offsets texture.
Graphic3d_Vec2i OffsetTilesViewportMax() const { return NbOffsetTilesMax() * myTileSize; }
+ //! Return maximum number of samples per tile.
+ int MaxTileSamples() const
+ {
+ int aNbSamples = 0;
+ for (Standard_Size aRowIter = 0; aRowIter < myTiles.SizeY; ++aRowIter)
+ {
+ for (Standard_Size aColIter = 0; aColIter < myTiles.SizeX; ++aColIter)
+ {
+ aNbSamples = Max (aNbSamples, myTiles.Value (aRowIter, aColIter));
+ }
+ }
+ return aNbSamples;
+ }
+
//! Specifies size of ray-tracing viewport and recomputes tile size.
Standard_EXPORT void SetSize (const Graphic3d_RenderingParams& theParams,
const Graphic3d_Vec2i& theSize);
//! Resets (restart) tile sampler to initial state.
void Reset() { myLastSample = 0; }
+ //! Uploads tile samples to the given OpenGL texture.
+ bool UploadSamples (const Handle(OpenGl_Context)& theContext,
+ const Handle(OpenGl_Texture)& theSamplesTexture,
+ const bool theAdaptive)
+ {
+ return upload (theContext, theSamplesTexture, Handle(OpenGl_Texture)(), theAdaptive);
+ }
+
//! Uploads offsets of sampled tiles to the given OpenGL texture.
- Standard_EXPORT bool UploadOffsets (const Handle(OpenGl_Context)& theContext,
- const Handle(OpenGl_Texture)& theOffsetsTexture,
- const bool theAdaptive);
+ bool UploadOffsets (const Handle(OpenGl_Context)& theContext,
+ const Handle(OpenGl_Texture)& theOffsetsTexture,
+ const bool theAdaptive)
+ {
+ return upload (theContext, Handle(OpenGl_Texture)(), theOffsetsTexture, theAdaptive);
+ }
protected:
//! Samples tile location according to estimated error.
Standard_EXPORT Graphic3d_Vec2i nextTileToSample();
+ //! Uploads offsets of sampled tiles to the given OpenGL texture.
+ Standard_EXPORT bool upload (const Handle(OpenGl_Context)& theContext,
+ const Handle(OpenGl_Texture)& theSamplesTexture,
+ const Handle(OpenGl_Texture)& theOffsetsTexture,
+ const bool theAdaptive);
+
+ //! Auxiliary method for dumping 2D image map into stream (e.g. for debugging).
+ Standard_EXPORT void dumpMap (std::ostream& theStream,
+ const Image_PixMapTypedData<int>& theMap,
+ const char* theTitle) const;
+
protected:
Image_PixMapTypedData<unsigned int> myTiles; //!< number of samples per tile (initially all 1)
+ Image_PixMapTypedData<unsigned int> myTileSamples; //!< number of samples for all pixels within the tile (initially equals to Tile area)
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
// images used by ISS mode
OpenGl_RT_uRenderImage,
+ OpenGl_RT_uTilesImage,
OpenGl_RT_uOffsetImage,
OpenGl_RT_uTileSize,
OpenGl_RT_uVarianceScaleFactor,
OpenGl_RT_OutputImage = 0,
OpenGl_RT_VisualErrorImage = 1,
OpenGl_RT_TileOffsetsImage = 2,
+ OpenGl_RT_TileSamplesImage = 3
};
//! Tool class for management of shader sources.
//! Enables/disables adaptive screen sampling for path tracing.
Standard_Boolean AdaptiveScreenSampling;
+ //! Enables/disables 1-pass atomic mode for AdaptiveScreenSampling.
+ Standard_Boolean AdaptiveScreenSamplingAtomic;
+
//! Enables/disables environment map for background.
Standard_Boolean UseEnvMapForBackground;
UseBindlessTextures (Standard_False),
TwoSidedBsdfModels (Standard_False),
AdaptiveScreenSampling (Standard_False),
+ AdaptiveScreenSamplingAtomic (Standard_False),
UseEnvMapForBackground (Standard_False),
RadianceClampingValue (30.0),
DepthOfField (Standard_False),
//! Texture containing offsets of sampled screen tiles (2 textures are used in stereo mode).
//! Used if adaptive screen sampling is activated.
Handle(OpenGl_Texture) myRaytraceTileOffsetsTexture[2];
+ //! Texture containing amount of extra per-tile samples (2 textures are used in stereo mode).
+ //! Used if adaptive screen sampling is activated.
+ Handle(OpenGl_Texture) myRaytraceTileSamplesTexture[2];
//! Vertex buffer (VBO) for drawing dummy quad.
OpenGl_VertexBuffer myRaytraceScreenQuad;
if (myRaytraceParameters.AdaptiveScreenSampling) // adaptive screen sampling requested
{
- // 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"))
+ if (theGlContext->IsGlGreaterEqual (4, 4))
{
aPrefixString += TCollection_AsciiString ("\n#define ADAPTIVE_SAMPLING");
+ if (myRaytraceParameters.AdaptiveScreenSamplingAtomic
+ && theGlContext->CheckExtension ("GL_NV_shader_atomic_float"))
+ {
+ aPrefixString += TCollection_AsciiString ("\n#define ADAPTIVE_SAMPLING_ATOMIC");
+ }
}
}
aToRebuildShaders = Standard_True;
}
- if (myRenderParams.AdaptiveScreenSampling != myRaytraceParameters.AdaptiveScreenSampling)
+ if (myRenderParams.AdaptiveScreenSampling != myRaytraceParameters.AdaptiveScreenSampling
+ || myRenderParams.AdaptiveScreenSamplingAtomic != myRaytraceParameters.AdaptiveScreenSamplingAtomic)
{
- myRaytraceParameters.AdaptiveScreenSampling = myRenderParams.AdaptiveScreenSampling;
+ myRaytraceParameters.AdaptiveScreenSampling = myRenderParams.AdaptiveScreenSampling;
+ myRaytraceParameters.AdaptiveScreenSamplingAtomic = myRenderParams.AdaptiveScreenSamplingAtomic;
if (myRenderParams.AdaptiveScreenSampling) // adaptive sampling was requested
{
if (!theGlContext->HasRayTracingAdaptiveSampling())
// disable the feature if it is not supported
myRaytraceParameters.AdaptiveScreenSampling = myRenderParams.AdaptiveScreenSampling = Standard_False;
theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
- "Adaptive sampling not supported (OpenGL 4.4 or GL_NV_shader_atomic_float is missing)");
+ "Adaptive sampling is not supported (OpenGL 4.4 is missing)");
+ }
+ else if (myRaytraceParameters.AdaptiveScreenSamplingAtomic
+ && !theGlContext->HasRayTracingAdaptiveSamplingAtomic())
+ {
+ // disable the feature if it is not supported
+ myRaytraceParameters.AdaptiveScreenSamplingAtomic = myRenderParams.AdaptiveScreenSamplingAtomic = Standard_False;
+ theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
+ "Atomic adaptive sampling is not supported (GL_NV_shader_atomic_float is missing)");
}
}
myUniformLocations[anIndex][OpenGl_RT_uRenderImage] =
aShaderProgram->GetUniformLocation (theGlContext, "uRenderImage");
+ myUniformLocations[anIndex][OpenGl_RT_uTilesImage] =
+ aShaderProgram->GetUniformLocation (theGlContext, "uTilesImage");
myUniformLocations[anIndex][OpenGl_RT_uOffsetImage] =
aShaderProgram->GetUniformLocation (theGlContext, "uOffsetImage");
myUniformLocations[anIndex][OpenGl_RT_uTileSize] =
nullifyResource (theGlContext, myRaytraceTileOffsetsTexture[1]);
nullifyResource (theGlContext, myRaytraceVisualErrorTexture[0]);
nullifyResource (theGlContext, myRaytraceVisualErrorTexture[1]);
+ nullifyResource (theGlContext, myRaytraceTileSamplesTexture[0]);
+ nullifyResource (theGlContext, myRaytraceTileSamplesTexture[1]);
nullifyResource (theGlContext, mySceneNodeInfoTexture);
nullifyResource (theGlContext, mySceneMinPointTexture);
{
myRaytraceOutputTexture[aViewIter] = new OpenGl_Texture();
myRaytraceVisualErrorTexture[aViewIter] = new OpenGl_Texture();
+ myRaytraceTileSamplesTexture[aViewIter] = new OpenGl_Texture();
myRaytraceTileOffsetsTexture[aViewIter] = new OpenGl_Texture();
}
&& myRaytraceVisualErrorTexture[aViewIter]->SizeX() == myTileSampler.NbTilesX()
&& myRaytraceVisualErrorTexture[aViewIter]->SizeY() == myTileSampler.NbTilesY())
{
- continue;
+ if (myRaytraceParameters.AdaptiveScreenSamplingAtomic)
+ {
+ continue; // offsets texture is dynamically resized
+ }
+ else if (myRaytraceTileSamplesTexture[aViewIter]->SizeX() == myTileSampler.NbTilesX()
+ && myRaytraceTileSamplesTexture[aViewIter]->SizeY() == myTileSampler.NbTilesY())
+ {
+ continue;
+ }
}
myAccumFrames = 0;
// workaround for some NVIDIA drivers
myRaytraceVisualErrorTexture[aViewIter]->Release (theGlContext.operator->());
+ myRaytraceTileSamplesTexture[aViewIter]->Release (theGlContext.operator->());
myRaytraceVisualErrorTexture[aViewIter]->Init (theGlContext, GL_R32I, GL_RED_INTEGER, GL_INT,
myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
+ if (!myRaytraceParameters.AdaptiveScreenSamplingAtomic)
+ {
+ myRaytraceTileSamplesTexture[aViewIter]->Init (theGlContext, GL_R32I, GL_RED_INTEGER, GL_INT,
+ myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
+ }
}
else // non-adaptive mode
{
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);
+ if (myRaytraceParameters.AdaptiveScreenSamplingAtomic)
+ {
+ theGlContext->core42->glBindImageTexture (OpenGl_RT_TileOffsetsImage,
+ myRaytraceTileOffsetsTexture[theStereoView]->TextureId(), 0, GL_TRUE, 0, GL_READ_ONLY, GL_RG32I);
+ }
+ else
+ {
+ theGlContext->core42->glBindImageTexture (OpenGl_RT_TileSamplesImage,
+ myRaytraceTileSamplesTexture[theStereoView]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32I);
+ }
#else
(void )theStereoView;
#endif
myTileSampler.Reset(); // reset tile sampler to its initial state
// Adaptive sampling is starting at the second frame
- myTileSampler.UploadOffsets (theGlContext, myRaytraceTileOffsetsTexture[aFBOIdx], false);
+ if (myRaytraceParameters.AdaptiveScreenSamplingAtomic)
+ {
+ myTileSampler.UploadOffsets (theGlContext, myRaytraceTileOffsetsTexture[aFBOIdx], false);
+ }
+ else
+ {
+ myTileSampler.UploadSamples (theGlContext, myRaytraceTileSamplesTexture[aFBOIdx], false);
+ }
#if !defined(GL_ES_VERSION_2_0)
theGlContext->core44->glClearTexImage (myRaytraceOutputTexture[aFBOIdx]->TextureId(), 0, GL_RED, GL_FLOAT, NULL);
// 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));
-
// Set image uniforms for render program
if (myRaytraceParameters.AdaptiveScreenSampling)
{
myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uRenderImage], OpenGl_RT_OutputImage);
+ myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uTilesImage], OpenGl_RT_TileSamplesImage);
myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uOffsetImage], OpenGl_RT_TileOffsetsImage);
myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uTileSize], myTileSampler.TileSize());
}
const Handle(OpenGl_FrameBuffer)& aRenderImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO1[aFBOIdx] : myRaytraceFBO2[aFBOIdx];
aRenderImageFramebuffer->BindBuffer (theGlContext);
- if (myRaytraceParameters.AdaptiveScreenSampling)
+ if (myRaytraceParameters.AdaptiveScreenSampling
+ && myRaytraceParameters.AdaptiveScreenSamplingAtomic)
{
// 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
// Generate for the given RNG seed
glDisable (GL_DEPTH_TEST);
- theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
+ // Adaptive Screen Sampling computes the same overall amount of samples per frame redraw as normal Path Tracing,
+ // but distributes them unequally across pixels (grouped in tiles), so that some pixels do not receive new samples at all.
+ //
+ // Offsets map (redirecting currently rendered tile to another tile) allows performing Adaptive Screen Sampling in single pass,
+ // but current implementation relies on atomic float operations (AdaptiveScreenSamplingAtomic) for this.
+ // So that when atomic floats are not supported by GPU, multi-pass rendering is used instead.
+ //
+ // Single-pass rendering is more optimal due to smaller amount of draw calls,
+ // memory synchronization barriers, discarding most of the fragments and bad parallelization in case of very small amount of tiles requiring more samples.
+ // However, atomic operations on float values still produces different result (close, but not bit exact) making non-regression testing not robust.
+ // It should be possible following single-pass rendering approach but using extra accumulation buffer and resolving pass as possible improvement.
+ const int aNbPasses = myRaytraceParameters.AdaptiveScreenSampling
+ && !myRaytraceParameters.AdaptiveScreenSamplingAtomic
+ ? myTileSampler.MaxTileSamples()
+ : 1;
+ if (myAccumFrames == 0)
+ {
+ myRNG.SetSeed(); // start RNG from beginning
+ }
+ for (int aPassIter = 0; aPassIter < aNbPasses; ++aPassIter)
+ {
+ myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uFrameRndSeed], static_cast<Standard_Integer> (myRNG.NextInt() >> 2));
+ theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
+ if (myRaytraceParameters.AdaptiveScreenSampling)
+ {
+ #if !defined(GL_ES_VERSION_2_0)
+ theGlContext->core44->glMemoryBarrier (GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
+ #endif
+ }
+ }
aRenderImageFramebuffer->UnbindBuffer (theGlContext);
- if (myRaytraceParameters.AdaptiveScreenSampling)
+ if (myRaytraceParameters.AdaptiveScreenSampling
+ && myRaytraceParameters.AdaptiveScreenSamplingAtomic)
{
glViewport (0, 0, theSizeX, theSizeY);
}
{
// 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);
+ if (myRaytraceParameters.AdaptiveScreenSamplingAtomic)
+ {
+ myTileSampler.UploadOffsets (theGlContext, myRaytraceTileOffsetsTexture[aFBOIdx], myAccumFrames != 0);
+ }
+ else
+ {
+ myTileSampler.UploadSamples (theGlContext, myRaytraceTileSamplesTexture[aFBOIdx], myAccumFrames != 0);
+ }
}
unbindRaytraceTextures (theGlContext);
#extension GL_ARB_shader_image_size : enable
//! OpenGL image used for accumulating rendering result.
- volatile restrict layout(size1x32) uniform image2D uRenderImage;
+ volatile restrict layout(r32f) uniform image2D uRenderImage;
//! OpenGL image storing variance of sampled pixels blocks.
- volatile restrict layout(size1x32) uniform iimage2D uVarianceImage;
+ volatile restrict layout(r32i) uniform iimage2D uVarianceImage;
//! Scale factor used to quantize visual error (float) into signed integer.
uniform float uVarianceScaleFactor;
#ifdef ADAPTIVE_SAMPLING
#extension GL_ARB_shader_image_load_store : require
+#endif
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
#extension GL_NV_shader_atomic_float : require
#endif
#ifdef ADAPTIVE_SAMPLING
//! OpenGL image used for accumulating rendering result.
- volatile restrict layout(size1x32) uniform image2D uRenderImage;
+ volatile restrict layout(r32f) uniform image2D uRenderImage;
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
//! OpenGL image storing offsets of sampled pixels blocks.
- coherent restrict layout(size2x32) uniform iimage2D uOffsetImage;
+ coherent restrict layout(rg32i) uniform iimage2D uOffsetImage;
+#else
+ //! OpenGL image defining per-tile amount of samples.
+ volatile restrict layout(r32i) uniform iimage2D uTilesImage;
+#endif
//! Screen space tile size.
uniform ivec2 uTileSize;
//=======================================================================
vec4 BackgroundColor()
{
-#ifdef ADAPTIVE_SAMPLING
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);
//! Decreases noise level, but introduces some bias.
uniform float uMaxRadiance = 50.f;
+#ifdef ADAPTIVE_SAMPLING
+//! Wrapper over imageLoad()+imageStore() having similar syntax as imageAtomicAdd().
+//! Modifies one component of 3Wx2H uRenderImage:
+//! |RGL| Red, Green, Luminance
+//! |SBH| Samples, Blue, Hit time transformed into OpenGL NDC space
+//! Returns previous value of the component.
+float addRenderImageComp (in ivec2 theFrag, in ivec2 theComp, in float theVal)
+{
+ ivec2 aCoord = ivec2 (3 * theFrag.x + theComp.x,
+ 2 * theFrag.y + theComp.y);
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
+ return imageAtomicAdd (uRenderImage, aCoord, theVal);
+#else
+ float aVal = imageLoad (uRenderImage, aCoord).x;
+ imageStore (uRenderImage, aCoord, vec4 (aVal + theVal));
+ return aVal;
+#endif
+}
+#endif
+
// =======================================================================
// function : main
// purpose :
#ifdef ADAPTIVE_SAMPLING
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;
if (aTileXY.x < 0) { discard; }
aFragCoord.x = aTileXY.x + (aFragCoord.x % aRealBlockSize.x);
aFragCoord.y = aTileXY.y + (aFragCoord.y % aRealBlockSize.y);
+#else
+ int aNbTileSamples = imageAtomicAdd (uTilesImage, aFragCoord / uTileSize, int(-1));
+ if (aNbTileSamples <= 0)
+ {
+ discard;
+ }
+#endif
#endif // ADAPTIVE_SAMPLING
#else
- float aNbSamples = imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,
- 2 * aFragCoord.y + 1), 1.0);
-
+ float aNbSamples = addRenderImageComp (aFragCoord, ivec2 (0, 1), 1.0);
vec4 aColor = PathTrace (aRay, aInvDirect, int (aNbSamples));
#endif
#ifdef ADAPTIVE_SAMPLING
// accumulate RGB color and depth
- imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,
- 2 * aFragCoord.y + 0), aColor.r);
- imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 1,
- 2 * aFragCoord.y + 0), aColor.g);
- imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 1,
- 2 * aFragCoord.y + 1), aColor.b);
- imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,
- 2 * aFragCoord.y + 1), aColor.w);
+ addRenderImageComp (aFragCoord, ivec2 (0, 0), aColor.r);
+ addRenderImageComp (aFragCoord, ivec2 (1, 0), aColor.g);
+ addRenderImageComp (aFragCoord, ivec2 (1, 1), aColor.b);
+ addRenderImageComp (aFragCoord, ivec2 (2, 1), aColor.w);
if (int (aNbSamples) % 2 == 0) // accumulate luminance for even samples only
{
- imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,
- 2 * aFragCoord.y + 0), dot (LUMA, aColor.rgb));
+ addRenderImageComp (aFragCoord, ivec2 (2, 0), dot (LUMA, aColor.rgb));
}
#else
" #extension GL_ARB_shader_image_size : enable\n"
"\n"
" //! OpenGL image used for accumulating rendering result.\n"
- " volatile restrict layout(size1x32) uniform image2D uRenderImage;\n"
+ " volatile restrict layout(r32f) uniform image2D uRenderImage;\n"
"\n"
" //! OpenGL image storing variance of sampled pixels blocks.\n"
- " volatile restrict layout(size1x32) uniform iimage2D uVarianceImage;\n"
+ " volatile restrict layout(r32i) uniform iimage2D uVarianceImage;\n"
"\n"
" //! Scale factor used to quantize visual error (float) into signed integer.\n"
" uniform float uVarianceScaleFactor;\n"
static const char Shaders_RaytraceBase_fs[] =
"#ifdef ADAPTIVE_SAMPLING\n"
" #extension GL_ARB_shader_image_load_store : require\n"
+ "#endif\n"
+ "#ifdef ADAPTIVE_SAMPLING_ATOMIC\n"
" #extension GL_NV_shader_atomic_float : require\n"
"#endif\n"
"\n"
"\n"
"#ifdef ADAPTIVE_SAMPLING\n"
" //! OpenGL image used for accumulating rendering result.\n"
- " volatile restrict layout(size1x32) uniform image2D uRenderImage;\n"
+ " volatile restrict layout(r32f) uniform image2D uRenderImage;\n"
"\n"
+ "#ifdef ADAPTIVE_SAMPLING_ATOMIC\n"
" //! OpenGL image storing offsets of sampled pixels blocks.\n"
- " coherent restrict layout(size2x32) uniform iimage2D uOffsetImage;\n"
+ " coherent restrict layout(rg32i) uniform iimage2D uOffsetImage;\n"
+ "#else\n"
+ " //! OpenGL image defining per-tile amount of samples.\n"
+ " volatile restrict layout(r32i) uniform iimage2D uTilesImage;\n"
+ "#endif\n"
"\n"
" //! Screen space tile size.\n"
" uniform ivec2 uTileSize;\n"
"//=======================================================================\n"
"vec4 BackgroundColor()\n"
"{\n"
- "#ifdef ADAPTIVE_SAMPLING\n"
+ "#ifdef ADAPTIVE_SAMPLING_ATOMIC\n"
"\n"
" ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);\n"
"\n"
"//! Decreases noise level, but introduces some bias.\n"
"uniform float uMaxRadiance = 50.f;\n"
"\n"
+ "#ifdef ADAPTIVE_SAMPLING\n"
+ "//! Wrapper over imageLoad()+imageStore() having similar syntax as imageAtomicAdd().\n"
+ "//! Modifies one component of 3Wx2H uRenderImage:\n"
+ "//! |RGL| Red, Green, Luminance\n"
+ "//! |SBH| Samples, Blue, Hit time transformed into OpenGL NDC space\n"
+ "//! Returns previous value of the component.\n"
+ "float addRenderImageComp (in ivec2 theFrag, in ivec2 theComp, in float theVal)\n"
+ "{\n"
+ " ivec2 aCoord = ivec2 (3 * theFrag.x + theComp.x,\n"
+ " 2 * theFrag.y + theComp.y);\n"
+ "#ifdef ADAPTIVE_SAMPLING_ATOMIC\n"
+ " return imageAtomicAdd (uRenderImage, aCoord, theVal);\n"
+ "#else\n"
+ " float aVal = imageLoad (uRenderImage, aCoord).x;\n"
+ " imageStore (uRenderImage, aCoord, vec4 (aVal + theVal));\n"
+ " return aVal;\n"
+ "#endif\n"
+ "}\n"
+ "#endif\n"
+ "\n"
"// =======================================================================\n"
"// function : main\n"
"// purpose :\n"
"\n"
"#ifdef ADAPTIVE_SAMPLING\n"
"\n"
+ "#ifdef ADAPTIVE_SAMPLING_ATOMIC\n"
" ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;\n"
" if (aTileXY.x < 0) { discard; }\n"
"\n"
"\n"
" aFragCoord.x = aTileXY.x + (aFragCoord.x % aRealBlockSize.x);\n"
" aFragCoord.y = aTileXY.y + (aFragCoord.y % aRealBlockSize.y);\n"
+ "#else\n"
+ " int aNbTileSamples = imageAtomicAdd (uTilesImage, aFragCoord / uTileSize, int(-1));\n"
+ " if (aNbTileSamples <= 0)\n"
+ " {\n"
+ " discard;\n"
+ " }\n"
+ "#endif\n"
"\n"
"#endif // ADAPTIVE_SAMPLING\n"
"\n"
"\n"
"#else\n"
"\n"
- " float aNbSamples = imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,\n"
- " 2 * aFragCoord.y + 1), 1.0);\n"
- "\n"
+ " float aNbSamples = addRenderImageComp (aFragCoord, ivec2 (0, 1), 1.0);\n"
" vec4 aColor = PathTrace (aRay, aInvDirect, int (aNbSamples));\n"
"\n"
"#endif\n"
"#ifdef ADAPTIVE_SAMPLING\n"
"\n"
" // accumulate RGB color and depth\n"
- " imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,\n"
- " 2 * aFragCoord.y + 0), aColor.r);\n"
- " imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 1,\n"
- " 2 * aFragCoord.y + 0), aColor.g);\n"
- " imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 1,\n"
- " 2 * aFragCoord.y + 1), aColor.b);\n"
- " imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,\n"
- " 2 * aFragCoord.y + 1), aColor.w);\n"
+ " addRenderImageComp (aFragCoord, ivec2 (0, 0), aColor.r);\n"
+ " addRenderImageComp (aFragCoord, ivec2 (1, 0), aColor.g);\n"
+ " addRenderImageComp (aFragCoord, ivec2 (1, 1), aColor.b);\n"
+ " addRenderImageComp (aFragCoord, ivec2 (2, 1), aColor.w);\n"
"\n"
" if (int (aNbSamples) % 2 == 0) // accumulate luminance for even samples only\n"
" {\n"
- " imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,\n"
- " 2 * aFragCoord.y + 0), dot (LUMA, aColor.rgb));\n"
+ " addRenderImageComp (aFragCoord, ivec2 (2, 0), dot (LUMA, aColor.rgb));\n"
" }\n"
"\n"
"#else\n"
}
#endif
-//==============================================================================
-//function : ActivateView
-//purpose : Make the view active
-//==============================================================================
-
-void ActivateView (const TCollection_AsciiString& theViewName)
+//! Make the view active
+void ActivateView (const TCollection_AsciiString& theViewName,
+ Standard_Boolean theToUpdate = Standard_True)
{
const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
- if (!aView.IsNull())
+ if (aView.IsNull())
{
- Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
- if (!anAISContext.IsNull())
- {
- if (!ViewerTest::CurrentView().IsNull())
- {
- TCollection_AsciiString aTitle("3D View - ");
- aTitle = aTitle + ViewerTest_myViews.Find2 (ViewerTest::CurrentView());
- SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
- }
+ return;
+ }
- ViewerTest::CurrentView (aView);
- ViewerTest::SetAISContext (anAISContext);
- TCollection_AsciiString aTitle = TCollection_AsciiString("3D View - ") + theViewName + "(*)";
+ Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
+ if (!anAISContext.IsNull())
+ {
+ if (!ViewerTest::CurrentView().IsNull())
+ {
+ TCollection_AsciiString aTitle("3D View - ");
+ aTitle = aTitle + ViewerTest_myViews.Find2 (ViewerTest::CurrentView());
SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
+ }
+
+ ViewerTest::CurrentView (aView);
+ ViewerTest::SetAISContext (anAISContext);
+ TCollection_AsciiString aTitle = TCollection_AsciiString("3D View - ") + theViewName + "(*)";
+ SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
#if defined(_WIN32)
- VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
+ VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
#elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
- VT_GetWindow() = Handle(Cocoa_Window)::DownCast(ViewerTest::CurrentView()->Window());
+ VT_GetWindow() = Handle(Cocoa_Window)::DownCast(ViewerTest::CurrentView()->Window());
#else
- VT_GetWindow() = Handle(Xw_Window)::DownCast(ViewerTest::CurrentView()->Window());
+ VT_GetWindow() = Handle(Xw_Window)::DownCast(ViewerTest::CurrentView()->Window());
#endif
- SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
+ SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
+ if (theToUpdate)
+ {
ViewerTest::CurrentView()->Redraw();
}
}
}
else
{
- Handle(V3d_View) anEmptyView;
-#if defined(_WIN32) || defined(__WIN32__)
- Handle(WNT_Window) anEmptyWindow;
-#elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
- Handle(Cocoa_Window) anEmptyWindow;
-#else
- Handle(Xw_Window) anEmptyWindow;
-#endif
- VT_GetWindow() = anEmptyWindow;
- ViewerTest::CurrentView (anEmptyView);
+ VT_GetWindow().Nullify();
+ ViewerTest::CurrentView (Handle(V3d_View)());
if (isContextRemoved)
{
Handle(AIS_InteractiveContext) anEmptyContext;
static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
{
- if (theArgsNb > 2)
- {
- theDi << theArgVec[0] << ": wrong number of command arguments.\n"
- << "Usage: " << theArgVec[0] << " ViewID\n";
- return 1;
- }
- if(theArgsNb == 1)
+ if (theArgsNb == 1)
{
theDi.Eval("vviewlist");
return 0;
}
- TCollection_AsciiString aNameString(theArgVec[1]);
- if ( strcasecmp( aNameString.ToCString(), "NONE" ) == 0 )
+ TCollection_AsciiString aNameString;
+ Standard_Boolean toUpdate = Standard_True;
+ Standard_Boolean toActivate = Standard_True;
+ for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
{
- TCollection_AsciiString aTitle("3D View - ");
- aTitle = aTitle + ViewerTest_myViews.Find2(ViewerTest::CurrentView());
- SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
- Handle(V3d_View) anEmptyView;
-#if defined(_WIN32) || defined(__WIN32__)
- Handle(WNT_Window) anEmptyWindow;
-#elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
- Handle(Cocoa_Window) anEmptyWindow;
-#else
- Handle(Xw_Window) anEmptyWindow;
-#endif
- VT_GetWindow() = anEmptyWindow;
- ViewerTest::CurrentView (anEmptyView);
- ViewerTest::ResetEventManager();
- theDi << theArgVec[0] << ": all views are inactive\n";
- return 0;
+ TCollection_AsciiString anArg (theArgVec[anArgIter]);
+ anArg.LowerCase();
+ if (toUpdate
+ && anArg == "-noupdate")
+ {
+ toUpdate = Standard_False;
+ }
+ else if (toActivate
+ && aNameString.IsEmpty()
+ && anArg == "none")
+ {
+ TCollection_AsciiString aTitle("3D View - ");
+ aTitle = aTitle + ViewerTest_myViews.Find2(ViewerTest::CurrentView());
+ SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
+ VT_GetWindow().Nullify();
+ ViewerTest::CurrentView (Handle(V3d_View)());
+ ViewerTest::ResetEventManager();
+ theDi << theArgVec[0] << ": all views are inactive\n";
+ toActivate = Standard_False;
+ }
+ else if (toActivate
+ && aNameString.IsEmpty())
+ {
+ aNameString = theArgVec[anArgIter];
+ }
+ else
+ {
+ std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
+ return 1;
+ }
}
- ViewerTest_Names aViewNames(aNameString);
+ if (!toActivate)
+ {
+ return 0;
+ }
+ else if (aNameString.IsEmpty())
+ {
+ std::cout << "Syntax error: wrong number of arguments\n";
+ return 1;
+ }
// Check if this view exists in the viewer with the driver
+ ViewerTest_Names aViewNames (aNameString);
if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
{
- theDi << "Wrong view name\n";
+ theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
return 1;
}
return 0;
}
- ActivateView (aViewNames.GetViewName());
+ ActivateView (aViewNames.GetViewName(), toUpdate);
return 0;
}
return 1;
}
- Standard_Integer aFramesNb = (theArgNb > 1) ? Draw::Atoi(theArgVec[1]) : 100;
- if (aFramesNb <= 0)
+ Standard_Integer aFramesNb = -1;
+ Standard_Real aDuration = -1.0;
+ for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
{
- std::cerr << "Incorrect arguments!\n";
- return 1;
+ TCollection_AsciiString anArg (theArgVec[anArgIter]);
+ anArg.LowerCase();
+ if (aDuration < 0.0
+ && anArgIter + 1 < theArgNb
+ && (anArg == "-duration"
+ || anArg == "-dur"
+ || anArg == "-time"))
+ {
+ aDuration = Draw::Atof (theArgVec[++anArgIter]);
+ }
+ else if (aFramesNb < 0
+ && anArg.IsIntegerValue())
+ {
+ aFramesNb = anArg.IntegerValue();
+ if (aFramesNb <= 0)
+ {
+ std::cerr << "Syntax error at '" << anArg << "'\n";
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Syntax error at '" << anArg << "'\n";
+ return 1;
+ }
+ }
+ if (aFramesNb < 0 && aDuration < 0.0)
+ {
+ aFramesNb = 100;
}
// the time is meaningless for first call
// redraw view in loop to estimate average values
OSD_Timer aTimer;
aTimer.Start();
- for (Standard_Integer anInter = 0; anInter < aFramesNb; ++anInter)
+ Standard_Integer aFrameIter = 1;
+ for (;; ++aFrameIter)
{
aView->Redraw();
+ if ((aFramesNb > 0
+ && aFrameIter >= aFramesNb)
+ || (aDuration > 0.0
+ && aTimer.ElapsedTime() >= aDuration))
+ {
+ break;
+ }
}
aTimer.Stop();
Standard_Real aCpu;
const Standard_Real aTime = aTimer.ElapsedTime();
aTimer.OSD_Chronometer::Show (aCpu);
- const Standard_Real aFpsAver = Standard_Real(aFramesNb) / aTime;
- const Standard_Real aCpuAver = aCpu / Standard_Real(aFramesNb);
+ const Standard_Real aFpsAver = Standard_Real(aFrameIter) / aTime;
+ const Standard_Real aCpuAver = aCpu / Standard_Real(aFrameIter);
// return statistics
theDI << "FPS: " << aFpsAver << "\n"
<< "CPU: " << (1000.0 * aCpuAver) << " msec\n";
// compute additional statistics in ray-tracing mode
- Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
-
+ const Graphic3d_RenderingParams& aParams = aView->RenderingParams();
if (aParams.Method == Graphic3d_RM_RAYTRACING)
{
- Standard_Integer aSizeX;
- Standard_Integer aSizeY;
-
- aView->Window()->Size (aSizeX, aSizeY);
+ Graphic3d_Vec2i aWinSize (0, 0);
+ aView->Window()->Size (aWinSize.x(), aWinSize.y());
// 1 shadow ray and 1 secondary ray pew each bounce
- const Standard_Real aMRays = aSizeX * aSizeY * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
-
+ const Standard_Real aMRays = aWinSize.x() * aWinSize.y() * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
theDI << "MRays/sec (upper bound): " << aMRays << "\n";
}
}
aParams.AdaptiveScreenSampling = toEnable;
}
+ else if (aFlag == "-issatomic")
+ {
+ if (toPrint)
+ {
+ theDI << (aParams.AdaptiveScreenSamplingAtomic ? "on" : "off") << " ";
+ continue;
+ }
+
+ Standard_Boolean toEnable = Standard_True;
+ if (++anArgIter < theArgNb
+ && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
+ {
+ --anArgIter;
+ }
+ aParams.AdaptiveScreenSamplingAtomic = toEnable;
+ }
else if (aFlag == "-issd")
{
if (toPrint)
" the current context is not removed.",
__FILE__,VClose,group);
theCommands.Add("vactivate" ,
- "view_id"
+ "vactivate view_id [-noUpdate]"
" - activates view(viewer window) defined by its view_id",
__FILE__,VActivate,group);
theCommands.Add("vviewlist",
"\n\t\t: Converts the given coordinates to window/view/model space.",
__FILE__, VConvert, group);
theCommands.Add ("vfps",
- "vfps [framesNb=100] : estimate average frame rate for active view",
+ "vfps [framesNb=100] [-duration seconds] : estimate average frame rate for active view",
__FILE__, VFps, group);
theCommands.Add ("vgldebug",
"vgldebug [-sync {0|1}] [-debug {0|1}] [-glslWarn {0|1}]"
@interface Cocoa_WindowController : NSObject <NSWindowDelegate>
@end
-extern void ActivateView (const TCollection_AsciiString& theViewName);
+extern void ActivateView (const TCollection_AsciiString& theViewName,
+ Standard_Boolean theToUpdate = Standard_True);
extern void VT_ProcessExpose();
extern void VT_ProcessConfigure();
extern void VT_ProcessKeyPress (const char* theBuffer);