// 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 #include #include #include 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 (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]); } { // 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 (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 (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 (aNodeIter->elem)) { (void )aText; ++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsNotCulled]; ++myCountersTmp[Graphic3d_FrameStatsCounter_NbElemsTextNotCulled]; } } } } } }