Make ART slider logarithmic + A handful of fixes from feedback by Pan

- cleanup and ratioanlise code altering the settings. 
- rename to make units more obvious
- make slider logarithmic to make the req'd range more practical.
make the auto-tuning more robust and a little less trigger happy. 
- fix incorrect logic that blocked maxnonimposter control from working
- Zoom to Avatar instead of cam to avatar for consistency rather than correctness.
-open phototools not phototools_camera.
master
Beq 2021-11-08 23:37:30 +00:00
parent 4336023179
commit 7c1d2c4db3
11 changed files with 112 additions and 93 deletions

View File

@ -25794,11 +25794,11 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Comment</key>
<string>Render Time Limit in microseconds (0.0 = no limit)</string>
<key>Persist</key>
<integer>1</integer>
<integer>0</integer>
<key>Type</key>
<string>U32</string>
<string>F32</string>
<key>Value</key>
<integer>50</integer>
<integer>4.699</integer>
</map>
<key>FSTuningFPSStrategy</key>
<map>

View File

@ -154,8 +154,6 @@ BOOL LLFloaterPerformance::postBuild()
mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateComplexityText, this));
mNearbyPanel->getChild<LLSliderCtrl>("IndirectMaxComplexity")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxComplexity, this));
updateMaxRenderTime();
// updateMaxRenderTimeText();
mMaxARTChangedSignal = gSavedSettings.getControl("FSRenderAvatarMaxART")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateMaxRenderTime, this));
mNearbyPanel->getChild<LLSliderCtrl>("FSRenderAvatarMaxART")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxRenderTime, this));
@ -194,13 +192,7 @@ void LLFloaterPerformance::draw()
static LLCachedControl<U32> fpsCap(gSavedSettings, "FramePerSecondLimit"); // user limited FPS
static LLCachedControl<U32> targetFPS(gSavedSettings, "FSTargetFPS"); // desired FPS
// static LLCachedControl<bool> autoTune(gSavedSettings, "FSAutoTuneFPS"); // auto tune enabled?
static LLCachedControl<U32> maxRenderCost(gSavedSettings, "FSRenderAvatarMaxART");
if(maxRenderCost != FSPerfStats::renderAvatarMaxART)
{
gSavedSettings.setU32("FSRenderAvatarMaxART", FSPerfStats::renderAvatarMaxART);
}
static LLCachedControl<U32> targetFPS(gSavedSettings, "FSTargetFPS"); // desired FPS
if (mUpdateTimer->hasExpired())
{
@ -334,9 +326,9 @@ void LLFloaterPerformance::draw()
textbox->setColor(LLUIColorTable::instance().getColor("red"));
}
}
else if( target_frame_time_ns > (tot_frame_time_ns + FSPerfStats::renderAvatarMaxART))
else if( target_frame_time_ns > (tot_frame_time_ns + FSPerfStats::renderAvatarMaxART_ns))
{
// if we have more time to spare let's shift up little in the hope we'll restore an avatar.
// if we have more time to spare. Display this (the service will update things)
textbox->setColor(LLUIColorTable::instance().getColor("green"));
}
}
@ -426,7 +418,7 @@ void LLFloaterPerformance::populateHUDList()
row[1]["value"] = llformat( "%.3f",FSPerfStats::raw_to_us(hud_render_time_raw) );
row[1]["font"]["name"] = "SANSSERIF";
row[2]["column"] = "complex_value";
row[2]["type"] = "text";
@ -580,10 +572,6 @@ void LLFloaterPerformance::populateNearbyList()
mNearbyList->clearRows();
mNearbyList->updateColumns(true);
static LLCachedControl<U32> maxRenderCost(gSavedSettings, "FSRenderAvatarMaxART", 0);
updateMaxRenderTime();
// updateMaxRenderTimeText();
std::vector<LLCharacter*> valid_nearby_avs;
getNearbyAvatars(valid_nearby_avs);
@ -813,7 +801,7 @@ void LLFloaterPerformance::updateMaxRenderTime()
void LLFloaterPerformance::updateMaxRenderTimeText()
{
LLAvatarComplexityControls::setRenderTimeText(
gSavedSettings.getU32("FSRenderAvatarMaxART"),
gSavedSettings.getF32("FSRenderAvatarMaxART"),
mNearbyPanel->getChild<LLTextBox>("FSRenderAvatarMaxARTText", true),
true);
}

View File

@ -42,17 +42,15 @@ namespace FSPerfStats
std::atomic<int64_t> inUseAttachmentRigged{0};
std::atomic<int64_t> inUseAttachmentUnRigged{0};
#endif
std::atomic<int64_t> tunedAvatars{0};
U32 targetFPS; // desired FPS
U32 renderAvatarMaxART{50000}; // highest render time we'll allow without culling features
U64 renderAvatarMaxART_ns{(U64)(ART_UNLIMITED_NANOS)}; // highest render time we'll allow without culling features
U32 fpsTuningStrategy{0}; // linked to FSTuningFPSStrategy
U32 lastGlobalPrefChange{0};
std::mutex bufferToggleLock{};
bool autoTune{false};
U32 smoothingPeriods{1}; // number of frames to smooth over.
std::atomic<int> StatsRecorder::writeBuffer{0};
bool StatsRecorder::collectionEnabled{true};
LLUUID StatsRecorder::focusAv{LLUUID::null};
@ -68,8 +66,8 @@ namespace FSPerfStats
FSPerfStats::targetFPS = gSavedSettings.getU32("FSTargetFPS");
FSPerfStats::autoTune = gSavedSettings.getBOOL("FSAutoTuneFPS");
FSPerfStats::renderAvatarMaxART = gSavedSettings.getBOOL("FSRenderAvatarMaxART");
FSPerfStats::smoothingPeriods = gSavedSettings.getU32("FSPerfFloaterSmoothingPeriods");
updateRenderCostLimitFromSettings();
t.detach();
}
@ -81,6 +79,7 @@ namespace FSPerfStats
using ST = StatType_t;
bool unreliable{false};
LLCachedControl<U32> smoothingPeriods(gSavedSettings, "FSPerfFloaterSmoothingPeriods");
auto& sceneStats = statsDoubleBuffer[writeBuffer][static_cast<size_t>(ObjType_t::OT_GENERAL)][LLUUID::null];
auto& lastStats = statsDoubleBuffer[writeBuffer ^ 1][static_cast<size_t>(ObjType_t::OT_GENERAL)][LLUUID::null];
@ -226,11 +225,42 @@ namespace FSPerfStats
}
}
// static
void StatsRecorder::updateSettingsFromRenderCostLimit()
{
static LLCachedControl<F32> maxRenderCost_us(gSavedSettings, "FSRenderAvatarMaxART");
if( (F32)maxRenderCost_us != log10( ( (F32)FSPerfStats::renderAvatarMaxART_ns )/1000 ) )
{
if( FSPerfStats::renderAvatarMaxART_ns != 0 )
{
gSavedSettings.setF32( "FSRenderAvatarMaxART", log10( ( (F32)FSPerfStats::renderAvatarMaxART_ns )/1000 ) );
}
else
{
gSavedSettings.setF32( "FSRenderAvatarMaxART",log10( FSPerfStats::ART_UNLIMITED_NANOS/1000 ) );
}
}
}
// static
void StatsRecorder::updateRenderCostLimitFromSettings()
{
const auto newval = gSavedSettings.getF32("FSRenderAvatarMaxART");
if(newval < log10(FSPerfStats::ART_UNLIMITED_NANOS/1000))
{
FSPerfStats::renderAvatarMaxART_ns = pow(10,newval)*1000;
}
else
{
FSPerfStats::renderAvatarMaxART_ns = 0;
};
}
// static
void StatsRecorder::updateAvatarParams()
{
LLCachedControl<F32> drawDistance(gSavedSettings, "RenderFarClip");
static LLCachedControl<F32> drawDistance(gSavedSettings, "RenderFarClip");
auto av_render_max_raw = FSPerfStats::StatsRecorder::getMax(ObjType_t::OT_AVATAR, FSPerfStats::StatType_t::RENDER_COMBINED);
// Is our target frame time lower than current? If so we need to take action to reduce draw overheads.
// cumulative avatar time (includes idle processing, attachments and base av)
@ -244,21 +274,24 @@ namespace FSPerfStats
// the time spent this frame on the "doFrame" call. Treated as "tot time for frame"
auto tot_frame_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FRAME);
if(tot_sleep_time_raw != 0 || tot_limit_time_raw !=0 )
if( tot_sleep_time_raw != 0 )
{
// Note: we do not average sleep and fpslimit, therefore we cannot reliably use them here.
// Note: we do not average sleep
// if at some point we need to, the averaging will need to take this into account or
// we forever think we're in the background due to residuals.
LL_DEBUGS() << "No tuning when not in focus" << LL_ENDL;
return;
}
// LL_INFOS() << "Effective FPS:" << (1000000/FSPerfStats::raw_to_us(tot_frame_time_raw)) << " Target:" << targetFPS << LL_ENDL;
// The frametime budget we have based on the target FPS selected
auto target_frame_time_raw = (U64)llround(get_timer_info().mClockFrequency/(targetFPS==0?1:targetFPS));
auto target_frame_time_raw = (U64)llround((F64)LLTrace::BlockTimer::countsPerSecond()/(targetFPS==0?1:targetFPS));
// LL_INFOS() << "Effective FPS(raw):" << tot_frame_time_raw << " Target:" << target_frame_time_raw << LL_ENDL;
if( tot_limit_time_raw != 0)
{
// This could be problematic.
tot_frame_time_raw -= tot_limit_time_raw;
}
// 1) Is the target frame tim lower than current?
if( target_frame_time_raw <= tot_frame_time_raw )
{
@ -276,22 +309,27 @@ namespace FSPerfStats
{
if(FSPerfStats::fpsTuningStrategy == 1)
{
// 1 - hack the water to opaque. all non opaque have a significan t hit, this is a big boost.
// 1 - hack the water to opaque. all non opaque have a significant hit, this is a big boost for (arguably) a minor visual hit.
// the other reflection options make comparatively little change and iof this overshoots we'll be stepping back up later
if(LLPipeline::RenderReflectionDetail != -2)
{
gSavedSettings.setS32("RenderReflectionDetail", -2);
FSPerfStats::lastGlobalPrefChange = gFrameCount;
return;
}
else // deliberately "else" here so we only do these in steps
{
// step down the DD by 10m per update
auto new_dd = (drawDistance>42)?(drawDistance - 10) : 32;
gSavedSettings.setF32("RenderFarClip", new_dd);
FSPerfStats::lastGlobalPrefChange = gFrameCount;
if(new_dd != drawDistance)
{
gSavedSettings.setF32("RenderFarClip", new_dd);
FSPerfStats::lastGlobalPrefChange = gFrameCount;
return;
}
}
}
}
// slam the avatar time to 0 "imposter all the things"
target_avatar_time_raw = 0;
}
else
@ -304,47 +342,47 @@ namespace FSPerfStats
{
// we need to spend less time drawing avatars to meet our budget
// Note: working in usecs now cos reasons.
U32 new_render_limit_us {0};
auto new_render_limit_ns {renderAvatarMaxART_ns};
// max render this frame may be higher than the last (cos new entrants and jitter) so make sure we are heading in the right direction
if(FSPerfStats::raw_to_us(av_render_max_raw) < renderAvatarMaxART)
if(FSPerfStats::raw_to_ns(av_render_max_raw) < renderAvatarMaxART_ns)
{
new_render_limit_us = FSPerfStats::raw_to_us(av_render_max_raw);
new_render_limit_ns = FSPerfStats::raw_to_ns(av_render_max_raw);
}
else
{
new_render_limit_us = renderAvatarMaxART;
}
new_render_limit_us -= 100;
// bounce at the bottom to prevent "no limit"
if(new_render_limit_us <= 0 || new_render_limit_us >1000000)
{
new_render_limit_us = 100;
new_render_limit_ns = renderAvatarMaxART_ns;
}
new_render_limit_ns -= FSPerfStats::ART_MIN_ADJUST_DOWN_NANOS;
// bounce at the bottom to prevent "no limit"
new_render_limit_ns = std::max((U64)new_render_limit_ns, (U64)FSPerfStats::ART_MINIMUM_NANOS);
// assign the new value
renderAvatarMaxART = new_render_limit_us;
// LL_DEBUGS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit_us << LL_ENDL;
renderAvatarMaxART_ns = new_render_limit_ns;
// LL_DEBUGS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit_ns << LL_ENDL;
}
// LL_DEBUGS() << "AUTO_TUNE: Target frame time:"<< FSPerfStats::raw_to_us(target_frame_time_raw) << "usecs (non_avatar is " << FSPerfStats::raw_to_us(non_avatar_time_raw) << "usecs) Max cost limited=" << renderAvatarMaxART << LL_ENDL;
// LL_DEBUGS() << "AUTO_TUNE: Target frame time:"<< FSPerfStats::raw_to_us(target_frame_time_raw) << "usecs (non_avatar is " << FSPerfStats::raw_to_us(non_avatar_time_raw) << "usecs) Max cost limited=" << renderAvatarMaxART_ns << LL_ENDL;
}
else if( FSPerfStats::raw_to_us(target_frame_time_raw) > (FSPerfStats::raw_to_us(tot_frame_time_raw) + renderAvatarMaxART) )
else if( FSPerfStats::raw_to_ns(target_frame_time_raw) > (FSPerfStats::raw_to_ns(tot_frame_time_raw) + renderAvatarMaxART_ns) )
{
if( FSPerfStats::tunedAvatars > 0 )
if( FSPerfStats::tunedAvatars >= 0 )
{
// if we have more time to spare let's shift up little in the hope we'll restore an avatar.
renderAvatarMaxART += 10;
renderAvatarMaxART_ns += FSPerfStats::ART_MIN_ADJUST_UP_NANOS;
}
if(drawDistance < 180.) // TODO(Beq) make this less arbitrary
if( drawDistance < FSPerfStats::PREFERRED_DD ) // TODO(Beq) make this less arbitrary
{
gSavedSettings.setF32("RenderFarClip", drawDistance + 10.);
}
if( (FSPerfStats::raw_to_us(target_frame_time_raw) * 1.5) > FSPerfStats::raw_to_us(tot_frame_time_raw) &&
if( (target_frame_time_raw * 1.5) > tot_frame_time_raw &&
FSPerfStats::tunedAvatars == 0 &&
drawDistance >= 128. )
drawDistance >= FSPerfStats::PREFERRED_DD )
{
// if everything else is "max" and we have 50% headroom let's knock the water quality up a notch at a time.
auto water = gSavedSettings.getS32("RenderReflectionDetail");
gSavedSettings.setS32("RenderReflectionDetail", water+1);
}
}
}
updateSettingsFromRenderCostLimit();
}
}

View File

@ -63,18 +63,21 @@ namespace FSPerfStats
extern std::atomic<int64_t> inUseAttachmentRigged;
extern std::atomic<int64_t> inUseAttachmentUnRigged;
#endif
// Note if changing these, they should correspond with the log range of the correpsonding sliders
constexpr U64 ART_UNLIMITED_NANOS{50000000};
constexpr U64 ART_MINIMUM_NANOS{100000};
constexpr U64 ART_MIN_ADJUST_UP_NANOS{10000};
constexpr U64 ART_MIN_ADJUST_DOWN_NANOS{10000};
constexpr F32 PREFERRED_DD{180};
extern std::atomic<int64_t> tunedAvatars;
extern U32 targetFPS; // desired FPS
extern U32 renderAvatarMaxART;
extern U64 renderAvatarMaxART_ns;
extern U32 fpsTuningStrategy;
extern U32 lastGlobalPrefChange;
extern std::mutex bufferToggleLock;
extern bool autoTune;
constexpr U64 ART_UNLIMITED{50000};
extern U32 smoothingPeriods; // number of frames to smooth over.
enum class ObjType_t{
OT_GENERAL=0, // Also Unknown. Used for n/a type stats such as scenery
OT_AVATAR,
@ -152,7 +155,8 @@ namespace FSPerfStats
{
return max[getReadBufferIndex()][static_cast<size_t>(otype)][static_cast<size_t>(type)];
}
static void updateSettingsFromRenderCostLimit();
static void updateRenderCostLimitFromSettings();
static void updateAvatarParams();
private:
StatsRecorder();

View File

@ -165,6 +165,8 @@
#endif
// </FS:LO>
#include "fsperfstats.h"// <FS:Beq/> perfstats
// <FS:Zi> FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
#include "llfiltereditor.h"
#include "llviewershadermgr.h"
@ -2877,16 +2879,10 @@ void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box, bool sh
// <FS:Beq> redner time controls
void LLAvatarComplexityControls::updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val)
{
// Called when the IndirectMaxComplexity control changes
// Responsible for fixing the slider label (IndirectMaxComplexityText) and setting RenderAvatarMaxComplexity
auto indirect_value = slider->getValue().asInteger();
gSavedSettings.setU32("FSRenderAvatarMaxART", indirect_value);
LLVOAvatar::sRenderTimeLimit_ns = indirect_value * 1000;
setRenderTimeText(indirect_value, value_label, short_val);
setRenderTimeText((F32)(FSPerfStats::renderAvatarMaxART_ns/1000), value_label, short_val);
}
void LLAvatarComplexityControls::setRenderTimeText(U32 value, LLTextBox* text_box, bool short_val)
void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val)
{
if (0 == value)
{
@ -2894,7 +2890,7 @@ void LLAvatarComplexityControls::setRenderTimeText(U32 value, LLTextBox* text_bo
}
else
{
text_box->setText(llformat("%u", value));
text_box->setText(llformat("%.0f", value));
}
}
// </FS:Beq>

View File

@ -481,7 +481,7 @@ class LLAvatarComplexityControls
static void setText(U32 value, LLTextBox* text_box, bool short_val = false);
// <FS:Beq> for render time support
static void updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val = false);
static void setRenderTimeText(U32 value, LLTextBox* text_box, bool short_val = false);
static void setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val = false);
// </FS:Beq>
static void setIndirectControls();
static void setIndirectMaxNonImpostors();

View File

@ -1071,21 +1071,15 @@ void handleAutoTuneFPSChanged(const LLSD& newValue)
{
const auto newval = gSavedSettings.getBOOL("FSAutoTuneFPS");
FSPerfStats::autoTune = newval;
if(gSavedSettings.getU32("FSRenderAvatarMaxART") == 0)
if(newval && FSPerfStats::renderAvatarMaxART_ns == 0) // If we've enabled autotune we override "unlimited" to max
{
gSavedSettings.setU32("FSRenderAvatarMaxART",50000);
gSavedSettings.setF32("FSRenderAvatarMaxART",log10(FSPerfStats::ART_UNLIMITED_NANOS-1000));//triggers callback to update static var
}
}
void handleRenderAvatarMaxARTChanged(const LLSD& newValue)
{
const auto newval = gSavedSettings.getU32("FSRenderAvatarMaxART");
FSPerfStats::renderAvatarMaxART = newval;
}
void handlePerfSmoothingPeriodsChanged(const LLSD& newValue)
{
const auto newval = gSavedSettings.getU32("FSPerfFloaterSmoothingPeriods");
FSPerfStats::smoothingPeriods = newval;
FSPerfStats::StatsRecorder::updateRenderCostLimitFromSettings();
}
void handleFPSTuningStrategyChanged(const LLSD& newValue)
{
@ -1358,7 +1352,6 @@ void settings_setup_listeners()
gSavedSettings.getControl("FSTargetFPS")->getSignal()->connect(boost::bind(&handleTargetFPSChanged, _2));
gSavedSettings.getControl("FSAutoTuneFPS")->getSignal()->connect(boost::bind(&handleAutoTuneFPSChanged, _2));
gSavedSettings.getControl("FSRenderAvatarMaxART")->getSignal()->connect(boost::bind(&handleRenderAvatarMaxARTChanged, _2));
gSavedSettings.getControl("FSRenderAvatarMaxART")->getSignal()->connect(boost::bind(&handlePerfSmoothingPeriodsChanged, _2));
gSavedSettings.getControl("FSTuningFPSStrategy")->getSignal()->connect(boost::bind(&handleFPSTuningStrategyChanged, _2));
gSavedSettings.getControl("FSPerfStatsCaptureEnabled")->getSignal()->connect(boost::bind(&handlePerformanceStatsEnabledChanged, _2));
// </FS:Beq>

View File

@ -602,7 +602,6 @@ bool LLVOAvatar::sLimitNonImpostors = false; // True unless RenderAvatarMaxNonIm
F32 LLVOAvatar::sRenderDistance = 256.f;
S32 LLVOAvatar::sNumVisibleAvatars = 0;
S32 LLVOAvatar::sNumLODChangesThisFrame = 0;
U64 LLVOAvatar::sRenderTimeLimit_ns {0}; // <FS:Beq/> time limit used for render time control
// const LLUUID LLVOAvatar::sStepSoundOnLand("e8af4a28-aa83-4310-a7c4-c047e15ea0df"); - <FS:PP> Commented out for FIRE-3169: Option to change the default footsteps sound
const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] =
{
@ -4704,7 +4703,6 @@ void LLVOAvatar::computeUpdatePeriod()
bool visually_muted = isVisuallyMuted();
bool slow = isTooSlowWithoutShadows();// <FS:Beq/> the geometry alone is forcing this to be slow so we must imposter
if (mDrawable.notNull()
&& slow
&& isVisible()
&& (!isSelf() || visually_muted)
&& !isUIAvatar()
@ -9186,8 +9184,8 @@ void LLVOAvatar::updateTooSlow()
render_time_raw = mRenderTime;
render_geom_time_raw = mGeomTime;
}
if( (LLVOAvatar::sRenderTimeLimit_ns > 0) &&
(FSPerfStats::raw_to_ns(render_time_raw) >= LLVOAvatar::sRenderTimeLimit_ns) )
if( (FSPerfStats::renderAvatarMaxART_ns > 0) &&
(FSPerfStats::raw_to_ns(render_time_raw) >= FSPerfStats::renderAvatarMaxART_ns) )
{
if( !mTooSlow )
{
@ -9199,7 +9197,7 @@ void LLVOAvatar::updateTooSlow()
mTooSlow = true;
}
// LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") mLastART too high = " << FSPerfStats::raw_to_ns(render_time_raw) << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL;
mTooSlowWithoutShadows = (FSPerfStats::raw_to_ns(render_geom_time_raw) >= LLVOAvatar::sRenderTimeLimit_ns);
mTooSlowWithoutShadows = (FSPerfStats::raw_to_ns(render_geom_time_raw) >= FSPerfStats::renderAvatarMaxART_ns);
}
else
{
@ -11525,6 +11523,7 @@ BOOL LLVOAvatar::shouldImpostor(const F32 rank_factor)
return true;
}
// <FS:Beq> render time handling using tooSlow()
// return sLimitNonImpostors && (mVisibilityRank > sMaxNonImpostors * rank_factor);
static LLCachedControl<bool> render_jellys_As_imposters(gSavedSettings, "RenderJellyDollsAsImpostors");
if (isTooSlowWithoutShadows() && render_jellys_As_imposters)

View File

@ -32,7 +32,8 @@
function="Avatar.Extended" parameter="inspect"/>
</menu_item_call>
<menu_item_call
label="Cam to Avatar"
label="Zoom to Avatar"
tool_tip="move camera to view this avatar."
name="zoom">
<menu_item_call.on_click
function="Avatar.Extended" parameter="zoom"/>

View File

@ -106,14 +106,14 @@ top="0">
tool_tip="Controls when a visually complex avatar is considered to be taking too long to render (unit: microseconds)"
follows="left|top"
height="16"
initial_value="10000"
increment="10"
initial_value="4.7"
increment="0.01"
label="Maximum render time (μs)"
text_color="White"
label_width="165"
layout="topleft"
min_val="0"
max_val="50000"
min_val="2"
max_val="4.7"
name="FSRenderAvatarMaxART"
show_text="false"
left_delta="-304"

View File

@ -510,6 +510,6 @@ help you find the right balance.
layout="topleft">
<button.init_callback
function="Button.SetFloaterToggle"
parameter="phototools_camera"/>
parameter="phototools"/>
</button>
</panel>