Files
OCCT/src/OpenGl/OpenGl_FrameStats.cxx
kgv e084dbbc20 0030476: Visualization, Path Tracing - Adaptive Screen Sampling leads to unstable results
OpenGl_View::runPathtrace() has been extended with alternative multi-pass
Adaptive Screen Sampling mode, not relying on atomic floating point operations.
Although atomic operations on floats allows single-pass rendering,
such operations leads to instability in case of different calculation order.
Atomic float operations are also currently supported only by single GPU vendor.

Fixed GLSL compilation on Intel drivers (follow ARB_shader_image_load_store
specs rather than EXT_shader_image_load_store).

Graphic3d_RenderingParams::AdaptiveScreenSamplingAtomic option has been added
to activate 1-pass Adaptive Screen Sampling mode when supported by hardware.

vfps command has been extended with -duration argument allowing to limit command execution time.
vactivate command has been extended with -noUpdate argument.
2019-02-15 17:16:12 +03:00

327 lines
14 KiB
C++

// Copyright (c) 2017 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.
#include <OpenGl_FrameStats.hxx>
#include <OpenGl_GlCore20.hxx>
#include <OpenGl_View.hxx>
#include <OpenGl_Workspace.hxx>
IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameStats, Graphic3d_FrameStats)
namespace
{
//! Return estimated data size.
static Standard_Size estimatedDataSize (const Handle(OpenGl_Resource)& theRes)
{
return !theRes.IsNull() ? theRes->EstimatedDataSize() : 0;
}
}
// =======================================================================
// function : OpenGl_FrameStats
// purpose :
// =======================================================================
OpenGl_FrameStats::OpenGl_FrameStats()
{
//
}
// =======================================================================
// function : ~OpenGl_FrameStats
// purpose :
// =======================================================================
OpenGl_FrameStats::~OpenGl_FrameStats()
{
//
}
// =======================================================================
// function : IsFrameUpdated
// purpose :
// =======================================================================
bool OpenGl_FrameStats::IsFrameUpdated (Handle(OpenGl_FrameStats)& thePrev) const
{
const Graphic3d_FrameStatsData& aFrame = LastDataFrame();
if (thePrev.IsNull())
{
thePrev = new OpenGl_FrameStats();
}
// check just a couple of major counters
else if (myLastFrameIndex == thePrev->myLastFrameIndex
&& Abs (aFrame.FrameRate() - thePrev->myCountersTmp.FrameRate()) <= 0.001
&& Abs (aFrame.FrameRateCpu() - thePrev->myCountersTmp.FrameRateCpu()) <= 0.001
&& aFrame[Graphic3d_FrameStatsCounter_NbLayers] == thePrev->myCountersTmp[Graphic3d_FrameStatsCounter_NbLayers]
&& aFrame[Graphic3d_FrameStatsCounter_NbLayersNotCulled] == thePrev->myCountersTmp[Graphic3d_FrameStatsCounter_NbLayersNotCulled]
&& aFrame[Graphic3d_FrameStatsCounter_NbStructs] == thePrev->myCountersTmp[Graphic3d_FrameStatsCounter_NbStructs]
&& aFrame[Graphic3d_FrameStatsCounter_NbStructsNotCulled] == thePrev->myCountersTmp[Graphic3d_FrameStatsCounter_NbStructsNotCulled])
{
return false;
}
thePrev->myLastFrameIndex = myLastFrameIndex;
thePrev->myCountersTmp = aFrame;
return true;
}
// =======================================================================
// function : updateStatistics
// purpose :
// =======================================================================
void OpenGl_FrameStats::updateStatistics (const Handle(Graphic3d_CView)& theView,
bool theIsImmediateOnly)
{
const OpenGl_View* aView = dynamic_cast<const OpenGl_View*> (theView.get());
if (aView == NULL)
{
myCounters.SetValue (myLastFrameIndex, myCountersTmp);
myCountersTmp.Reset();
return;
}
const Graphic3d_RenderingParams::PerfCounters aBits = theView->RenderingParams().CollectedStats;
const Standard_Boolean toCountMem = (aBits & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0;
const Standard_Boolean toCountTris = (aBits & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
|| (aBits & Graphic3d_RenderingParams::PerfCounters_Points) != 0;
const Standard_Boolean toCountElems = (aBits & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0 || toCountTris || toCountMem;
const Standard_Boolean toCountGroups = (aBits & Graphic3d_RenderingParams::PerfCounters_Groups) != 0 || toCountElems;
const Standard_Boolean toCountStructs = (aBits & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
|| (aBits & Graphic3d_RenderingParams::PerfCounters_Layers) != 0 || toCountGroups;
myCountersTmp[Graphic3d_FrameStatsCounter_NbLayers] = aView->LayerList().Layers().Size();
if (toCountStructs
|| (aBits & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
{
const Standard_Integer aViewId = aView->Identification();
for (OpenGl_SequenceOfLayers::Iterator aLayerIter (aView->LayerList().Layers()); aLayerIter.More(); aLayerIter.Next())
{
const Handle(OpenGl_Layer)& aLayer = aLayerIter.Value();
myCountersTmp[Graphic3d_FrameStatsCounter_NbStructs] += aLayer->NbStructures();
if (theIsImmediateOnly && !aLayer->LayerSettings().IsImmediate())
{
continue;
}
if (!aLayer->IsCulled())
{
++myCountersTmp[Graphic3d_FrameStatsCounter_NbLayersNotCulled];
}
myCountersTmp[Graphic3d_FrameStatsCounter_NbStructsNotCulled] += aLayer->NbStructuresNotCulled();
if (toCountGroups)
{
updateStructures (aViewId, aLayer->CullableStructuresBVH().Structures(), toCountElems, toCountTris, toCountMem);
updateStructures (aViewId, aLayer->CullableTrsfPersStructuresBVH().Structures(), toCountElems, toCountTris, toCountMem);
updateStructures (aViewId, aLayer->NonCullableStructures(), toCountElems, toCountTris, toCountMem);
}
}
}
if (toCountMem)
{
for (OpenGl_Context::OpenGl_ResourcesMap::Iterator aResIter (aView->GlWindow()->GetGlContext()->SharedResources());
aResIter.More(); aResIter.Next())
{
myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesTextures] += aResIter.Value()->EstimatedDataSize();
}
{
Standard_Size& aMemFbos = myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesFbos];
// main FBOs
aMemFbos += estimatedDataSize (aView->myMainSceneFbos[0]);
aMemFbos += estimatedDataSize (aView->myMainSceneFbos[1]);
aMemFbos += estimatedDataSize (aView->myImmediateSceneFbos[0]);
aMemFbos += estimatedDataSize (aView->myImmediateSceneFbos[1]);
// OIT FBOs
aMemFbos += estimatedDataSize (aView->myMainSceneFbosOit[0]);
aMemFbos += estimatedDataSize (aView->myMainSceneFbosOit[1]);
aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[0]);
aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[1]);
// dump FBO
aMemFbos += estimatedDataSize (aView->myFBO);
// RayTracing FBO
aMemFbos += estimatedDataSize (aView->myOpenGlFBO);
aMemFbos += estimatedDataSize (aView->myOpenGlFBO2);
aMemFbos += estimatedDataSize (aView->myRaytraceFBO1[0]);
aMemFbos += estimatedDataSize (aView->myRaytraceFBO1[1]);
aMemFbos += estimatedDataSize (aView->myRaytraceFBO2[0]);
aMemFbos += estimatedDataSize (aView->myRaytraceFBO2[1]);
// also RayTracing
aMemFbos += estimatedDataSize (aView->myRaytraceOutputTexture[0]);
aMemFbos += estimatedDataSize (aView->myRaytraceOutputTexture[1]);
aMemFbos += estimatedDataSize (aView->myRaytraceVisualErrorTexture[0]);
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
Standard_Size& aMemGeom = myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesGeom];
aMemGeom += estimatedDataSize (aView->mySceneNodeInfoTexture);
aMemGeom += estimatedDataSize (aView->mySceneMinPointTexture);
aMemGeom += estimatedDataSize (aView->mySceneMaxPointTexture);
aMemGeom += estimatedDataSize (aView->mySceneTransformTexture);
aMemGeom += estimatedDataSize (aView->myGeometryVertexTexture);
aMemGeom += estimatedDataSize (aView->myGeometryNormalTexture);
aMemGeom += estimatedDataSize (aView->myGeometryTexCrdTexture);
aMemGeom += estimatedDataSize (aView->myGeometryTriangTexture);
aMemGeom += estimatedDataSize (aView->myRaytraceMaterialTexture);
aMemGeom += estimatedDataSize (aView->myRaytraceLightSrcTexture);
}
}
}
// =======================================================================
// function : updateStructures
// purpose :
// =======================================================================
void OpenGl_FrameStats::updateStructures (Standard_Integer theViewId,
const OpenGl_IndexedMapOfStructure& theStructures,
Standard_Boolean theToCountElems,
Standard_Boolean theToCountTris,
Standard_Boolean theToCountMem)
{
for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (theStructures); aStructIter.More(); aStructIter.Next())
{
const OpenGl_Structure* aStruct = aStructIter.Value();
const bool isStructHidden = aStruct->IsCulled()
|| !aStruct->IsVisible (theViewId);
for (; aStruct != NULL; aStruct = aStruct->InstancedStructure())
{
if (isStructHidden)
{
if (theToCountMem)
{
for (OpenGl_Structure::GroupIterator aGroupIter (aStruct->Groups()); aGroupIter.More(); aGroupIter.Next())
{
const OpenGl_Group* aGroup = aGroupIter.Value();
for (const OpenGl_ElementNode* aNodeIter = aGroup->FirstNode(); aNodeIter != NULL; aNodeIter = aNodeIter->next)
{
if (const OpenGl_PrimitiveArray* aPrim = dynamic_cast<const OpenGl_PrimitiveArray*> (aNodeIter->elem))
{
myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
}
}
}
}
continue;
}
myCountersTmp[Graphic3d_FrameStatsCounter_NbGroupsNotCulled] += aStruct->Groups().Size();
if (!theToCountElems)
{
continue;
}
for (OpenGl_Structure::GroupIterator aGroupIter (aStruct->Groups()); aGroupIter.More(); aGroupIter.Next())
{
const OpenGl_Group* aGroup = aGroupIter.Value();
for (const OpenGl_ElementNode* aNodeIter = aGroup->FirstNode(); aNodeIter != NULL; aNodeIter = aNodeIter->next)
{
if (const OpenGl_PrimitiveArray* aPrim = dynamic_cast<const OpenGl_PrimitiveArray*> (aNodeIter->elem))
{
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsNotCulled];
if (theToCountMem)
{
myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
myCountersTmp[Graphic3d_FrameStatsCounter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
}
if (aPrim->IsFillDrawMode())
{
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled];
if (!theToCountTris)
{
continue;
}
const Handle(OpenGl_VertexBuffer)& anAttribs = aPrim->AttributesVbo();
if (anAttribs.IsNull()
|| !anAttribs->IsValid())
{
continue;
}
const Handle(OpenGl_VertexBuffer)& anIndices = aPrim->IndexVbo();
const Standard_Integer aNbIndices = !anIndices.IsNull() ? anIndices->GetElemsNb() : anAttribs->GetElemsNb();
const Standard_Integer aNbBounds = !aPrim->Bounds().IsNull() ? aPrim->Bounds()->NbBounds : 1;
switch (aPrim->DrawMode())
{
case GL_TRIANGLES:
{
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices / 3;
break;
}
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
{
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices - 2 * aNbBounds;
break;
}
case GL_TRIANGLES_ADJACENCY:
{
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices / 6;
break;
}
case GL_TRIANGLE_STRIP_ADJACENCY:
{
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices - 4 * aNbBounds;
break;
}
#if !defined(GL_ES_VERSION_2_0)
case GL_QUADS:
{
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices / 2;
break;
}
case GL_QUAD_STRIP:
{
myCountersTmp[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += (aNbIndices / 2 - aNbBounds) * 2;
break;
}
#endif
}
}
else if (aPrim->DrawMode() == GL_POINTS)
{
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled];
if (theToCountTris)
{
const Handle(OpenGl_VertexBuffer)& anAttribs = aPrim->AttributesVbo();
if (!anAttribs.IsNull()
&& anAttribs->IsValid())
{
const Handle(OpenGl_VertexBuffer)& anIndices = aPrim->IndexVbo();
const Standard_Integer aNbIndices = !anIndices.IsNull() ? anIndices->GetElemsNb() : anAttribs->GetElemsNb();
myCountersTmp[Graphic3d_FrameStatsCounter_NbPointsNotCulled] += aNbIndices;
}
}
}
else
{
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled];
}
}
else if (const OpenGl_Text* aText = dynamic_cast<const OpenGl_Text*> (aNodeIter->elem))
{
(void )aText;
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsNotCulled];
++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled];
}
}
}
}
}
}