0032121: Draw Harness, ViewerTest - implement -reset option for vlight command
[occt.git] / src / OpenGl / OpenGl_FrameStatsPrs.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_FrameStatsPrs.hxx>
15
16#include <OpenGl_View.hxx>
1220d98e 17#include <OpenGl_IndexBuffer.hxx>
18#include <OpenGl_VertexBuffer.hxx>
15669413 19#include <OpenGl_ShaderManager.hxx>
20#include <OpenGl_Workspace.hxx>
21
5e30547b 22#include <Graphic3d_ArrayOfTriangles.hxx>
23
24namespace
25{
26 //! Auxiliary structure defining vertex with two attributes.
27 struct OpenGl_Vec3Vec4ub
28 {
29 Graphic3d_Vec3 Pos;
30 Graphic3d_Vec4ub Color;
31 };
32
33 //! Auxiliary function formatting rendering time in " 10 ms (100 FPS)" format.
34 static TCollection_AsciiString formatTimeMs (Standard_Real theSeconds)
35 {
36 const Standard_Real aFpsVal = theSeconds != 0.0 ? 1.0 / theSeconds : 0.0;
37 char aFps[50];
38 Sprintf (aFps, "%.1f", aFpsVal);
39 return TCollection_AsciiString() + Standard_Integer(theSeconds * 1000.0) + " ms (" + aFps + " FPS)";
40 }
41}
42
15669413 43// =======================================================================
44// function : OpenGl_FrameStatsPrs
45// purpose :
46// =======================================================================
47OpenGl_FrameStatsPrs::OpenGl_FrameStatsPrs()
5e30547b 48: myStatsPrev (new OpenGl_FrameStats()),
49 myCountersTrsfPers (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i (20, 20))),
50 myChartTrsfPers (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_RIGHT_UPPER, Graphic3d_Vec2i (20, 20))),
51 myChartVertices (new OpenGl_VertexBuffer()),
52 myChartIndices (new OpenGl_IndexBuffer()),
53 myChartLines (new OpenGl_VertexBuffer())
15669413 54{
5e30547b 55 //
15669413 56}
57
58// =======================================================================
59// function : ~OpenGl_FrameStatsPrs
60// purpose :
61// =======================================================================
62OpenGl_FrameStatsPrs::~OpenGl_FrameStatsPrs()
63{
64 //
65}
66
67// =======================================================================
68// function : Release
69// purpose :
70// =======================================================================
71void OpenGl_FrameStatsPrs::Release (OpenGl_Context* theCtx)
72{
5e30547b 73 myCountersText.Release (theCtx);
74 myChartLabels[0].Release (theCtx);
75 myChartLabels[1].Release (theCtx);
76 myChartLabels[2].Release (theCtx);
77 myChartVertices->Release (theCtx);
78 myChartIndices->Release (theCtx);
79 myChartLines->Release (theCtx);
15669413 80}
81
82// =======================================================================
83// function : Update
84// purpose :
85// =======================================================================
86void OpenGl_FrameStatsPrs::Update (const Handle(OpenGl_Workspace)& theWorkspace)
87{
88 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
89 const Handle(OpenGl_FrameStats)& aStats = aCtx->FrameStats();
90 const Graphic3d_RenderingParams& aRendParams = theWorkspace->View()->RenderingParams();
5e30547b 91 myCountersTrsfPers = theWorkspace->View()->RenderingParams().StatsPosition;
92 myChartTrsfPers = theWorkspace->View()->RenderingParams().ChartPosition;
15669413 93 myTextAspect.SetAspect (aRendParams.StatsTextAspect);
94
95 // adjust text alignment depending on corner
8ed07085 96 Graphic3d_Text aParams ((Standard_ShortReal)aRendParams.StatsTextHeight);
97 aParams.SetHorizontalAlignment (Graphic3d_HTA_CENTER);
98 aParams.SetVerticalAlignment (Graphic3d_VTA_CENTER);
5e30547b 99 if (!myCountersTrsfPers.IsNull() && (myCountersTrsfPers->Corner2d() & Aspect_TOTP_LEFT) != 0)
15669413 100 {
8ed07085 101 aParams.SetHorizontalAlignment (Graphic3d_HTA_LEFT);
15669413 102 }
5e30547b 103 else if (!myCountersTrsfPers.IsNull() && (myCountersTrsfPers->Corner2d() & Aspect_TOTP_RIGHT) != 0)
15669413 104 {
8ed07085 105 aParams.SetHorizontalAlignment (Graphic3d_HTA_RIGHT);
15669413 106 }
5e30547b 107 if (!myCountersTrsfPers.IsNull() && (myCountersTrsfPers->Corner2d() & Aspect_TOTP_TOP) != 0)
15669413 108 {
8ed07085 109 aParams.SetVerticalAlignment (Graphic3d_VTA_TOP);
15669413 110 }
5e30547b 111 else if (!myCountersTrsfPers.IsNull() && (myCountersTrsfPers->Corner2d() & Aspect_TOTP_BOTTOM) != 0)
15669413 112 {
8ed07085 113 aParams.SetVerticalAlignment (Graphic3d_VTA_BOTTOM);
15669413 114 }
8ed07085 115 if (aParams.Height() != myCountersText.Text()->Height()
116 || aParams.HorizontalAlignment() != myCountersText.Text()->HorizontalAlignment()
117 || aParams.VerticalAlignment() != myCountersText.Text()->VerticalAlignment())
15669413 118 {
5e30547b 119 myCountersText.Release (aCtx.operator->());
15669413 120 }
121
5e30547b 122 if (!aStats->IsFrameUpdated (myStatsPrev)
8ed07085 123 && !myCountersText.Text()->Text().IsEmpty())
15669413 124 {
125 return;
126 }
127
8ed07085 128 Handle(Graphic3d_Text) aText = myCountersText.Text();
129 aText->SetText (aStats->FormatStats (aRendParams.CollectedStats).ToCString());
130 aText->SetHeight (aParams.Height());
131 aText->SetPosition (gp_Pnt());
132 aText->SetHorizontalAlignment (aParams.HorizontalAlignment());
133 aText->SetVerticalAlignment (aParams.VerticalAlignment());
134 myCountersText.Reset (aCtx);
5e30547b 135
136 updateChart (theWorkspace);
137}
138
139// =======================================================================
140// function : updateChart
141// purpose :
142// =======================================================================
143void OpenGl_FrameStatsPrs::updateChart (const Handle(OpenGl_Workspace)& theWorkspace)
144{
145 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
146 const Handle(OpenGl_FrameStats)& aStats = aCtx->FrameStats();
147 const Graphic3d_RenderingParams& aRendParams = theWorkspace->View()->RenderingParams();
148
149 const Standard_Integer aNbBins = aStats->DataFrames().Size();
150 if (aNbBins <= 1)
151 {
dc2749cf 152 myChartIndices ->Release (aCtx.get());
153 myChartVertices->Release (aCtx.get());
154 myChartLines ->Release (aCtx.get());
5e30547b 155 return;
156 }
157
158 Standard_Real aMaxDuration = aRendParams.StatsMaxChartTime;
159 if (aMaxDuration <= 0.0f)
160 {
161 for (Standard_Integer aFrameIter = aStats->DataFrames().Lower(); aFrameIter <= aStats->DataFrames().Upper(); ++aFrameIter)
162 {
163 const Graphic3d_FrameStatsData& aFrame = aStats->DataFrames().Value (aFrameIter);
164 aMaxDuration = Max (aMaxDuration, aFrame.TimerValue (Graphic3d_FrameStatsTimer_ElapsedFrame));
165 }
166 aMaxDuration = Ceiling (aMaxDuration * 1000.0 * 0.1) * 0.001 * 10.0; // round number
167 aMaxDuration = Max (Min (aMaxDuration, 0.1), 0.005); // limit by 100 ms (10 FPS) and 5 ms (200 FPS)
168 }
169
170 const Standard_Integer aNbTimers = 4;
171 const Graphic3d_FrameStatsTimer aTimers[4] =
172 {
173 Graphic3d_FrameStatsTimer_CpuDynamics,
174 Graphic3d_FrameStatsTimer_CpuPicking,
175 Graphic3d_FrameStatsTimer_CpuCulling,
176 Graphic3d_FrameStatsTimer_ElapsedFrame,
177 };
178 const Graphic3d_Vec4ub aColors[4] =
179 {
180 Graphic3d_Vec4ub (255, 0, 0, 127),
181 Graphic3d_Vec4ub (255, 127, 39, 127),
182 Graphic3d_Vec4ub (255, 0, 0, 127),
183 Graphic3d_Vec4ub (0, 255, 0, 127),
184 };
185
186 const Standard_Integer aNbVerts = aNbBins * 4 * aNbTimers;
187 const Standard_Integer aNbIndexes = aNbBins * 2 * 3 * aNbTimers;
188 bool toFillEdges = false;
189 if (myChartArray.IsNull()
190 || myChartArray->VertexNumber() != aNbVerts
191 || myChartArray->EdgeNumber() != aNbIndexes)
192 {
193 myChartArray = new Graphic3d_ArrayOfTriangles (aNbVerts, aNbIndexes, false, true);
194 toFillEdges = true;
195 }
196
197 const Graphic3d_Vec2i aViewSize (aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);
198 Graphic3d_Vec2i aCharSize (aRendParams.ChartSize);
199 if (aCharSize.x() <= 0)
200 {
201 aCharSize.x() = aViewSize.x() / 2;
202 }
203 if (aCharSize.y() <= 0)
204 {
205 aCharSize.y() = Standard_Integer(0.15 * aViewSize.y());
206 }
207
208 const Graphic3d_Vec2d aBinSize (Standard_Real(aCharSize.x()) / Standard_Real(aNbBins), 0.15 * aViewSize.y());
209 Graphic3d_Vec2i anOffset;
210 if (!myChartTrsfPers.IsNull()
211 && myChartTrsfPers->IsTrihedronOr2d())
212 {
213 if ((myChartTrsfPers->Corner2d() & Aspect_TOTP_LEFT) != 0)
214 {
215 anOffset.x() = 0;
216 }
217 else if ((myChartTrsfPers->Corner2d() & Aspect_TOTP_RIGHT) != 0)
218 {
219 anOffset.x() = -aCharSize.x();
220 }
221 else
222 {
223 anOffset.x() = -aCharSize.x() / 2;
224 }
225
226 if ((myChartTrsfPers->Corner2d() & Aspect_TOTP_BOTTOM) != 0)
227 {
228 anOffset.y() = aCharSize.y();
229 }
230 else if ((myChartTrsfPers->Corner2d() & Aspect_TOTP_TOP) != 0)
231 {
232 anOffset.y() = 0;
233 }
234 else
235 {
236 anOffset.y() = aCharSize.y() / 2;
237 }
238 }
239
240 Standard_Integer aVertLast = 1;
241 const bool isTopDown = false;
242 for (Standard_Integer aFrameIter = 0; aFrameIter < aNbBins; ++aFrameIter)
243 {
244 Standard_Integer aFrameIndex = aStats->DataFrames().Lower() + aStats->LastDataFrameIndex() + 1 + aFrameIter;
245 if (aFrameIndex > aStats->DataFrames().Upper())
246 {
247 aFrameIndex -= aNbBins;
248 }
249
250 const Graphic3d_FrameStatsData& aFrame = aStats->DataFrames().Value (aFrameIndex);
251 Standard_Real aTimeElapsed = 0.0;
252 Standard_Real aCurrY = 0.0;
253 for (Standard_Integer aTimerIter = 0; aTimerIter < aNbTimers; ++aTimerIter)
254 {
255 if (aTimers[aTimerIter] == Graphic3d_FrameStatsTimer_ElapsedFrame)
256 {
257 aTimeElapsed = aFrame.TimerValue (aTimers[aTimerIter]);
258 }
259 else
260 {
261 aTimeElapsed += aFrame.TimerValue (aTimers[aTimerIter]);
262 }
263
264 const Standard_Real aBinX1 = anOffset.x() + Standard_Real(aFrameIter) * aBinSize.x();
265 const Standard_Real aBinX2 = aBinX1 + aBinSize.x();
266 const Standard_Real aCurrSizeY = Min (aTimeElapsed / aMaxDuration, 1.2) * aBinSize.y();
267 const Standard_Real aBinY1 = isTopDown ? (anOffset.y() - aCurrY) : (anOffset.y() - aBinSize.y() + aCurrY);
268 const Standard_Real aBinY2 = isTopDown ? (anOffset.y() - aCurrSizeY) : (anOffset.y() - aBinSize.y() + aCurrSizeY);
269 myChartArray->SetVertice (aVertLast + 0, gp_Pnt (aBinX1, aBinY2, 0.0));
270 myChartArray->SetVertice (aVertLast + 1, gp_Pnt (aBinX1, aBinY1, 0.0));
271 myChartArray->SetVertice (aVertLast + 2, gp_Pnt (aBinX2, aBinY1, 0.0));
272 myChartArray->SetVertice (aVertLast + 3, gp_Pnt (aBinX2, aBinY2, 0.0));
273
274 if (toFillEdges)
275 {
276 const Graphic3d_Vec4ub& aTimerColor = aColors[aTimerIter];
277 myChartArray->SetVertexColor (aVertLast + 0, aTimerColor);
278 myChartArray->SetVertexColor (aVertLast + 1, aTimerColor);
279 myChartArray->SetVertexColor (aVertLast + 2, aTimerColor);
280 myChartArray->SetVertexColor (aVertLast + 3, aTimerColor);
281 myChartArray->AddEdges (aVertLast + 0, aVertLast + 1, aVertLast + 3);
282 myChartArray->AddEdges (aVertLast + 1, aVertLast + 2, aVertLast + 3);
283 }
284 aVertLast += 4;
285
286 if (aTimers[aTimerIter] == Graphic3d_FrameStatsTimer_ElapsedFrame)
287 {
288 aTimeElapsed = 0.0;
289 aCurrY = 0.0;
290 }
291 else
292 {
293 aCurrY = aCurrSizeY;
294 }
295 }
296 }
297
298 myChartVertices->init (aCtx,
299 myChartArray->Attributes()->Stride,
300 myChartArray->Attributes()->NbElements,
301 myChartArray->Attributes()->Data(),
302 GL_UNSIGNED_BYTE,
303 myChartArray->Attributes()->Stride);
304 if (myChartArray->Indices()->Stride == 2)
305 {
306 myChartIndices ->Init (aCtx,
307 1,
308 myChartArray->Indices()->NbElements,
309 (const GLushort* )myChartArray->Indices()->Data());
310 }
311 else if (myChartArray->Indices()->Stride == 4)
312 {
313 myChartIndices ->Init (aCtx,
314 1,
315 myChartArray->Indices()->NbElements,
316 (const GLuint* )myChartArray->Indices()->Data());
317 }
15669413 318
5e30547b 319 {
320 const Graphic3d_Vec4ub aWhite (255, 255, 255, 255);
321 const OpenGl_Vec3Vec4ub aLines[4] =
322 {
323 { Graphic3d_Vec3((float )anOffset.x(), (float )anOffset.y(), 0.0f), aWhite },
324 { Graphic3d_Vec3(float(anOffset.x() + aCharSize.x()), (float )anOffset.y(), 0.0f), aWhite },
325 { Graphic3d_Vec3((float )anOffset.x(), float(anOffset.y() - aBinSize.y()), 0.0f), aWhite },
326 { Graphic3d_Vec3(float(anOffset.x() + aCharSize.x()), float(anOffset.y() - aBinSize.y()),+ 0.0f), aWhite },
327 };
328 myChartLines->init (aCtx, sizeof(OpenGl_Vec3Vec4ub), 4, aLines, GL_UNSIGNED_BYTE, sizeof(OpenGl_Vec3Vec4ub));
329 }
330
331 {
8ed07085 332 Graphic3d_Text aParams ((Standard_ShortReal)aRendParams.StatsTextHeight);
333 aParams.SetHorizontalAlignment ((!myChartTrsfPers.IsNull()
5e30547b 334 && myChartTrsfPers->IsTrihedronOr2d()
335 && (myChartTrsfPers->Corner2d() & Aspect_TOTP_RIGHT) != 0)
336 ? Graphic3d_HTA_RIGHT
8ed07085 337 : Graphic3d_HTA_LEFT);
338 aParams.SetVerticalAlignment (Graphic3d_VTA_CENTER);
5e30547b 339 TCollection_AsciiString aLabels[3] =
340 {
341 TCollection_AsciiString() + 0 + " ms",
342 formatTimeMs(aMaxDuration * 0.5),
343 formatTimeMs(aMaxDuration)
344 };
345
8ed07085 346 const float aLabX = aParams.HorizontalAlignment() == Graphic3d_HTA_RIGHT
5e30547b 347 ? float(anOffset.x())
348 : float(anOffset.x() + aCharSize.x());
8ed07085 349
350 myChartLabels[0].Text()->SetText (aLabels[isTopDown ? 0 : 2].ToCString());
351 myChartLabels[0].Text()->SetPosition (gp_Pnt (aLabX, float(anOffset.y()), 0.0f));
352
353 myChartLabels[1].Text()->SetText (aLabels[isTopDown ? 1 : 1].ToCString());
354 myChartLabels[1].Text()->SetPosition (gp_Pnt (aLabX, float(anOffset.y() - aBinSize.y() / 2), 0.0f));
355
356 myChartLabels[2].Text()->SetText (aLabels[isTopDown ? 2 : 0].ToCString());
357 myChartLabels[2].Text()->SetPosition (gp_Pnt (aLabX, float(anOffset.y() - aBinSize.y()), 0.0f));
358
359 for (int i = 0; i < 3; i++)
360 {
361 myChartLabels[i].Text()->SetHeight (aParams.Height());
362 myChartLabels[i].Text()->SetHorizontalAlignment (aParams.HorizontalAlignment());
363 myChartLabels[i].Text()->SetVerticalAlignment (aParams.VerticalAlignment());
364
365 myChartLabels[i].Reset(aCtx);
366 }
5e30547b 367 }
15669413 368}
369
370// =======================================================================
371// function : Render
372// purpose :
373// =======================================================================
374void OpenGl_FrameStatsPrs::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
375{
376 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
377 const Standard_Boolean wasEnabledDepth = theWorkspace->UseDepthWrite();
378 if (theWorkspace->UseDepthWrite())
379 {
380 theWorkspace->UseDepthWrite() = Standard_False;
381 glDepthMask (GL_FALSE);
382 }
383
bf5f0ca2 384 const OpenGl_Aspects* aTextAspectBack = theWorkspace->SetAspects (&myTextAspect);
5e30547b 385
15669413 386 aCtx->ModelWorldState.Push();
387 aCtx->ModelWorldState.ChangeCurrent().InitIdentity();
388
5e30547b 389 // draw counters
15669413 390 {
5e30547b 391 aCtx->WorldViewState.Push();
392 if (!myCountersTrsfPers.IsNull())
393 {
b40cdc2b 394 myCountersTrsfPers->Apply (aCtx->Camera(),
5e30547b 395 aCtx->ProjectionState.Current(), aCtx->WorldViewState.ChangeCurrent(),
396 aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);
397 }
398 aCtx->ApplyModelViewMatrix();
399 myCountersText.Render (theWorkspace);
400 aCtx->WorldViewState.Pop();
15669413 401 }
402
5e30547b 403 // draw chart
404 if (myChartIndices->IsValid()
405 && myChartIndices->GetElemsNb() > 0)
406 {
407 aCtx->WorldViewState.Push();
408 if (!myChartTrsfPers.IsNull())
409 {
008210c3 410 myChartTrsfPers->Apply (aCtx->Camera(),
5e30547b 411 aCtx->ProjectionState.Current(), aCtx->WorldViewState.ChangeCurrent(),
412 aCtx->VirtualViewport()[2], aCtx->VirtualViewport()[3]);
413 }
414 aCtx->ApplyModelViewMatrix();
15669413 415
5e30547b 416 aCtx->ShaderManager()->BindFaceProgram (Handle(OpenGl_TextureSet)(), Graphic3d_TOSM_UNLIT,
417 Graphic3d_AlphaMode_Blend, true, false,
418 Handle(OpenGl_ShaderProgram)());
419 aCtx->SetColor4fv (OpenGl_Vec4 (1.0f, 1.0f, 1.0f, 1.0f));
420 glEnable (GL_BLEND);
421 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
422 myChartVertices->Bind (aCtx);
423 myChartVertices->bindAttribute (aCtx, Graphic3d_TOA_POS, 3, GL_FLOAT, myChartVertices->GetComponentsNb(), NULL);
424 myChartVertices->bindAttribute (aCtx, Graphic3d_TOA_COLOR, 4, GL_UNSIGNED_BYTE, myChartVertices->GetComponentsNb(), (void* )sizeof(Graphic3d_Vec3));
425
426 myChartIndices->Bind (aCtx);
427 aCtx->core15fwd->glDrawElements (GL_TRIANGLES, myChartIndices->GetElemsNb(), myChartIndices->GetDataType(), NULL);
428 myChartIndices->Unbind (aCtx);
429 myChartVertices->Unbind (aCtx);
430 myChartVertices->unbindAttribute (aCtx, Graphic3d_TOA_COLOR);
431 myChartVertices->unbindAttribute (aCtx, Graphic3d_TOA_POS);
432 glDisable (GL_BLEND);
433
434 myChartLines->Bind (aCtx);
435 myChartLines->bindAttribute (aCtx, Graphic3d_TOA_POS, 3, GL_FLOAT, myChartLines->GetComponentsNb(), NULL);
436 myChartLines->bindAttribute (aCtx, Graphic3d_TOA_COLOR, 4, GL_UNSIGNED_BYTE, myChartLines->GetComponentsNb(), (void* )sizeof(Graphic3d_Vec3));
437 aCtx->core15fwd->glDrawArrays (GL_LINES, 0, myChartLines->GetElemsNb());
438 myChartLines->Unbind (aCtx);
439 myChartLines->unbindAttribute (aCtx, Graphic3d_TOA_COLOR);
440 myChartLines->unbindAttribute (aCtx, Graphic3d_TOA_POS);
441
442 myChartLabels[0].Render (theWorkspace);
443 myChartLabels[1].Render (theWorkspace);
444 myChartLabels[2].Render (theWorkspace);
445
446 aCtx->WorldViewState.Pop();
447 }
15669413 448
15669413 449 aCtx->ModelWorldState.Pop();
450 aCtx->ApplyWorldViewMatrix();
451
bf5f0ca2 452 theWorkspace->SetAspects (aTextAspectBack);
15669413 453 if (theWorkspace->UseDepthWrite() != wasEnabledDepth)
454 {
455 theWorkspace->UseDepthWrite() = wasEnabledDepth;
456 glDepthMask (wasEnabledDepth ? GL_TRUE : GL_FALSE);
457 }
458}
bc73b006 459
460// =======================================================================
461// function : DumpJson
462// purpose :
463// =======================================================================
464void OpenGl_FrameStatsPrs::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
465{
466 OCCT_DUMP_CLASS_BEGIN (theOStream, OpenGl_FrameStatsPrs)
467
468 OCCT_DUMP_BASE_CLASS (theOStream, theDepth, OpenGl_Element)
469}