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