FIRE-31326 - Fix crash thread contention crash

Crash caused by DD stepping and AutoTune both hacking the RenderFarClip. Added a proxy tunables structure to allow the main thread to tweak the tunables while the work is still done on the perf thread.
master
Beq 2022-01-30 15:48:16 +00:00
parent 5b1282d35e
commit 105f20b055
5 changed files with 49 additions and 16 deletions

2
.gitignore vendored
View File

@ -111,3 +111,5 @@ compile_commands.json
# ignore tracy for now
indra/tracy
firestorm.code-workspace
.cache/clangd/index/

View File

@ -49,11 +49,12 @@ namespace FSPerfStats
std::atomic<int64_t> tunedAvatars{0};
U32 targetFPS; // desired FPS
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};
Tunables tunables;
std::atomic<int> StatsRecorder::writeBuffer{0};
bool StatsRecorder::collectionEnabled{true};
LLUUID StatsRecorder::focusAv{LLUUID::null};
@ -61,6 +62,14 @@ namespace FSPerfStats
std::array<StatsRecorder::StatsSummaryArray,2> StatsRecorder::max{ {} };
std::array<StatsRecorder::StatsSummaryArray,2> StatsRecorder::sum{ {} };
void Tunables::applyUpdates()
{
assert_main_thread();
if( tuningFlag & NonImposters ){ gSavedSettings.setU32("IndirectMaxNonImpostors", nonImposters); };
if( tuningFlag & ReflectionDetail ){ gSavedSettings.setS32("RenderReflectionDetail", reflectionDetail); };
if( tuningFlag & FarClip ){ gSavedSettings.setF32("RenderFarClip", farClip); };
resetChanges();
}
StatsRecorder::StatsRecorder():q(1024*16),t(&StatsRecorder::run)
{
@ -175,7 +184,7 @@ namespace FSPerfStats
sum[writeBuffer][i].fill(0);
}
// and now adjust the visuals.
// and now adjust the proxy vars so that the main thread can adjust the visuals.
if(autoTune)
{
updateAvatarParams();
@ -280,6 +289,7 @@ namespace FSPerfStats
static LLCachedControl<F32> impostorDistance(gSavedSettings, "FSAutoTuneImpostorFarAwayDistance");
static LLCachedControl<bool> impostorDistanceTuning(gSavedSettings, "FSAutoTuneImpostorByDistEnabled");
static LLCachedControl<U32> maxNonImpostors (gSavedSettings, "IndirectMaxNonImpostors");
static LLCachedControl<U32> fpsTuningStrategy (gSavedSettings, "FSTuningFPSStrategy");
if(impostorDistanceTuning)
{
@ -288,7 +298,7 @@ namespace FSPerfStats
auto count = countNearbyAvatars(std::min(drawDistance, impostorDistance));
if( count != maxNonImpostors )
{
gSavedSettings.setU32("IndirectMaxNonImpostors", (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER);
tunables.updateNonImposters( (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER );
LL_DEBUGS("AutoTune") << "There are " << count << "avatars within " << std::min(drawDistance, impostorDistance) << "m of the camera" << LL_ENDL;
}
}
@ -339,13 +349,13 @@ namespace FSPerfStats
// we cannnot do this by avatar adjustment alone.
if((gFrameCount - FSPerfStats::lastGlobalPrefChange) > 10) // give changes a short time to take effect.
{
if(FSPerfStats::fpsTuningStrategy == 1)
if(fpsTuningStrategy == 1)
{
// 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::tunables.updateReflectionDetail(-2);
FSPerfStats::lastGlobalPrefChange = gFrameCount;
return;
}
@ -355,7 +365,7 @@ namespace FSPerfStats
auto new_dd = (drawDistance-10>userMinDrawDistance)?(drawDistance - 10) : userMinDrawDistance;
if(new_dd != drawDistance)
{
gSavedSettings.setF32("RenderFarClip", new_dd);
FSPerfStats::tunables.updateFarClip( new_dd );
FSPerfStats::lastGlobalPrefChange = gFrameCount;
return;
}
@ -404,15 +414,14 @@ namespace FSPerfStats
}
if( drawDistance < userTargetDrawDistance )
{
gSavedSettings.setF32("RenderFarClip", drawDistance + 10.);
FSPerfStats::tunables.updateFarClip( drawDistance + 10. );
}
if( (target_frame_time_raw * 1.5) > tot_frame_time_raw &&
FSPerfStats::tunedAvatars == 0 &&
drawDistance >= userTargetDrawDistance)
{
// 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);
FSPerfStats::tunables.updateReflectionDetail( gSavedSettings.getS32("RenderReflectionDetail") + 1 );
}
}
updateSettingsFromRenderCostLimit();

View File

@ -74,7 +74,6 @@ namespace FSPerfStats
extern std::atomic<int64_t> tunedAvatars;
extern U32 targetFPS; // desired FPS
extern U64 renderAvatarMaxART_ns;
extern U32 fpsTuningStrategy;
extern U32 lastGlobalPrefChange;
extern std::mutex bufferToggleLock;
extern bool autoTune;
@ -116,6 +115,28 @@ namespace FSPerfStats
bool isHUD;
};
struct Tunables
{
static constexpr U32 Nothing{0};
static constexpr U32 NonImposters{1};
static constexpr U32 ReflectionDetail{2};
static constexpr U32 FarClip{4};
U32 tuningFlag{0};
U32 nonImposters;
S32 reflectionDetail;
F32 farClip;
void updateFarClip(F32 nv){farClip=nv; tuningFlag |= FarClip;};
void updateNonImposters(U32 nv){nonImposters=nv; tuningFlag |= NonImposters;};
void updateReflectionDetail(S32 nv){reflectionDetail=nv; tuningFlag |= ReflectionDetail;};
void applyUpdates();
void resetChanges(){tuningFlag=Nothing;};
};
extern Tunables tunables;
class StatsRecorder{
using Queue = moodycamel::BlockingConcurrentQueue<StatsRecord>;
public:

View File

@ -1644,6 +1644,12 @@ bool LLAppViewer::doFrame()
{
// <FS:Beq> Perfstats collection Frame boundary
{
// and now adjust the visuals from previous frame.
if(FSPerfStats::autoTune && FSPerfStats::tunables.tuningFlag != FSPerfStats::Tunables::Nothing)
{
FSPerfStats::tunables.applyUpdates();
}
FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_FRAME);
LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));

View File

@ -1112,11 +1112,7 @@ void handleRenderAvatarMaxARTChanged(const LLSD& newValue)
{
FSPerfStats::StatsRecorder::updateRenderCostLimitFromSettings();
}
void handleFPSTuningStrategyChanged(const LLSD& newValue)
{
const auto newval = gSavedSettings.getU32("FSTuningFPSStrategy");
FSPerfStats::fpsTuningStrategy = newval;
}
void handlePerformanceStatsEnabledChanged(const LLSD& newValue)
{
const auto newval = gSavedSettings.getBOOL("FSPerfStatsCaptureEnabled");
@ -1383,7 +1379,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("FSTuningFPSStrategy")->getSignal()->connect(boost::bind(&handleFPSTuningStrategyChanged, _2));
gSavedSettings.getControl("FSPerfStatsCaptureEnabled")->getSignal()->connect(boost::bind(&handlePerformanceStatsEnabledChanged, _2));
// </FS:Beq>
}