Overte C++ Documentation
LODManager.h
1 //
2 // LODManager.h
3 // interface/src/LODManager.h
4 //
5 // Created by Clement on 1/16/15.
6 // Copyright 2015 High Fidelity, Inc.
7 // Copyright 2021 Vircadia contributors.
8 // Copyright 2023 Overte e.V.
9 //
10 // Distributed under the Apache License, Version 2.0.
11 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
12 // SPDX-License-Identifier: Apache-2.0
13 //
14 
15 #ifndef hifi_LODManager_h
16 #define hifi_LODManager_h
17 
18 #include <mutex>
19 
20 #include <DependencyManager.h>
21 #include <NumericalConstants.h>
22 #include <OctreeConstants.h>
23 #include <OctreeUtils.h>
24 #include <PIDController.h>
25 #include <SimpleMovingAverage.h>
26 #include <render/Args.h>
27 #include <ScriptValue.h>
28 
29 class ScriptEngine;
30 
31 /*@jsdoc
32  * <p>The balance between target framerate and world detail quality rendered.</p>
33  * <table>
34  * <thead>
35  * <tr><th>Value</th><th>Description</th></tr>
36  * </thead>
37  * <tbody>
38  * <tr><td><code>0</code></td><td>High frame rate / Low detail quality.</td></tr>
39  * <tr><td><code>1</code></td><td>Medium frame rate / Medium detail quality.</td></tr>
40  * <tr><td><code>2</code></td><td>Low frame rate / High detail quality.</td></tr>
41  * </tbody>
42  * </table>
43  * @typedef {number} LODManager.WorldDetailQuality
44  */
45 enum WorldDetailQuality {
46  WORLD_DETAIL_LOW = 0,
47  WORLD_DETAIL_MEDIUM,
48  WORLD_DETAIL_HIGH
49 };
50 Q_DECLARE_METATYPE(WorldDetailQuality);
51 
52 const bool DEFAULT_LOD_AUTO_ADJUST = true; // true for auto, false for manual.
53 
54 #ifdef Q_OS_ANDROID
55 const float DEFAULT_LOD_QUALITY_LEVEL = 0.2f; // default quality level setting is High (lower framerate)
56 #else
57 const float DEFAULT_LOD_QUALITY_LEVEL = 0.5f; // default quality level setting is Mid
58 #endif
59 
60 #ifdef Q_OS_ANDROID
61 const WorldDetailQuality DEFAULT_WORLD_DETAIL_QUALITY = WORLD_DETAIL_LOW;
62 const std::vector<float> QUALITY_TO_FPS_DESKTOP = { 60.0f, 30.0f, 15.0f };
63 const std::vector<float> QUALITY_TO_FPS_HMD = { 25.0f, 16.0f, 10.0f };
64 #else
65 const WorldDetailQuality DEFAULT_WORLD_DETAIL_QUALITY = WORLD_DETAIL_MEDIUM;
66 const std::vector<float> QUALITY_TO_FPS_DESKTOP = { 60.0f, 30.0f, 15.0f };
67 const std::vector<float> QUALITY_TO_FPS_HMD = { 90.0f, 45.0f, 22.5f };
68 #endif
69 
70 const float LOD_OFFSET_FPS = 5.0f; // offset of FPS to add for computing the target framerate
71 
72 class AABox;
73 
74 
75 /*@jsdoc
76  * The <code>LODManager</code> API manages the Level of Detail displayed in Interface. If the LOD is being automatically
77  * adjusted, the LOD is decreased if the measured frame rate is lower than the target FPS, and increased if the measured frame
78  * rate is greater than the target FPS.
79  *
80  * @namespace LODManager
81  *
82  * @hifi-interface
83  * @hifi-client-entity
84  * @hifi-avatar
85  *
86  * @property {LODManager.WorldDetailQuality} worldDetailQuality - The quality of the rendered world detail.
87  * <p>Setting this value updates the current desktop or HMD target LOD FPS.</p>
88  * @property {number} lodQualityLevel - <em>Not used.</em>
89  * <p class="important">Deprecated: This property is deprecated and will be removed.</p>
90  * @property {boolean} automaticLODAdjust - <code>true</code> to automatically adjust the LOD, <code>false</code> to manually
91  * adjust it.
92  *
93  * @property {number} engineRunTime - The time spent in the "render" thread to produce the most recent frame, in ms.
94  * <em>Read-only.</em>
95  * @property {number} batchTime - The time spent in the "present" thread processing the batches of the most recent frame, in ms.
96  * <em>Read-only.</em>
97  * @property {number} presentTime - The time spent in the "present" thread between the last buffer swap, i.e., the total time
98  * to submit the most recent frame, in ms.
99  * <em>Read-only.</em>
100  * @property {number} gpuTime - The time spent in the GPU executing the most recent frame, in ms.
101  * <em>Read-only.</em>
102  *
103  * @property {number} nowRenderTime - The current, instantaneous time spend to produce frames, in ms. This is the worst of
104  * <code>engineRunTime</code>, <code>batchTime</code>, <code>presentTime</code>, and <code>gpuTime</code>.
105  * <em>Read-only.</em>
106  * @property {number} nowRenderFPS - The current, instantaneous frame rate, in Hz.
107  * <em>Read-only.</em>
108  *
109  * @property {number} smoothScale - The amount of smoothing applied to calculate <code>smoothRenderTime</code> and
110  * <code>smoothRenderFPS</code>.
111  * @property {number} smoothRenderTime - The average time spend to produce frames, in ms.
112  * <em>Read-only.</em>
113  * @property {number} smoothRenderFPS - The average frame rate, in Hz.
114  * <em>Read-only.</em>
115  *
116  * @property {number} lodTargetFPS - The target LOD FPS per the current desktop or HMD display mode, capped by the target
117  * refresh rate set by the {@link Performance} API.
118  * <em>Read-only.</em>
119 
120  * @property {number} lodAngleDeg - The minimum angular dimension (relative to the camera position) of an entity in order for
121  * it to be rendered, in degrees. The angular dimension is calculated as a sphere of radius half the diagonal of the
122  * entity's AA box.
123 
124  * @property {number} lodFarMaxAngleDeg - The maximum angular size (relative to the camera position)
125  * of an entity that is allowed to be culled by LOD Manager, in degrees at distance specified by lodFarDistance. The angular dimension is
126  * calculated as a sphere of radius half the diagonal of the entity's AA box.
127  * @property {number} lodNearMaxAngleDeg - The maximum angular size (relative to the camera position)
128  * of an entity that is allowed to be culled by LOD Manager, in degrees at distance specified by lodNearDistance. The angular dimension is
129  * calculated as a sphere of radius half the diagonal of the entity's AA box.
130 
131  * @property {number} lodFarDistance - Distance for which lodFarMaxAngleDeg limit is applied
132  * @property {number} lodNearDistance - Distance for which lodNearMaxAngleDeg limit is applied
133 
134  *
135  * @property {number} pidKp - <em>Not used.</em>
136  * @property {number} pidKi - <em>Not used.</em>
137  * @property {number} pidKd - <em>Not used.</em>
138  * @property {number} pidKv - <em>Not used.</em>
139  * @property {number} pidOp - <em>Not used.</em> <em>Read-only.</em>
140  * @property {number} pidOi - <em>Not used.</em> <em>Read-only.</em>
141  * @property {number} pidOd - <em>Not used.</em> <em>Read-only.</em>
142  * @property {number} pidO - <em>Not used.</em> <em>Read-only.</em>
143  */
144 class LODManager : public QObject, public Dependency {
145  Q_OBJECT
146  SINGLETON_DEPENDENCY
147 
148  Q_PROPERTY(WorldDetailQuality worldDetailQuality READ getWorldDetailQuality WRITE setWorldDetailQuality
149  NOTIFY worldDetailQualityChanged)
150 
151  Q_PROPERTY(float lodQualityLevel READ getLODQualityLevel WRITE setLODQualityLevel NOTIFY lodQualityLevelChanged)
152 
153  Q_PROPERTY(bool automaticLODAdjust READ getAutomaticLODAdjust WRITE setAutomaticLODAdjust NOTIFY autoLODChanged)
154 
155  Q_PROPERTY(float presentTime READ getPresentTime)
156  Q_PROPERTY(float engineRunTime READ getEngineRunTime)
157  Q_PROPERTY(float batchTime READ getBatchTime)
158  Q_PROPERTY(float gpuTime READ getGPUTime)
159 
160  Q_PROPERTY(float nowRenderTime READ getNowRenderTime)
161  Q_PROPERTY(float nowRenderFPS READ getNowRenderFPS)
162 
163  Q_PROPERTY(float smoothScale READ getSmoothScale WRITE setSmoothScale)
164  Q_PROPERTY(float smoothRenderTime READ getSmoothRenderTime)
165  Q_PROPERTY(float smoothRenderFPS READ getSmoothRenderFPS)
166 
167  Q_PROPERTY(float lodTargetFPS READ getLODTargetFPS)
168 
169  Q_PROPERTY(float lodAngleDeg READ getLODAngleDeg WRITE setLODAngleDeg)
170 
171  Q_PROPERTY(float lodFarMaxAngleDeg READ getLODFarMaxAngleDeg WRITE setLODFarMaxAngleDeg)
172  Q_PROPERTY(float lodNearMaxAngleDeg READ getLODNearMaxAngle WRITE setLODNearMaxAngle)
173  Q_PROPERTY(float lodFarDistance READ getLODFarDistance WRITE setLODFarDistance)
174  Q_PROPERTY(float lodNearDistance READ getLODNearDistance WRITE setLODNearDistance)
175 
176  Q_PROPERTY(float pidKp READ getPidKp WRITE setPidKp)
177  Q_PROPERTY(float pidKi READ getPidKi WRITE setPidKi)
178  Q_PROPERTY(float pidKd READ getPidKd WRITE setPidKd)
179  Q_PROPERTY(float pidKv READ getPidKv WRITE setPidKv)
180 
181  Q_PROPERTY(float pidOp READ getPidOp)
182  Q_PROPERTY(float pidOi READ getPidOi)
183  Q_PROPERTY(float pidOd READ getPidOd)
184  Q_PROPERTY(float pidO READ getPidO)
185 
186 public:
187 
188  /*@jsdoc
189  * Sets whether the LOD should be automatically adjusted.
190  * @function LODManager.setAutomaticLODAdjust
191  * @param {boolean} value - <code>true</code> to automatically adjust the LOD, <code>false</code> to manually adjust it.
192  */
193  Q_INVOKABLE void setAutomaticLODAdjust(bool value);
194 
195  /*@jsdoc
196  * Gets whether the LOD is being automatically adjusted.
197  * @function LODManager.getAutomaticLODAdjust
198  * @returns {boolean} <code>true</code> if the LOD is being automatically adjusted, <code>false</code> if it is being
199  * manually adjusted.
200  */
201  Q_INVOKABLE bool getAutomaticLODAdjust() const { return _automaticLODAdjust; }
202 
203  /*@jsdoc
204  * Sets the target desktop LOD FPS.
205  * @function LODManager.setDesktopLODTargetFPS
206  * @param {number} value - The target desktop LOD FPS, in Hz.
207  */
208  Q_INVOKABLE void setDesktopLODTargetFPS(float value);
209 
210  /*@jsdoc
211  * Gets the target desktop LOD FPS.
212  * @function LODManager.getDesktopLODTargetFPS
213  * @returns {number} The target desktop LOD FPS, in Hz.
214  */
215 
216  Q_INVOKABLE float getDesktopLODTargetFPS() const;
217 
218  /*@jsdoc
219  * Sets the target HMD LOD FPS.
220  * @function LODManager.setHMDLODTargetFPS
221  * @param {number} value - The target HMD LOD FPS, in Hz.
222  */
223 
224  Q_INVOKABLE void setHMDLODTargetFPS(float value);
225 
226  /*@jsdoc
227  * Gets the target HMD LOD FPS.
228  * The target FPS in HMD mode. The LOD is adjusted to ...
229  * @function LODManager.getHMDLODTargetFPS
230  * @returns {number} The target HMD LOD FPS, in Hz.
231  */
232  Q_INVOKABLE float getHMDLODTargetFPS() const;
233 
234 
235  // User Tweakable LOD Items
236 
237  /*@jsdoc
238  * Gets a text description of the current level of detail rendered.
239  * @function LODManager.getLODFeedbackText
240  * @returns {string} A text description of the current level of detail rendered.
241  * @example <caption>Report the current level of detail rendered.</caption>
242  * print("You can currently see: " + LODManager.getLODFeedbackText());
243  */
244  Q_INVOKABLE QString getLODFeedbackText();
245 
246  /*@jsdoc
247  * @function LODManager.setOctreeSizeScale
248  * @param {number} sizeScale - The octree size scale.
249  * @deprecated This function is deprecated and will be removed. Use the <code>lodAngleDeg</code> property instead.
250  */
251  Q_INVOKABLE void setOctreeSizeScale(float sizeScale);
252 
253  /*@jsdoc
254  * @function LODManager.getOctreeSizeScale
255  * @returns {number} The octree size scale.
256  * @deprecated This function is deprecated and will be removed. Use the <code>lodAngleDeg</code> property instead.
257  */
258  Q_INVOKABLE float getOctreeSizeScale() const;
259 
260  /*@jsdoc
261  * @function LODManager.setBoundaryLevelAdjust
262  * @param {number} boundaryLevelAdjust - The boundary level adjust factor.
263  * @deprecated This function is deprecated and will be removed.
264  */
265  Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust);
266 
267  /*@jsdoc
268  * @function LODManager.getBoundaryLevelAdjust
269  * @returns {number} The boundary level adjust factor.
270  * @deprecated This function is deprecated and will be removed.
271  */
272  Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
273 
274  /*@jsdoc
275  * The target LOD FPS per the current desktop or HMD display mode, capped by the target refresh rate.
276  * @function LODManager.getLODTargetFPS
277  * @returns {number} The target LOD FPS, in Hz.
278  */
279  Q_INVOKABLE float getLODTargetFPS() const;
280 
281  float getPresentTime() const { return _presentTime; }
282  float getEngineRunTime() const { return _engineRunTime; }
283  float getBatchTime() const { return _batchTime; }
284  float getGPUTime() const { return _gpuTime; }
285 
286  static bool shouldRender(const RenderArgs* args, const AABox& bounds);
287  void setRenderTimes(float presentTime, float engineRunTime, float batchTime, float gpuTime);
288  void autoAdjustLOD(float realTimeDelta);
289 
290  void loadSettings();
291  void saveSettings();
292  void resetLODAdjust();
293 
294  float getNowRenderTime() const { return _nowRenderTime; };
295  float getNowRenderFPS() const { return (_nowRenderTime > 0.0f ? (float)MSECS_PER_SECOND / _nowRenderTime : 0.0f); };
296 
297  void setSmoothScale(float t);
298  float getSmoothScale() const { return _smoothScale; }
299 
300  float getSmoothRenderTime() const { return _smoothRenderTime; };
301  float getSmoothRenderFPS() const { return (_smoothRenderTime > 0.0f ? (float)MSECS_PER_SECOND / _smoothRenderTime : 0.0f); };
302 
303  void setWorldDetailQuality(WorldDetailQuality quality);
304  WorldDetailQuality getWorldDetailQuality() const;
305 
306  void setLODQualityLevel(float quality);
307  float getLODQualityLevel() const;
308 
309  float getLODAngleDeg() const;
310  void setLODAngleDeg(float lodAngle);
311  float getLODFarHalfAngleTan() const;
312  float getLODNearHalfAngleTan() const;
313  float getLODAngle() const;
314  float getVisibilityDistance() const;
315  void setVisibilityDistance(float distance);
316 
317  float getPidKp() const;
318  float getPidKi() const;
319  float getPidKd() const;
320  float getPidKv() const;
321  void setPidKp(float k);
322  void setPidKi(float k);
323  void setPidKd(float k);
324  void setPidKv(float t);
325 
326  float getPidOp() const;
327  float getPidOi() const;
328  float getPidOd() const;
329  float getPidO() const;
330 
331  void setLODFarDistance(float value);
332  float getLODFarDistance() const { return _farDistance; }
333  void setLODNearDistance(float value);
334  float getLODNearDistance() const { return _nearDistance; }
335  void setLODFarMaxAngleDeg(float value);
336  float getLODFarMaxAngleDeg() const;
337  void setLODNearMaxAngle(float value);
338  float getLODNearMaxAngle() const;
339 
340 signals:
341 
342  /*@jsdoc
343  * <em>Not triggered.</em>
344  * @function LODManager.LODIncreased
345  * @returns {Signal}
346  * @deprecated This signal is deprecated and will be removed.
347  */
348  void LODIncreased();
349 
350  /*@jsdoc
351  * <em>Not triggered.</em>
352  * @function LODManager.LODDecreased
353  * @returns {Signal}
354  * @deprecated This signal is deprecated and will be removed.
355  */
356  void LODDecreased();
357 
358  /*@jsdoc
359  * Triggered when whether or not the LOD is being automatically adjusted changes.
360  * @function LODManager.autoLODChanged
361  * @returns {Signal}
362  */
363  void autoLODChanged();
364 
365  /*@jsdoc
366  * Triggered when the <code>lodQualityLevel</code> property value changes.
367  * @function LODManager.lodQualityLevelChanged
368  * @returns {Signal}
369  * @deprecated This signal is deprecated and will be removed.
370  */
371  void lodQualityLevelChanged();
372 
373  /*@jsdoc
374  * Triggered when the world detail quality changes.
375  * @function LODManager.worldDetailQualityChanged
376  * @returns {Signal}
377  */
378  void worldDetailQualityChanged();
379 
380 private:
381  LODManager();
382 
383  float getLODHalfAngleTan() const;
384  void setWorldDetailQuality(WorldDetailQuality quality, bool isHMDMode);
385  void updateLODAfterSettingsChange();
386 
387  std::mutex _automaticLODLock;
388  bool _automaticLODAdjust = DEFAULT_LOD_AUTO_ADJUST;
389 
390  float _presentTime{ 0.0f }; // msec
391  float _engineRunTime{ 0.0f }; // msec
392  float _batchTime{ 0.0f }; // msec
393  float _gpuTime{ 0.0f }; // msec
394 
395  float _farDistance{ 200.0f };
396  float _nearDistance{ 4.0f };
397  float _farMaxAngle{ 15.0f / 180.f * (float)M_PI };
398  float _nearMaxAngle{ 1.0f / 180.f * (float)M_PI };
399 
400  float _nowRenderTime{ 0.0f }; // msec
401  float _smoothScale{ 10.0f }; // smooth is evaluated over 10 times longer than now
402  float _smoothRenderTime{ 0.0f }; // msec
403 
404  float _lodQualityLevel{ DEFAULT_LOD_QUALITY_LEVEL };
405 
406  WorldDetailQuality _desktopWorldDetailQuality { DEFAULT_WORLD_DETAIL_QUALITY };
407  WorldDetailQuality _hmdWorldDetailQuality { DEFAULT_WORLD_DETAIL_QUALITY };
408 
409  float _desktopTargetFPS { QUALITY_TO_FPS_DESKTOP[_desktopWorldDetailQuality] };
410  float _hmdTargetFPS { QUALITY_TO_FPS_HMD[_hmdWorldDetailQuality] };
411 
412  float _lodHalfAngle = getHalfAngleFromVisibilityDistance(DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT);
413  int _boundaryLevelAdjust = 0;
414 
415  glm::vec4 _pidCoefs{ 1.0f, 0.0f, 0.0f, 1.0f }; // Kp, Ki, Kd, Kv
416  glm::vec4 _pidHistory{ 0.0f };
417  glm::vec4 _pidOutputs{ 0.0f };
418 };
419 
420 ScriptValue worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDetailQuality& worldDetailQuality);
421 bool worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality);
422 
423 #endif // hifi_LODManager_h
Provides an engine-independent interface for a scripting engine.
Definition: ScriptEngine.h:93
[ScriptInterface] Provides an engine-independent interface for QScriptValue
Definition: ScriptValue.h:40