0030058: Visualization, Select3D_SensitivePrimitiveArray - the selection is not fast...
[occt.git] / src / OpenGl / OpenGl_FrameStats.cxx
CommitLineData
15669413 1// Copyright (c) 2017 OPEN CASCADE SAS
2//
3// This file is part of Open CASCADE Technology software library.
4//
5// This library is free software; you can redistribute it and/or modify it under
6// the terms of the GNU Lesser General Public License version 2.1 as published
7// by the Free Software Foundation, with special exception defined in the file
8// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9// distribution for complete text of the license and disclaimer of any warranty.
10//
11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
13
14#include <OpenGl_FrameStats.hxx>
15
16#include <OpenGl_GlCore20.hxx>
17#include <OpenGl_View.hxx>
18#include <OpenGl_Workspace.hxx>
19
20IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameStats, Standard_Transient)
21
22namespace
23{
24 //! Format counter.
25 static std::ostream& formatCounter (std::ostream& theStream,
26 Standard_Integer theWidth,
27 const char* thePrefix,
28 Standard_Size theValue,
29 const char* thePostfix = NULL)
30 {
31 if (thePrefix != NULL)
32 {
33 theStream << thePrefix;
34 }
35 theStream << std::setfill(' ') << std::setw (theWidth);
36 if (theValue >= 1000000000)
37 {
38 Standard_Real aValM = Standard_Real(theValue) / 1000000000.0;
39 theStream << std::fixed << std::setprecision (1) << aValM << "G";
40 }
41 else if (theValue >= 1000000)
42 {
43 Standard_Real aValM = Standard_Real(theValue) / 1000000.0;
44 theStream << std::fixed << std::setprecision (1) << aValM << "M";
45 }
46 else if (theValue >= 1000)
47 {
48 Standard_Real aValK = Standard_Real(theValue) / 1000.0;
49 theStream << std::fixed << std::setprecision (1) << aValK << "k";
50 }
51 else
52 {
53 theStream << theValue;
54 }
55 if (thePostfix != NULL)
56 {
57 theStream << thePostfix;
58 }
59 return theStream;
60 }
61
62 //! Format memory counter.
63 static std::ostream& formatBytes (std::ostream& theStream,
64 Standard_Integer theWidth,
65 const char* thePrefix,
66 Standard_Size theValue,
67 const char* thePostfix = NULL)
68 {
69 if (thePrefix != NULL)
70 {
71 theStream << thePrefix;
72 }
73 theStream << std::setfill(' ') << std::setw (theWidth);
74 if (theValue >= 1024 * 1024 * 1024)
75 {
76 Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0 * 1024.0);
77 theStream << std::fixed << std::setprecision (1) << aValM << " GiB";
78 }
79 else if (theValue >= 1024 * 1024)
80 {
81 Standard_Real aValM = Standard_Real(theValue) / (1024.0 * 1024.0);
82 theStream << std::fixed << std::setprecision (1) << aValM << " MiB";
83 }
84 else if (theValue >= 1024)
85 {
86 Standard_Real aValK = Standard_Real(theValue) / 1024.0;
87 theStream << std::fixed << std::setprecision (1) << aValK << " KiB";
88 }
89 else
90 {
91 theStream << theValue;
92 }
93 if (thePostfix != NULL)
94 {
95 theStream << thePostfix;
96 }
97 return theStream;
98 }
99
100 //! Return estimated data size.
101 static Standard_Size estimatedDataSize (const Handle(OpenGl_Resource)& theRes)
102 {
103 return !theRes.IsNull() ? theRes->EstimatedDataSize() : 0;
104 }
105}
106
107// =======================================================================
108// function : OpenGl_FrameStats
109// purpose :
110// =======================================================================
111OpenGl_FrameStats::OpenGl_FrameStats()
112: myFpsTimer (Standard_True),
113 myFrameStartTime (0.0),
114 myFrameDuration (0.0),
115 myFps (-1.0),
116 myFpsCpu (-1.0),
117 myUpdateInterval (1.0),
118 myFpsFrameCount (0),
119 myIsLongLineFormat (Standard_False)
120{
121 memset (myCounters, 0, sizeof(myCounters));
122 memset (myCountersTmp, 0, sizeof(myCountersTmp));
123}
124
125// =======================================================================
126// function : ~OpenGl_FrameStats
127// purpose :
128// =======================================================================
129OpenGl_FrameStats::~OpenGl_FrameStats()
130{
131 //
132}
133
134// =======================================================================
135// function : FormatStats
136// purpose :
137// =======================================================================
138TCollection_AsciiString OpenGl_FrameStats::FormatStats (Graphic3d_RenderingParams::PerfCounters theFlags) const
139{
140 const Standard_Integer aValWidth = 5;
141 std::stringstream aBuf;
142 const Standard_Boolean isCompact = theFlags == Graphic3d_RenderingParams::PerfCounters_FrameRate; // only FPS is displayed
143 if (myIsLongLineFormat
144 && (theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0
145 && (theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
146 {
147 aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 9) << std::fixed << std::setprecision (1) << myFps
148 << " [CPU: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : 10) << std::fixed << std::setprecision (1) << myFpsCpu << "]\n";
149 }
150 else
151 {
152 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
153 {
154 aBuf << "FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << myFps << "\n";
155 }
156 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
157 {
158 aBuf << "CPU FPS: " << std::setfill(' ') << std::setw (isCompact ? aValWidth : aValWidth + 3) << std::fixed << std::setprecision (1) << myFpsCpu << "\n";
159 }
160 }
161 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
162 {
163 if (myIsLongLineFormat)
164 {
165 formatCounter (aBuf, aValWidth, "Layers: ", myCounters[Counter_NbLayers]);
166 if (HasCulledLayers())
167 {
168 formatCounter (aBuf, aValWidth, " [rendered: ", myCounters[Counter_NbLayersNotCulled], "]");
169 }
170 aBuf << "\n";
171 }
172 else
173 {
174 formatCounter (aBuf, aValWidth + 3, "Layers: ", myCounters[Counter_NbLayers], "\n");
175 }
176 }
177 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
178 {
179 if (myIsLongLineFormat)
180 {
181 formatCounter (aBuf, aValWidth, "Structs: ", myCounters[Counter_NbStructs]);
182 if (HasCulledStructs())
183 {
184 formatCounter (aBuf, aValWidth, " [rendered: ", myCounters[Counter_NbStructsNotCulled], "]");
185 }
186 aBuf << "\n";
187 }
188 else
189 {
190 formatCounter (aBuf, aValWidth + 3, "Structs: ", myCounters[Counter_NbStructs], "\n");
191 }
192 }
193 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0
194 || (theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0
195 || (theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
196 || (theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0
197 || (!myIsLongLineFormat
198 && ((theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
199 || (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)))
200 {
201 aBuf << "Rendered\n";
202 }
203 if (!myIsLongLineFormat
204 && (theFlags & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
205 {
206 formatCounter (aBuf, aValWidth, " Layers: ", myCounters[Counter_NbLayersNotCulled], "\n");
207 }
208 if (!myIsLongLineFormat
209 && (theFlags & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
210 {
211 formatCounter (aBuf, aValWidth, " Structs: ", myCounters[Counter_NbStructsNotCulled], "\n");
212 }
213 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
214 {
215 formatCounter (aBuf, aValWidth, " Groups: ", myCounters[Counter_NbGroupsNotCulled], "\n");
216 }
217 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
218 {
219 formatCounter (aBuf, aValWidth, " Arrays: ", myCounters[Counter_NbElemsNotCulled], "\n");
220 formatCounter (aBuf, aValWidth, " [fill]: ", myCounters[Counter_NbElemsFillNotCulled], "\n");
221 formatCounter (aBuf, aValWidth, " [line]: ", myCounters[Counter_NbElemsLineNotCulled], "\n");
222 formatCounter (aBuf, aValWidth, " [point]: ", myCounters[Counter_NbElemsPointNotCulled], "\n");
223 formatCounter (aBuf, aValWidth, " [text]: ", myCounters[Counter_NbElemsTextNotCulled], "\n");
224 }
225 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
226 {
227 formatCounter (aBuf, aValWidth, " Triangles: ", myCounters[Counter_NbTrianglesNotCulled], "\n");
228 }
229 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
230 {
231 formatCounter (aBuf, aValWidth, " Points: ", myCounters[Counter_NbPointsNotCulled], "\n");
232 }
233 if ((theFlags & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
234 {
235 aBuf << "GPU Memory\n";
236 formatBytes (aBuf, aValWidth, " Geometry: ", myCounters[Counter_EstimatedBytesGeom], "\n");
237 formatBytes (aBuf, aValWidth, " Textures: ", myCounters[Counter_EstimatedBytesTextures], "\n");
238 formatBytes (aBuf, aValWidth, " Frames: ", myCounters[Counter_EstimatedBytesFbos], "\n");
239 }
240 return TCollection_AsciiString (aBuf.str().c_str());
241}
242
243// =======================================================================
244// function : FrameStart
245// purpose :
246// =======================================================================
247void OpenGl_FrameStats::FrameStart (const Handle(OpenGl_Workspace)& )
248{
249 memset (myCountersTmp, 0, sizeof(myCountersTmp));
250 myFrameStartTime = myFpsTimer.ElapsedTime();
251 if (!myFpsTimer.IsStarted())
252 {
253 myFpsTimer.Reset();
254 myFpsTimer.Start();
255 myFpsFrameCount = 0;
256 }
257}
258
259// =======================================================================
260// function : FrameEnd
261// purpose :
262// =======================================================================
263void OpenGl_FrameStats::FrameEnd (const Handle(OpenGl_Workspace)& theWorkspace)
264{
265 const Graphic3d_RenderingParams::PerfCounters aBits = !theWorkspace.IsNull()
266 ? theWorkspace->View()->RenderingParams().CollectedStats
267 : Graphic3d_RenderingParams::PerfCounters_NONE;
268 const double aTime = myFpsTimer.ElapsedTime();
269 myFrameDuration = aTime - myFrameStartTime;
270 ++myFpsFrameCount;
271 if (!theWorkspace.IsNull())
272 {
273 myUpdateInterval = theWorkspace->View()->RenderingParams().StatsUpdateInterval;
274 }
275
276 if (aTime < myUpdateInterval)
277 {
278 return;
279 }
280
281 if (aTime > gp::Resolution())
282 {
283 // update FPS
284 myFpsTimer.Stop();
285 const double aCpuSec = myFpsTimer.UserTimeCPU();
286 myFps = double(myFpsFrameCount) / aTime;
287 myFpsCpu = aCpuSec > gp::Resolution()
288 ? double(myFpsFrameCount) / aCpuSec
289 : -1.0;
290 myFpsTimer.Reset();
291 myFpsTimer.Start();
292 myFpsFrameCount = 0;
293 }
294
295 // update structure counters
296 if (theWorkspace.IsNull())
297 {
298 memcpy (myCounters, myCountersTmp, sizeof(myCounters));
299 return;
300 }
301
302 const Standard_Boolean toCountMem = (aBits & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0;
303 const Standard_Boolean toCountTris = (aBits & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0
304 || (aBits & Graphic3d_RenderingParams::PerfCounters_Points) != 0;
305 const Standard_Boolean toCountElems = (aBits & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0 || toCountTris || toCountMem;
306 const Standard_Boolean toCountGroups = (aBits & Graphic3d_RenderingParams::PerfCounters_Groups) != 0 || toCountElems;
5dc0517d 307 const Standard_Boolean toCountStructs = (aBits & Graphic3d_RenderingParams::PerfCounters_Structures) != 0
308 || (aBits & Graphic3d_RenderingParams::PerfCounters_Layers) != 0 || toCountGroups;
309
310 myCountersTmp[Counter_NbLayers] = theWorkspace->View()->LayerList().Layers().Size();
311 if (toCountStructs
312 || (aBits & Graphic3d_RenderingParams::PerfCounters_Layers) != 0)
15669413 313 {
5dc0517d 314 const Standard_Integer aViewId = theWorkspace->View()->Identification();
15669413 315 for (OpenGl_SequenceOfLayers::Iterator aLayerIter (theWorkspace->View()->LayerList().Layers()); aLayerIter.More(); aLayerIter.Next())
316 {
317 const Handle(OpenGl_Layer)& aLayer = aLayerIter.Value();
318 if (!aLayer->IsCulled())
319 {
320 ++myCountersTmp[Counter_NbLayersNotCulled];
321 }
322 myCountersTmp[Counter_NbStructs] += aLayer->NbStructures();
323 myCountersTmp[Counter_NbStructsNotCulled] += aLayer->NbStructuresNotCulled();
324 if (toCountGroups)
325 {
5dc0517d 326 updateStructures (aViewId, aLayer->CullableStructuresBVH().Structures(), toCountElems, toCountTris, toCountMem);
327 updateStructures (aViewId, aLayer->CullableTrsfPersStructuresBVH().Structures(), toCountElems, toCountTris, toCountMem);
328 updateStructures (aViewId, aLayer->NonCullableStructures(), toCountElems, toCountTris, toCountMem);
15669413 329 }
330 }
331 }
332 if (toCountMem
333 && !theWorkspace.IsNull())
334 {
335 for (OpenGl_Context::OpenGl_ResourcesMap::Iterator aResIter (theWorkspace->GetGlContext()->SharedResources());
336 aResIter.More(); aResIter.Next())
337 {
338 myCountersTmp[Counter_EstimatedBytesTextures] += aResIter.Value()->EstimatedDataSize();
339 }
340
341 const OpenGl_View* aView = theWorkspace->View();
342 {
343 Standard_Size& aMemFbos = myCountersTmp[Counter_EstimatedBytesFbos];
344 // main FBOs
345 aMemFbos += estimatedDataSize (aView->myMainSceneFbos[0]);
346 aMemFbos += estimatedDataSize (aView->myMainSceneFbos[1]);
347 aMemFbos += estimatedDataSize (aView->myImmediateSceneFbos[0]);
348 aMemFbos += estimatedDataSize (aView->myImmediateSceneFbos[1]);
349 // OIT FBOs
350 aMemFbos += estimatedDataSize (aView->myMainSceneFbosOit[0]);
351 aMemFbos += estimatedDataSize (aView->myMainSceneFbosOit[1]);
352 aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[0]);
353 aMemFbos += estimatedDataSize (aView->myImmediateSceneFbosOit[1]);
354 // dump FBO
355 aMemFbos += estimatedDataSize (aView->myFBO);
356 // RayTracing FBO
357 aMemFbos += estimatedDataSize (aView->myOpenGlFBO);
358 aMemFbos += estimatedDataSize (aView->myOpenGlFBO2);
359 aMemFbos += estimatedDataSize (aView->myRaytraceFBO1[0]);
360 aMemFbos += estimatedDataSize (aView->myRaytraceFBO1[1]);
361 aMemFbos += estimatedDataSize (aView->myRaytraceFBO2[0]);
362 aMemFbos += estimatedDataSize (aView->myRaytraceFBO2[1]);
363 // also RayTracing
364 aMemFbos += estimatedDataSize (aView->myRaytraceOutputTexture[0]);
365 aMemFbos += estimatedDataSize (aView->myRaytraceOutputTexture[1]);
366 aMemFbos += estimatedDataSize (aView->myRaytraceVisualErrorTexture[0]);
367 aMemFbos += estimatedDataSize (aView->myRaytraceVisualErrorTexture[1]);
368 aMemFbos += estimatedDataSize (aView->myRaytraceTileOffsetsTexture[0]);
369 aMemFbos += estimatedDataSize (aView->myRaytraceTileOffsetsTexture[1]);
370 }
371 {
372 // Ray Tracing geometry
373 Standard_Size& aMemGeom = myCountersTmp[Counter_EstimatedBytesGeom];
374 aMemGeom += estimatedDataSize (aView->mySceneNodeInfoTexture);
375 aMemGeom += estimatedDataSize (aView->mySceneMinPointTexture);
376 aMemGeom += estimatedDataSize (aView->mySceneMaxPointTexture);
377 aMemGeom += estimatedDataSize (aView->mySceneTransformTexture);
378 aMemGeom += estimatedDataSize (aView->myGeometryVertexTexture);
379 aMemGeom += estimatedDataSize (aView->myGeometryNormalTexture);
380 aMemGeom += estimatedDataSize (aView->myGeometryTexCrdTexture);
381 aMemGeom += estimatedDataSize (aView->myGeometryTriangTexture);
382 aMemGeom += estimatedDataSize (aView->myRaytraceMaterialTexture);
383 aMemGeom += estimatedDataSize (aView->myRaytraceLightSrcTexture);
384 }
385 }
386 memcpy (myCounters, myCountersTmp, sizeof(myCounters));
387}
388
389// =======================================================================
390// function : updateStructures
391// purpose :
392// =======================================================================
5dc0517d 393void OpenGl_FrameStats::updateStructures (Standard_Integer theViewId,
394 const OpenGl_IndexedMapOfStructure& theStructures,
15669413 395 Standard_Boolean theToCountElems,
396 Standard_Boolean theToCountTris,
397 Standard_Boolean theToCountMem)
398{
399 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (theStructures); aStructIter.More(); aStructIter.Next())
400 {
401 const OpenGl_Structure* aStruct = aStructIter.Value();
5dc0517d 402 if (aStruct->IsCulled()
403 || !aStruct->IsVisible (theViewId))
15669413 404 {
405 if (theToCountMem)
406 {
407 for (OpenGl_Structure::GroupIterator aGroupIter (aStruct->Groups()); aGroupIter.More(); aGroupIter.Next())
408 {
409 const OpenGl_Group* aGroup = aGroupIter.Value();
410 for (const OpenGl_ElementNode* aNodeIter = aGroup->FirstNode(); aNodeIter != NULL; aNodeIter = aNodeIter->next)
411 {
412 if (const OpenGl_PrimitiveArray* aPrim = dynamic_cast<const OpenGl_PrimitiveArray*> (aNodeIter->elem))
413 {
414 myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
415 myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
416 }
417 }
418 }
419 }
420 continue;
421 }
422
423 myCountersTmp[Counter_NbGroupsNotCulled] += aStruct->Groups().Size();
424 if (!theToCountElems)
425 {
426 continue;
427 }
428
429 for (OpenGl_Structure::GroupIterator aGroupIter (aStruct->Groups()); aGroupIter.More(); aGroupIter.Next())
430 {
431 const OpenGl_Group* aGroup = aGroupIter.Value();
432 for (const OpenGl_ElementNode* aNodeIter = aGroup->FirstNode(); aNodeIter != NULL; aNodeIter = aNodeIter->next)
433 {
434 if (const OpenGl_PrimitiveArray* aPrim = dynamic_cast<const OpenGl_PrimitiveArray*> (aNodeIter->elem))
435 {
436 ++myCountersTmp[Counter_NbElemsNotCulled];
437 if (theToCountMem)
438 {
439 myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->AttributesVbo());
440 myCountersTmp[Counter_EstimatedBytesGeom] += estimatedDataSize (aPrim->IndexVbo());
441 }
442
443 if (aPrim->IsFillDrawMode())
444 {
445 ++myCountersTmp[Counter_NbElemsFillNotCulled];
446 if (!theToCountTris)
447 {
448 continue;
449 }
450
451 const Handle(OpenGl_VertexBuffer)& anAttribs = aPrim->AttributesVbo();
452 if (anAttribs.IsNull()
453 || !anAttribs->IsValid())
454 {
455 continue;
456 }
457
458 const Handle(OpenGl_VertexBuffer)& anIndices = aPrim->IndexVbo();
459 const Standard_Integer aNbIndices = !anIndices.IsNull() ? anIndices->GetElemsNb() : anAttribs->GetElemsNb();
460 const Standard_Integer aNbBounds = !aPrim->Bounds().IsNull() ? aPrim->Bounds()->NbBounds : 1;
461 switch (aPrim->DrawMode())
462 {
463 case GL_TRIANGLES:
464 {
465 myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 3;
466 break;
467 }
468 case GL_TRIANGLE_STRIP:
469 case GL_TRIANGLE_FAN:
470 {
471 myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices - 2 * aNbBounds;
472 break;
473 }
474 case GL_TRIANGLES_ADJACENCY:
475 {
476 myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 6;
477 break;
478 }
479 case GL_TRIANGLE_STRIP_ADJACENCY:
480 {
481 myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices - 4 * aNbBounds;
482 break;
483 }
484 #if !defined(GL_ES_VERSION_2_0)
485 case GL_QUADS:
486 {
487 myCountersTmp[Counter_NbTrianglesNotCulled] += aNbIndices / 2;
488 break;
489 }
490 case GL_QUAD_STRIP:
491 {
492 myCountersTmp[Counter_NbTrianglesNotCulled] += (aNbIndices / 2 - aNbBounds) * 2;
493 break;
494 }
495 #endif
496 }
497 }
498 else if (aPrim->DrawMode() == GL_POINTS)
499 {
500 ++myCountersTmp[Counter_NbElemsPointNotCulled];
501 if (theToCountTris)
502 {
503 const Handle(OpenGl_VertexBuffer)& anAttribs = aPrim->AttributesVbo();
504 if (!anAttribs.IsNull()
505 && anAttribs->IsValid())
506 {
507 const Handle(OpenGl_VertexBuffer)& anIndices = aPrim->IndexVbo();
508 const Standard_Integer aNbIndices = !anIndices.IsNull() ? anIndices->GetElemsNb() : anAttribs->GetElemsNb();
509 myCountersTmp[Counter_NbPointsNotCulled] += aNbIndices;
510 }
511 }
512 }
513 else
514 {
515 ++myCountersTmp[Counter_NbElemsLineNotCulled];
516 }
517 }
518 else if (const OpenGl_Text* aText = dynamic_cast<const OpenGl_Text*> (aNodeIter->elem))
519 {
520 (void )aText;
521 ++myCountersTmp[Counter_NbElemsNotCulled];
522 ++myCountersTmp[Counter_NbElemsTextNotCulled];
523 }
524 }
525 }
526 }
527}