Merge pull request #16372 from ctrlaltdavid/DEV-2055

DEV-2055: Sanitize LODManager.setWorldQualityDetail() parameter value
This commit is contained in:
Shannon Romano 2019-10-24 15:20:34 -07:00 committed by GitHub
commit 15f27e53cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 87 deletions

View file

@ -133,15 +133,12 @@ Item {
ListElement {
text: "Low World Detail"
worldDetailQualityValue: 0.25
}
ListElement {
text: "Medium World Detail"
worldDetailQualityValue: 0.5
}
ListElement {
text: "Full World Detail"
worldDetailQualityValue: 0.75
}
}
@ -158,14 +155,7 @@ Item {
currentIndex: -1
function refreshWorldDetailDropdown() {
var currentWorldDetailQuality = LODManager.worldDetailQuality;
if (currentWorldDetailQuality <= 0.25) {
worldDetailDropdown.currentIndex = 0;
} else if (currentWorldDetailQuality <= 0.5) {
worldDetailDropdown.currentIndex = 1;
} else {
worldDetailDropdown.currentIndex = 2;
}
worldDetailDropdown.currentIndex = LODManager.worldDetailQuality;
}
Component.onCompleted: {
@ -173,7 +163,7 @@ Item {
}
onCurrentIndexChanged: {
LODManager.worldDetailQuality = model.get(currentIndex).worldDetailQualityValue;
LODManager.worldDetailQuality = currentIndex;
worldDetailDropdown.displayText = model.get(currentIndex).text;
}
}

View file

@ -7516,6 +7516,7 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptEngine
scriptEngine->registerGlobalObject("AvatarManager", DependencyManager::get<AvatarManager>().data());
scriptEngine->registerGlobalObject("LODManager", DependencyManager::get<LODManager>().data());
qScriptRegisterMetaType(scriptEngine.data(), worldDetailQualityToScriptValue, worldDetailQualityFromScriptValue);
scriptEngine->registerGlobalObject("Keyboard", DependencyManager::get<KeyboardScriptingInterface>().data());
scriptEngine->registerGlobalObject("Performance", new PerformanceScriptingInterface());

View file

@ -19,11 +19,8 @@
#include "ui/DialogsManager.h"
#include "InterfaceLogging.h"
const float LODManager::DEFAULT_DESKTOP_LOD_DOWN_FPS = LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_DESKTOP_FPS;
const float LODManager::DEFAULT_HMD_LOD_DOWN_FPS = LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS;
Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", LODManager::DEFAULT_DESKTOP_LOD_DOWN_FPS);
Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", LODManager::DEFAULT_HMD_LOD_DOWN_FPS);
Setting::Handle<int> desktopWorldDetailQuality("desktopWorldDetailQuality", (int)DEFAULT_WORLD_DETAIL_QUALITY);
Setting::Handle<int> hmdWorldDetailQuality("hmdWorldDetailQuality", (int)DEFAULT_WORLD_DETAIL_QUALITY);
LODManager::LODManager() {
}
@ -326,19 +323,21 @@ QString LODManager::getLODFeedbackText() {
}
void LODManager::loadSettings() {
setDesktopLODTargetFPS(desktopLODDecreaseFPS.get());
Setting::Handle<bool> firstRun { Settings::firstRun, true };
auto desktopQuality = static_cast<WorldDetailQuality>(desktopWorldDetailQuality.get());
auto hmdQuality = static_cast<WorldDetailQuality>(hmdWorldDetailQuality.get());
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
if (qApp->property(hifi::properties::OCULUS_STORE).toBool() && firstRun.get()) {
const float LOD_HIGH_QUALITY_LEVEL = 0.75f;
setHMDLODTargetFPS(LOD_HIGH_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS);
} else {
setHMDLODTargetFPS(hmdLODDecreaseFPS.get());
hmdQuality = WORLD_DETAIL_HIGH;
}
setWorldDetailQuality(desktopQuality, false);
setWorldDetailQuality(hmdQuality, true);
}
void LODManager::saveSettings() {
desktopLODDecreaseFPS.set(getDesktopLODTargetFPS());
hmdLODDecreaseFPS.set(getHMDLODTargetFPS());
desktopWorldDetailQuality.set((int)_desktopWorldDetailQuality);
hmdWorldDetailQuality.set((int)_hmdWorldDetailQuality);
}
const float MIN_DECREASE_FPS = 0.5f;
@ -393,54 +392,33 @@ float LODManager::getLODTargetFPS() const {
}
}
void LODManager::setWorldDetailQuality(float quality) {
static const float MIN_FPS = 10;
static const float LOW = 0.25f;
bool isLowestValue = quality == LOW;
bool isHMDMode = qApp->isHMDMode();
float maxFPS = isHMDMode ? LOD_MAX_LIKELY_HMD_FPS : LOD_MAX_LIKELY_DESKTOP_FPS;
float desiredFPS = maxFPS;
if (!isLowestValue) {
float calculatedFPS = (maxFPS - (maxFPS * quality));
desiredFPS = calculatedFPS < MIN_FPS ? MIN_FPS : calculatedFPS;
}
void LODManager::setWorldDetailQuality(WorldDetailQuality quality, bool isHMDMode) {
float desiredFPS = isHMDMode ? QUALITY_TO_FPS_HMD[quality] : QUALITY_TO_FPS_DESKTOP[quality];
if (isHMDMode) {
_hmdWorldDetailQuality = quality;
setHMDLODTargetFPS(desiredFPS);
} else {
_desktopWorldDetailQuality = quality;
setDesktopLODTargetFPS(desiredFPS);
}
}
void LODManager::setWorldDetailQuality(WorldDetailQuality quality) {
setWorldDetailQuality(quality, qApp->isHMDMode());
emit worldDetailQualityChanged();
}
float LODManager::getWorldDetailQuality() const {
WorldDetailQuality LODManager::getWorldDetailQuality() const {
return qApp->isHMDMode() ? _hmdWorldDetailQuality : _desktopWorldDetailQuality;
}
static const float LOW = 0.25f;
static const float MEDIUM = 0.5f;
static const float HIGH = 0.75f;
QScriptValue worldDetailQualityToScriptValue(QScriptEngine* engine, const WorldDetailQuality& worldDetailQuality) {
return worldDetailQuality;
}
bool inHMD = qApp->isHMDMode();
float targetFPS = 0.0f;
if (inHMD) {
targetFPS = getHMDLODTargetFPS();
} else {
targetFPS = getDesktopLODTargetFPS();
}
float maxFPS = inHMD ? LOD_MAX_LIKELY_HMD_FPS : LOD_MAX_LIKELY_DESKTOP_FPS;
float percentage = 1.0f - targetFPS / maxFPS;
if (percentage <= LOW) {
return LOW;
} else if (percentage <= MEDIUM) {
return MEDIUM;
}
return HIGH;
void worldDetailQualityFromScriptValue(const QScriptValue& object, WorldDetailQuality& worldDetailQuality) {
worldDetailQuality =
static_cast<WorldDetailQuality>(std::min(std::max(object.toInt32(), (int)WORLD_DETAIL_LOW), (int)WORLD_DETAIL_HIGH));
}
void LODManager::setLODQualityLevel(float quality) {

View file

@ -23,26 +23,52 @@
#include <render/Args.h>
/**jsdoc
* <p>The world detail quality rendered.</p>
* <table>
* <thead>
* <tr><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>0</code></td><td>Low world detail quality.</td></tr>
* <tr><td><code>1</code></td><td>Medium world detail quality.</td></tr>
* <tr><td><code>2</code></td><td>High world detail quality.</td></tr>
* </tbody>
* </table>
* @typedef {number} LODManager.WorldDetailQuality
*/
enum WorldDetailQuality {
WORLD_DETAIL_LOW = 0,
WORLD_DETAIL_MEDIUM,
WORLD_DETAIL_HIGH
};
Q_DECLARE_METATYPE(WorldDetailQuality);
#ifdef Q_OS_ANDROID
const float LOD_DEFAULT_QUALITY_LEVEL = 0.2f; // default quality level setting is High (lower framerate)
#else
const float LOD_DEFAULT_QUALITY_LEVEL = 0.5f; // default quality level setting is Mid
#endif
const float LOD_MAX_LIKELY_DESKTOP_FPS = 60.0f; // this is essentially, V-synch fps
#ifdef Q_OS_ANDROID
const float LOD_MAX_LIKELY_HMD_FPS = 36.0f; // this is essentially, V-synch fps
const WorldDetailQuality DEFAULT_WORLD_DETAIL_QUALITY = WORLD_DETAIL_LOW;
const std::vector<float> QUALITY_TO_FPS_DESKTOP = { 60.0f, 30.0f, 15.0f };
const std::vector<float> QUALITY_TO_FPS_HMD = { 25.0f, 16.0f, 10.0f };
#else
const float LOD_MAX_LIKELY_HMD_FPS = 90.0f; // this is essentially, V-synch fps
const WorldDetailQuality DEFAULT_WORLD_DETAIL_QUALITY = WORLD_DETAIL_MEDIUM;
const std::vector<float> QUALITY_TO_FPS_DESKTOP = { 60.0f, 30.0f, 15.0f };
const std::vector<float> QUALITY_TO_FPS_HMD = { 90.0f, 45.0f, 22.5f };
#endif
const float LOD_OFFSET_FPS = 5.0f; // offset of FPS to add for computing the target framerate
class AABox;
/**jsdoc
* The LOD class manages your Level of Detail functions within Interface.
* @namespace LODManager
*
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
@ -51,12 +77,12 @@ class AABox;
* @property {number} engineRunTime <em>Read-only.</em>
* @property {number} gpuTime <em>Read-only.</em>
*/
class LODManager : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
Q_PROPERTY(float worldDetailQuality READ getWorldDetailQuality WRITE setWorldDetailQuality NOTIFY worldDetailQualityChanged)
Q_PROPERTY(WorldDetailQuality worldDetailQuality READ getWorldDetailQuality WRITE setWorldDetailQuality
NOTIFY worldDetailQualityChanged)
Q_PROPERTY(float lodQualityLevel READ getLODQualityLevel WRITE setLODQualityLevel NOTIFY lodQualityLevelChanged)
@ -193,8 +219,8 @@ public:
float getSmoothRenderTime() const { return _smoothRenderTime; };
float getSmoothRenderFPS() const { return (_smoothRenderTime > 0.0f ? (float)MSECS_PER_SECOND / _smoothRenderTime : 0.0f); };
void setWorldDetailQuality(float quality);
float getWorldDetailQuality() const;
void setWorldDetailQuality(WorldDetailQuality quality);
WorldDetailQuality getWorldDetailQuality() const;
void setLODQualityLevel(float quality);
float getLODQualityLevel() const;
@ -220,9 +246,6 @@ public:
float getPidOd() const;
float getPidO() const;
static const float DEFAULT_DESKTOP_LOD_DOWN_FPS;
static const float DEFAULT_HMD_LOD_DOWN_FPS;
signals:
/**jsdoc
@ -244,6 +267,8 @@ signals:
private:
LODManager();
void setWorldDetailQuality(WorldDetailQuality quality, bool isHMDMode);
std::mutex _automaticLODLock;
bool _automaticLODAdjust = true;
@ -258,8 +283,11 @@ private:
float _lodQualityLevel{ LOD_DEFAULT_QUALITY_LEVEL };
float _desktopTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_DESKTOP_FPS };
float _hmdTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS };
WorldDetailQuality _desktopWorldDetailQuality { DEFAULT_WORLD_DETAIL_QUALITY };
WorldDetailQuality _hmdWorldDetailQuality { DEFAULT_WORLD_DETAIL_QUALITY };
float _desktopTargetFPS { QUALITY_TO_FPS_DESKTOP[_desktopWorldDetailQuality] };
float _hmdTargetFPS { QUALITY_TO_FPS_HMD[_hmdWorldDetailQuality] };
float _lodHalfAngle = getHalfAngleFromVisibilityDistance(DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT);
int _boundaryLevelAdjust = 0;
@ -269,4 +297,7 @@ private:
glm::vec4 _pidOutputs{ 0.0f };
};
QScriptValue worldDetailQualityToScriptValue(QScriptEngine* engine, const WorldDetailQuality& worldDetailQuality);
void worldDetailQualityFromScriptValue(const QScriptValue& object, WorldDetailQuality& worldDetailQuality);
#endif // hifi_LODManager_h

View file

@ -92,7 +92,7 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
RenderScriptingInterface::getInstance()->setShadowsEnabled(true);
qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME);
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.75f);
DependencyManager::get<LODManager>()->setWorldDetailQuality(WORLD_DETAIL_HIGH);
break;
case PerformancePreset::MID:
@ -104,7 +104,7 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
RenderScriptingInterface::getInstance()->setShadowsEnabled(false);
qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::INTERACTIVE);
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.5f);
DependencyManager::get<LODManager>()->setWorldDetailQuality(WORLD_DETAIL_MEDIUM);
break;
case PerformancePreset::LOW:
@ -114,7 +114,7 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommandedPpiScale);
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.25f);
DependencyManager::get<LODManager>()->setWorldDetailQuality(WORLD_DETAIL_LOW);
break;
case PerformancePreset::UNKNOWN:

View file

@ -58,18 +58,19 @@ void setupPreferences() {
static const QString GRAPHICS_QUALITY { "Graphics Quality" };
{
auto getter = []()->float {
return DependencyManager::get<LODManager>()->getWorldDetailQuality();
return (int)DependencyManager::get<LODManager>()->getWorldDetailQuality();
};
auto setter = [](float value) {
DependencyManager::get<LODManager>()->setWorldDetailQuality(value);
auto setter = [](int value) {
DependencyManager::get<LODManager>()->setWorldDetailQuality(static_cast<WorldDetailQuality>(value));
};
auto wodSlider = new SliderPreference(GRAPHICS_QUALITY, "World Detail", getter, setter);
wodSlider->setMin(0.25f);
wodSlider->setMax(0.75f);
wodSlider->setStep(0.25f);
preferences->addPreference(wodSlider);
auto wodButtons = new RadioButtonsPreference(GRAPHICS_QUALITY, "World Detail", getter, setter);
QStringList items;
items << "Low World Detail" << "Medium World Detail" << "High World Detail";
wodButtons->setHeading("World Detail");
wodButtons->setItems(items);
preferences->addPreference(wodButtons);
auto getterShadow = []()->bool {
auto menu = Menu::getInstance();