Merge branch 'DRTVWR-559' of https://github.com/secondlife/viewer
# Conflicts: # indra/llaudio/llaudiodecodemgr.cpp # indra/llwindow/llwindowwin32.cpp # indra/newview/llperfstats.cpp # indra/newview/llperfstats.h # indra/newview/llvoavatar.cpp # indra/newview/llvoavatar.h # indra/newview/pipeline.cppmaster
commit
8e9b3a8f37
|
|
@ -1410,6 +1410,7 @@ Sovereign Engineer
|
|||
SL-18497
|
||||
SL-18525
|
||||
SL-18534
|
||||
SL-19690
|
||||
SpacedOut Frye
|
||||
VWR-34
|
||||
VWR-45
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
|
|||
if (DARWIN)
|
||||
# test binaries always need to be signed for local development
|
||||
set_target_properties(PROJECT_${project}_TEST_${name}
|
||||
PROPERTIES
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-")
|
||||
endif ()
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
|
|||
# test binaries always need to be signed for local development
|
||||
set_target_properties(INTEGRATION_TEST_${testname}
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-")
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-")
|
||||
endif ()
|
||||
|
||||
# Add link deps to the executable
|
||||
|
|
|
|||
|
|
@ -612,43 +612,40 @@ void LLAudioDecodeMgr::Impl::startMoreDecodes()
|
|||
|
||||
// Kick off a decode
|
||||
mDecodes[decode_id] = LLPointer<LLVorbisDecodeState>(NULL);
|
||||
try
|
||||
{
|
||||
main_queue->postTo(
|
||||
general_queue,
|
||||
[decode_id]() // Work done on general queue
|
||||
bool posted = main_queue->postTo(
|
||||
general_queue,
|
||||
[decode_id]() // Work done on general queue
|
||||
{
|
||||
LLPointer<LLVorbisDecodeState> decode_state = beginDecodingAndWritingAudio(decode_id);
|
||||
|
||||
if (!decode_state)
|
||||
{
|
||||
LLPointer<LLVorbisDecodeState> decode_state = beginDecodingAndWritingAudio(decode_id);
|
||||
if (gAudiop)
|
||||
gAudiop->markSoundCorrupt(decode_id);
|
||||
|
||||
if (!decode_state)
|
||||
{
|
||||
if (gAudiop)
|
||||
gAudiop->markSoundCorrupt(decode_id);
|
||||
|
||||
// Audio decode has errored
|
||||
return decode_state;
|
||||
}
|
||||
|
||||
// Disk write of decoded audio is now in progress off-thread
|
||||
// Audio decode has errored
|
||||
return decode_state;
|
||||
},
|
||||
[decode_id, this](LLPointer<LLVorbisDecodeState> decode_state) // Callback to main thread
|
||||
mutable {
|
||||
if (!gAudiop)
|
||||
{
|
||||
// There is no LLAudioEngine anymore. This might happen if
|
||||
// an audio decode is enqueued just before shutdown.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we can be certain that the pointer to "this"
|
||||
// is valid because the lifetime of "this" is dependent upon
|
||||
// the lifetime of gAudiop.
|
||||
// Disk write of decoded audio is now in progress off-thread
|
||||
return decode_state;
|
||||
},
|
||||
[decode_id, this](LLPointer<LLVorbisDecodeState> decode_state) // Callback to main thread
|
||||
mutable {
|
||||
if (!gAudiop)
|
||||
{
|
||||
// There is no LLAudioEngine anymore. This might happen if
|
||||
// an audio decode is enqueued just before shutdown.
|
||||
return;
|
||||
}
|
||||
|
||||
enqueueFinishAudio(decode_id, decode_state);
|
||||
});
|
||||
}
|
||||
catch (const LLThreadSafeQueueInterrupt&)
|
||||
// At this point, we can be certain that the pointer to "this"
|
||||
// is valid because the lifetime of "this" is dependent upon
|
||||
// the lifetime of gAudiop.
|
||||
|
||||
enqueueFinishAudio(decode_id, decode_state);
|
||||
});
|
||||
if (! posted)
|
||||
{
|
||||
// Shutdown
|
||||
// Consider making processQueue() do a cleanup instead
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ S32 LLQueuedThread::updateQueue(F32 max_time_ms)
|
|||
// schedule a call to threadedUpdate for every call to updateQueue
|
||||
if (!isQuitting())
|
||||
{
|
||||
mRequestQueue.postIfOpen([=]()
|
||||
mRequestQueue.post([=]()
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qt - update");
|
||||
mIdleThread = false;
|
||||
|
|
|
|||
|
|
@ -161,12 +161,7 @@ bool LL::WorkQueue::done()
|
|||
return mQueue.done();
|
||||
}
|
||||
|
||||
void LL::WorkQueue::post(const Work& callable)
|
||||
{
|
||||
mQueue.push(callable);
|
||||
}
|
||||
|
||||
bool LL::WorkQueue::postIfOpen(const Work& callable)
|
||||
bool LL::WorkQueue::post(const Work& callable)
|
||||
{
|
||||
return mQueue.pushIfOpen(callable);
|
||||
}
|
||||
|
|
@ -215,26 +210,16 @@ bool LL::WorkSchedule::done()
|
|||
return mQueue.done();
|
||||
}
|
||||
|
||||
void LL::WorkSchedule::post(const Work& callable)
|
||||
bool LL::WorkSchedule::post(const Work& callable)
|
||||
{
|
||||
// Use TimePoint::clock::now() instead of TimePoint's representation of
|
||||
// the epoch because this WorkSchedule may contain a mix of past-due
|
||||
// TimedWork items and TimedWork items scheduled for the future. Sift this
|
||||
// new item into the correct place.
|
||||
post(callable, TimePoint::clock::now());
|
||||
return post(callable, TimePoint::clock::now());
|
||||
}
|
||||
|
||||
void LL::WorkSchedule::post(const Work& callable, const TimePoint& time)
|
||||
{
|
||||
mQueue.push(TimedWork(time, callable));
|
||||
}
|
||||
|
||||
bool LL::WorkSchedule::postIfOpen(const Work& callable)
|
||||
{
|
||||
return postIfOpen(callable, TimePoint::clock::now());
|
||||
}
|
||||
|
||||
bool LL::WorkSchedule::postIfOpen(const Work& callable, const TimePoint& time)
|
||||
bool LL::WorkSchedule::post(const Work& callable, const TimePoint& time)
|
||||
{
|
||||
return mQueue.pushIfOpen(TimedWork(time, callable));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,13 +83,10 @@ namespace LL
|
|||
|
||||
/*---------------------- fire and forget API -----------------------*/
|
||||
|
||||
/// fire-and-forget
|
||||
virtual void post(const Work&) = 0;
|
||||
|
||||
/**
|
||||
* post work, unless the queue is closed before we can post
|
||||
*/
|
||||
virtual bool postIfOpen(const Work&) = 0;
|
||||
virtual bool post(const Work&) = 0;
|
||||
|
||||
/**
|
||||
* post work, unless the queue is full
|
||||
|
|
@ -247,13 +244,10 @@ namespace LL
|
|||
|
||||
/*---------------------- fire and forget API -----------------------*/
|
||||
|
||||
/// fire-and-forget
|
||||
void post(const Work&) override;
|
||||
|
||||
/**
|
||||
* post work, unless the queue is closed before we can post
|
||||
*/
|
||||
bool postIfOpen(const Work&) override;
|
||||
bool post(const Work&) override;
|
||||
|
||||
/**
|
||||
* post work, unless the queue is full
|
||||
|
|
@ -320,22 +314,16 @@ namespace LL
|
|||
|
||||
/*---------------------- fire and forget API -----------------------*/
|
||||
|
||||
/// fire-and-forget
|
||||
void post(const Work& callable) override;
|
||||
|
||||
/// fire-and-forget, but at a particular (future?) time
|
||||
void post(const Work& callable, const TimePoint& time);
|
||||
|
||||
/**
|
||||
* post work, unless the queue is closed before we can post
|
||||
*/
|
||||
bool postIfOpen(const Work& callable) override;
|
||||
bool post(const Work& callable) override;
|
||||
|
||||
/**
|
||||
* post work for a particular time, unless the queue is closed before
|
||||
* we can post
|
||||
*/
|
||||
bool postIfOpen(const Work& callable, const TimePoint& time);
|
||||
bool post(const Work& callable, const TimePoint& time);
|
||||
|
||||
/**
|
||||
* post work, unless the queue is full
|
||||
|
|
@ -356,7 +344,7 @@ namespace LL
|
|||
* an LLCond variant, e.g. LLOneShotCond or LLBoolCond.
|
||||
*/
|
||||
template <typename Rep, typename Period, typename CALLABLE>
|
||||
void postEvery(const std::chrono::duration<Rep, Period>& interval,
|
||||
bool postEvery(const std::chrono::duration<Rep, Period>& interval,
|
||||
CALLABLE&& callable);
|
||||
|
||||
private:
|
||||
|
|
@ -417,15 +405,10 @@ namespace LL
|
|||
// move-only callable; but naturally this statement must be
|
||||
// the last time we reference this instance, which may become
|
||||
// moved-from.
|
||||
try
|
||||
{
|
||||
auto target{ std::dynamic_pointer_cast<WorkSchedule>(mTarget.lock()) };
|
||||
target->post(std::move(*this), mStart);
|
||||
}
|
||||
catch (const Closed&)
|
||||
{
|
||||
// Once this queue is closed, oh well, just stop
|
||||
}
|
||||
auto target{ std::dynamic_pointer_cast<WorkSchedule>(mTarget.lock()) };
|
||||
// Discard bool return: once this queue is closed, oh well,
|
||||
// just stop
|
||||
target->post(std::move(*this), mStart);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -437,7 +420,7 @@ namespace LL
|
|||
};
|
||||
|
||||
template <typename Rep, typename Period, typename CALLABLE>
|
||||
void WorkSchedule::postEvery(const std::chrono::duration<Rep, Period>& interval,
|
||||
bool WorkSchedule::postEvery(const std::chrono::duration<Rep, Period>& interval,
|
||||
CALLABLE&& callable)
|
||||
{
|
||||
if (interval.count() <= 0)
|
||||
|
|
@ -454,7 +437,7 @@ namespace LL
|
|||
// Instantiate and post a suitable BackJack, binding a weak_ptr to
|
||||
// self, the current time, the desired interval and the desired
|
||||
// callable.
|
||||
post(
|
||||
return post(
|
||||
BackJack<Rep, Period, CALLABLE>(
|
||||
getWeak(), TimePoint::clock::now(), interval, std::move(callable)));
|
||||
}
|
||||
|
|
@ -516,7 +499,7 @@ namespace LL
|
|||
// Here we believe target WorkQueue still exists. Post to it a
|
||||
// lambda that packages our callable, our callback and a weak_ptr
|
||||
// to this originating WorkQueue.
|
||||
tptr->post(
|
||||
return tptr->post(
|
||||
[reply = super::getWeak(),
|
||||
callable = std::move(callable),
|
||||
callback = std::move(callback)]
|
||||
|
|
@ -547,9 +530,6 @@ namespace LL
|
|||
},
|
||||
// if caller passed a TimePoint, pass it along to post()
|
||||
std::forward<ARGS>(args)...);
|
||||
|
||||
// looks like we were able to post()
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename... ARGS>
|
||||
|
|
@ -560,18 +540,9 @@ namespace LL
|
|||
auto tptr = target.lock();
|
||||
if (tptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
tptr->post(std::forward<ARGS>(args)...);
|
||||
// we were able to post()
|
||||
return true;
|
||||
}
|
||||
catch (const Closed&)
|
||||
{
|
||||
// target WorkQueue still exists, but is Closed
|
||||
}
|
||||
return tptr->post(std::forward<ARGS>(args)...);
|
||||
}
|
||||
// either target no longer exists, or its WorkQueue is Closed
|
||||
// target no longer exists
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -583,7 +554,7 @@ namespace LL
|
|||
auto operator()(WorkQueueBase* self, CALLABLE&& callable, ARGS&&... args)
|
||||
{
|
||||
LLCoros::Promise<RETURNTYPE> promise;
|
||||
self->post(
|
||||
bool posted = self->post(
|
||||
// We dare to bind a reference to Promise because it's
|
||||
// specifically designed for cross-thread communication.
|
||||
[&promise, callable = std::move(callable)]()
|
||||
|
|
@ -600,6 +571,10 @@ namespace LL
|
|||
},
|
||||
// if caller passed a TimePoint, pass it to post()
|
||||
std::forward<ARGS>(args)...);
|
||||
if (! posted)
|
||||
{
|
||||
LLTHROW(WorkQueueBase::Closed());
|
||||
}
|
||||
auto future{ LLCoros::getFuture(promise) };
|
||||
// now, on the calling thread, wait for that result
|
||||
LLCoros::TempStatus st("waiting for WorkQueue::waitForResult()");
|
||||
|
|
@ -615,7 +590,7 @@ namespace LL
|
|||
void operator()(WorkQueueBase* self, CALLABLE&& callable, ARGS&&... args)
|
||||
{
|
||||
LLCoros::Promise<void> promise;
|
||||
self->post(
|
||||
bool posted = self->post(
|
||||
// &promise is designed for cross-thread access
|
||||
[&promise, callable = std::move(callable)]()
|
||||
mutable {
|
||||
|
|
@ -631,6 +606,10 @@ namespace LL
|
|||
},
|
||||
// if caller passed a TimePoint, pass it to post()
|
||||
std::forward<ARGS>(args)...);
|
||||
if (! posted)
|
||||
{
|
||||
LLTHROW(WorkQueueBase::Closed());
|
||||
}
|
||||
auto future{ LLCoros::getFuture(promise) };
|
||||
// block until set_value()
|
||||
LLCoros::TempStatus st("waiting for void WorkQueue::waitForResult()");
|
||||
|
|
|
|||
|
|
@ -93,13 +93,18 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(
|
|||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
|
||||
// Instantiate the ImageRequest right in the lambda, why not?
|
||||
mThreadPool->getQueue().post(
|
||||
bool posted = mThreadPool->getQueue().post(
|
||||
[req = ImageRequest(image, discard, needs_aux, responder)]
|
||||
() mutable
|
||||
{
|
||||
auto done = req.processRequest();
|
||||
req.finishRequest(done);
|
||||
});
|
||||
if (! posted)
|
||||
{
|
||||
LL_DEBUGS() << "Tried to start decoding on shutdown" << LL_ENDL;
|
||||
// should this return 0?
|
||||
}
|
||||
|
||||
// It's important to our consumer (LLTextureFetchWorker) that we return a
|
||||
// nonzero handle. It is NOT important that the nonzero handle be unique:
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ public:
|
|||
template <typename CALLABLE>
|
||||
bool post(CALLABLE&& func)
|
||||
{
|
||||
return getQueue().postIfOpen(std::forward<CALLABLE>(func));
|
||||
return getQueue().post(std::forward<CALLABLE>(func));
|
||||
}
|
||||
|
||||
void run() override;
|
||||
|
|
|
|||
|
|
@ -373,16 +373,10 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
|
|||
template <typename CALLABLE>
|
||||
void post(CALLABLE&& func)
|
||||
{
|
||||
try
|
||||
{
|
||||
LL_DEBUGS("Window") << "post( callable ) to work queue" << LL_ENDL; // <FS:Beq/> extra debug for threaded window handler
|
||||
getQueue().post(std::forward<CALLABLE>(func));
|
||||
}
|
||||
catch (const LLThreadSafeQueueInterrupt&)
|
||||
{
|
||||
// Shutdown timing is tricky. The main thread can end up trying
|
||||
// to post a cursor position after having closed the WorkQueue.
|
||||
}
|
||||
// Ignore bool return. Shutdown timing is tricky: the main thread can
|
||||
// end up trying to post a cursor position after having closed the
|
||||
// WorkQueue.
|
||||
getQueue().post(std::forward<CALLABLE>(func));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2345,13 +2339,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
ASSERT_WINDOW_THREAD();
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
|
||||
|
||||
LL_DEBUGS("Window") << "mainWindowProc(" << std::hex << h_wnd
|
||||
<< ", " << u_msg
|
||||
<< ", " << w_param << ")" << std::dec << LL_ENDL;
|
||||
|
||||
if (u_msg == WM_POST_FUNCTION_)
|
||||
{
|
||||
LL_DEBUGS("Window") << "WM_POST_FUNCTION_" << LL_ENDL;
|
||||
// from LLWindowWin32Thread::Post()
|
||||
// Cast l_param back to the pointer to the heap FuncType
|
||||
// allocated by Post(). Capture in unique_ptr so we'll delete
|
||||
|
|
@ -2398,8 +2387,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
case WM_DEVICECHANGE:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE");
|
||||
LL_INFOS("Window") << " WM_DEVICECHANGE: wParam=" << w_param
|
||||
<< "; lParam=" << l_param << LL_ENDL;
|
||||
if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL)
|
||||
{
|
||||
WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp));
|
||||
|
|
@ -2461,13 +2448,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
{
|
||||
// This message should be sent whenever the app gains or loses focus.
|
||||
BOOL activating = (BOOL)w_param;
|
||||
BOOL minimized = window_imp->getMinimized();
|
||||
|
||||
LL_INFOS("Window") << "WINDOWPROC ActivateApp "
|
||||
<< " activating " << S32(activating)
|
||||
<< " minimized " << S32(minimized)
|
||||
<< " fullscreen " << S32(window_imp->mFullscreen)
|
||||
<< LL_ENDL;
|
||||
|
||||
if (window_imp->mFullscreen)
|
||||
{
|
||||
|
|
@ -2502,20 +2482,10 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
// Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE
|
||||
BOOL activating = (LOWORD(w_param) != WA_INACTIVE);
|
||||
|
||||
BOOL minimized = BOOL(HIWORD(w_param));
|
||||
|
||||
if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor)
|
||||
{
|
||||
window_imp->interruptLanguageTextInput();
|
||||
}
|
||||
|
||||
// JC - I'm not sure why, but if we don't report that we handled the
|
||||
// WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work
|
||||
// properly when we run fullscreen.
|
||||
LL_INFOS("Window") << "WINDOWPROC Activate "
|
||||
<< " activating " << S32(activating)
|
||||
<< " minimized " << S32(minimized)
|
||||
<< LL_ENDL;
|
||||
});
|
||||
|
||||
break;
|
||||
|
|
@ -2593,13 +2563,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
window_imp->mRawWParam = w_param;
|
||||
window_imp->mRawLParam = l_param;
|
||||
|
||||
{
|
||||
LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN "
|
||||
<< " key " << S32(w_param)
|
||||
<< LL_ENDL;
|
||||
|
||||
gKeyboard->handleKeyDown(w_param, mask);
|
||||
}
|
||||
gKeyboard->handleKeyDown(w_param, mask);
|
||||
});
|
||||
if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress
|
||||
break;
|
||||
|
|
@ -2619,11 +2583,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
window_imp->mRawLParam = l_param;
|
||||
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER);
|
||||
|
||||
LL_INFOS("Window") << "Debug WindowProc WM_KEYUP "
|
||||
<< " key " << S32(w_param)
|
||||
<< LL_ENDL;
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYUP");
|
||||
gKeyboard->handleKeyUp(w_param, mask);
|
||||
}
|
||||
});
|
||||
|
|
@ -2633,7 +2593,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
case WM_IME_SETCONTEXT:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_SETCONTEXT");
|
||||
LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL;
|
||||
if (LLWinImm::isAvailable() && window_imp->mPreeditor)
|
||||
{
|
||||
l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW;
|
||||
|
|
@ -2644,7 +2603,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
case WM_IME_STARTCOMPOSITION:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_STARTCOMPOSITION");
|
||||
LL_INFOS("Window") << "WM_IME_STARTCOMPOSITION" << LL_ENDL;
|
||||
if (LLWinImm::isAvailable() && window_imp->mPreeditor)
|
||||
{
|
||||
WINDOW_IMP_POST(window_imp->handleStartCompositionMessage());
|
||||
|
|
@ -2655,7 +2613,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
case WM_IME_ENDCOMPOSITION:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_ENDCOMPOSITION");
|
||||
LL_INFOS("Window") << "WM_IME_ENDCOMPOSITION" << LL_ENDL;
|
||||
if (LLWinImm::isAvailable() && window_imp->mPreeditor)
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -2665,7 +2622,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
case WM_IME_COMPOSITION:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_COMPOSITION");
|
||||
LL_INFOS("Window") << "WM_IME_COMPOSITION" << LL_ENDL;
|
||||
if (LLWinImm::isAvailable() && window_imp->mPreeditor)
|
||||
{
|
||||
WINDOW_IMP_POST(window_imp->handleCompositionMessage(l_param));
|
||||
|
|
@ -2676,7 +2632,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
case WM_IME_REQUEST:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_REQUEST");
|
||||
LL_INFOS("Window") << "WM_IME_REQUEST" << LL_ENDL;
|
||||
if (LLWinImm::isAvailable() && window_imp->mPreeditor)
|
||||
{
|
||||
LRESULT result;
|
||||
|
|
@ -2705,9 +2660,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
// it is worth trying. The good old WM_CHAR works just fine even for supplementary
|
||||
// characters. We just need to take care of surrogate pairs sent as two WM_CHAR's
|
||||
// by ourselves. It is not that tough. -- Alissa Sabre @ SL
|
||||
LL_INFOS("Window") << "Debug WindowProc WM_CHAR "
|
||||
<< " key " << S32(w_param)
|
||||
<< LL_ENDL;
|
||||
|
||||
// Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE,
|
||||
// we *did* processed the event, so I believe we should not pass it to DefWindowProc...
|
||||
window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE));
|
||||
|
|
@ -3031,21 +2984,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SIZE");
|
||||
window_imp->updateWindowRect();
|
||||
S32 width = S32(LOWORD(l_param));
|
||||
S32 height = S32(HIWORD(l_param));
|
||||
|
||||
|
||||
LL_INFOS("Window");
|
||||
BOOL maximized = (w_param == SIZE_MAXIMIZED);
|
||||
BOOL restored = (w_param == SIZE_RESTORED);
|
||||
BOOL minimized = (w_param == SIZE_MINIMIZED);
|
||||
|
||||
LL_CONT << "WINDOWPROC Size "
|
||||
<< width << "x" << height
|
||||
<< " max " << S32(maximized)
|
||||
<< " min " << S32(minimized)
|
||||
<< " rest " << S32(restored);
|
||||
LL_ENDL;
|
||||
|
||||
// There's an odd behavior with WM_SIZE that I would call a bug. If
|
||||
// the window is maximized, and you call MoveWindow() with a size smaller
|
||||
|
|
@ -3111,7 +3049,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
case WM_SETFOCUS:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETFOCUS");
|
||||
LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL;
|
||||
|
||||
// <FS:Ansariel> Stop flashing when we gain focus
|
||||
if (window_imp->mWindowHandle)
|
||||
|
|
@ -3133,7 +3070,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
case WM_KILLFOCUS:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KILLFOCUS");
|
||||
LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL;
|
||||
WINDOW_IMP_POST(window_imp->mCallbacks->handleFocusLost(window_imp));
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3254,7 +3190,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
default:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - default");
|
||||
LL_INFOS("Window") << "Unhandled windows message code: 0x" << std::hex << U32(u_msg) << LL_ENDL;
|
||||
LL_DEBUGS("Window") << "Unhandled windows message code: 0x" << std::hex << U32(u_msg) << LL_ENDL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -756,14 +756,7 @@ void FSFloaterPerformance::populateNearbyList()
|
|||
|
||||
row[colno]["column"] = "art_value";
|
||||
row[colno]["type"] = "text";
|
||||
if (is_slow)
|
||||
{
|
||||
row[colno]["value"] = llformat( "%.2f", LLPerfStats::raw_to_us( avatar->getLastART() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
row[colno]["value"] = llformat( "%.2f", render_av_gpu_ms * 1000.f);
|
||||
}
|
||||
row[colno]["value"] = llformat( "%.2f", render_av_gpu_ms * 1000.f);
|
||||
row[colno]["font"]["name"] = "SANSSERIF";
|
||||
row[colno]["width"] = "50";
|
||||
colno++;
|
||||
|
|
|
|||
|
|
@ -5522,6 +5522,8 @@ void LLAppViewer::idle()
|
|||
LLFrameTimer::updateFrameTime();
|
||||
LLFrameTimer::updateFrameCount();
|
||||
LLEventTimer::updateClass();
|
||||
LLPerfStats::updateClass();
|
||||
|
||||
// LLApp::stepFrame() performs the above three calls plus mRunner.run().
|
||||
// Not sure why we don't call stepFrame() here, except that LLRunner seems
|
||||
// completely redundant with LLEventTimer.
|
||||
|
|
|
|||
|
|
@ -349,15 +349,18 @@ public:
|
|||
void resetDrawOrders() { }
|
||||
|
||||
static void applyModelMatrix(const LLDrawInfo& params);
|
||||
virtual void pushBatches(U32 type, bool texture = true, bool batch_textures = false);
|
||||
virtual void pushRiggedBatches(U32 type, bool texture = true, bool batch_textures = false);
|
||||
// Use before a non-GLTF batch if it is interleaved with GLTF batches that share the same shader
|
||||
static void resetGLTFTextureTransform();
|
||||
void pushBatches(U32 type, bool texture = true, bool batch_textures = false);
|
||||
void pushRiggedBatches(U32 type, bool texture = true, bool batch_textures = false);
|
||||
void pushGLTFBatches(U32 type);
|
||||
void pushGLTFBatch(LLDrawInfo& params);
|
||||
void pushRiggedGLTFBatches(U32 type);
|
||||
void pushRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvatar, U64& lastMeshId);
|
||||
virtual void pushMaskBatches(U32 type, bool texture = true, bool batch_textures = false);
|
||||
virtual void pushRiggedMaskBatches(U32 type, bool texture = true, bool batch_textures = false);
|
||||
virtual void pushBatch(LLDrawInfo& params, bool texture, bool batch_textures = false);
|
||||
void pushMaskBatches(U32 type, bool texture = true, bool batch_textures = false);
|
||||
void pushRiggedMaskBatches(U32 type, bool texture = true, bool batch_textures = false);
|
||||
void pushBatch(LLDrawInfo& params, bool texture, bool batch_textures = false);
|
||||
void pushBumpBatch(LLDrawInfo& params, bool texture, bool batch_textures = false);
|
||||
static bool uploadMatrixPalette(LLDrawInfo& params);
|
||||
static bool uploadMatrixPalette(LLVOAvatar* avatar, LLMeshSkinInfo* skinInfo);
|
||||
virtual void renderGroup(LLSpatialGroup* group, U32 type, bool texture = true);
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
|
|||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
|
||||
|
||||
if ((!LLPipeline::sRenderTransparentWater || gCubeSnapshot) && getType() == LLDrawPool::POOL_ALPHA_PRE_WATER)
|
||||
if (LLPipeline::isWaterClip() && getType() == LLDrawPool::POOL_ALPHA_PRE_WATER)
|
||||
{ // don't render alpha objects on the other side of the water plane if water is opaque
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ static LLGLSLShader* shader = NULL;
|
|||
static S32 cube_channel = -1;
|
||||
static S32 diffuse_channel = -1;
|
||||
static S32 bump_channel = -1;
|
||||
static BOOL shiny = FALSE;
|
||||
|
||||
// Enabled after changing LLViewerTexture::mNeedsCreateTexture to an
|
||||
// LLAtomicBool; this should work just fine, now. HB
|
||||
|
|
@ -201,7 +202,7 @@ void LLStandardBumpmap::destroyGL()
|
|||
LLDrawPoolBump::LLDrawPoolBump()
|
||||
: LLRenderPass(LLDrawPool::POOL_BUMP)
|
||||
{
|
||||
mShiny = FALSE;
|
||||
shiny = FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -350,7 +351,7 @@ void LLDrawPoolBump::beginFullbrightShiny()
|
|||
diffuse_channel = 0;
|
||||
}
|
||||
|
||||
mShiny = TRUE;
|
||||
shiny = TRUE;
|
||||
}
|
||||
|
||||
void LLDrawPoolBump::renderFullbrightShiny()
|
||||
|
|
@ -402,7 +403,7 @@ void LLDrawPoolBump::endFullbrightShiny()
|
|||
|
||||
diffuse_channel = -1;
|
||||
cube_channel = 0;
|
||||
mShiny = FALSE;
|
||||
shiny = FALSE;
|
||||
}
|
||||
|
||||
void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, bool texture = true)
|
||||
|
|
@ -545,7 +546,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
|
|||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP);
|
||||
|
||||
mShiny = TRUE;
|
||||
shiny = TRUE;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
bool rigged = i == 1;
|
||||
|
|
@ -579,11 +580,11 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
|
|||
avatar = params.mAvatar;
|
||||
skin = params.mSkinInfo->mHash;
|
||||
}
|
||||
pushBatch(params, true, false);
|
||||
pushBumpBatch(params, true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
pushBatch(params, true, false);
|
||||
pushBumpBatch(params, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -593,7 +594,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
|
|||
gGL.getTexUnit(0)->activate();
|
||||
}
|
||||
|
||||
mShiny = FALSE;
|
||||
shiny = FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1221,12 +1222,12 @@ void LLDrawPoolBump::pushBumpBatches(U32 type)
|
|||
}
|
||||
}
|
||||
}
|
||||
pushBatch(params, false);
|
||||
pushBumpBatch(params, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLDrawPoolBump::pushBatch(LLDrawInfo& params, bool texture, bool batch_textures)
|
||||
void LLRenderPass::pushBumpBatch(LLDrawInfo& params, bool texture, bool batch_textures)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
|
||||
applyModelMatrix(params);
|
||||
|
|
@ -1247,7 +1248,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, bool texture, bool batch_text
|
|||
{ //not batching textures or batch has only 1 texture -- might need a texture matrix
|
||||
if (params.mTextureMatrix)
|
||||
{
|
||||
if (mShiny)
|
||||
if (shiny)
|
||||
{
|
||||
gGL.getTexUnit(0)->activate();
|
||||
gGL.matrixMode(LLRender::MM_TEXTURE);
|
||||
|
|
@ -1266,7 +1267,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, bool texture, bool batch_text
|
|||
tex_setup = true;
|
||||
}
|
||||
|
||||
if (mShiny && mShaderLevel > 1 && texture)
|
||||
if (shiny && mShaderLevel > 1 && texture)
|
||||
{
|
||||
if (params.mTexture.notNull())
|
||||
{
|
||||
|
|
@ -1284,7 +1285,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, bool texture, bool batch_text
|
|||
|
||||
if (tex_setup)
|
||||
{
|
||||
if (mShiny)
|
||||
if (shiny)
|
||||
{
|
||||
gGL.getTexUnit(0)->activate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ public:
|
|||
LLDrawPoolBump();
|
||||
|
||||
/*virtual*/ void prerender() override;
|
||||
void pushBatch(LLDrawInfo& params, bool texture, bool batch_textures = false) override;
|
||||
|
||||
void pushBumpBatches(U32 type);
|
||||
void renderGroup(LLSpatialGroup* group, U32 type, bool texture) override;
|
||||
|
|
|
|||
|
|
@ -610,13 +610,6 @@ void renderFace(LLDrawable* drawable, LLFace *face)
|
|||
LLVOVolume* vobj = drawable->getVOVolume();
|
||||
if (vobj)
|
||||
{
|
||||
// <FS:Beq> Placeholder - This function emits drawcalls but is only used in one place and not useful for stats.
|
||||
// TODO(Beq) if we need this consider moving it to llSelectMgr loop instead to reduce overhead.
|
||||
// std::unique_ptr<FSPerfStats::RecordAttachmentTime> ratPtr{};
|
||||
// if(vobj->isAttachment())
|
||||
// {
|
||||
// trackAttachments(vobj, LLPipeline::sShadowRender, &ratPtr);
|
||||
// }
|
||||
LLVolume* volume = NULL;
|
||||
|
||||
if (drawable->isState(LLDrawable::RIGGED))
|
||||
|
|
|
|||
|
|
@ -456,15 +456,8 @@ void LLFloaterPerformance::populateNearbyList()
|
|||
|
||||
row[1]["column"] = "complex_value";
|
||||
row[1]["type"] = "text";
|
||||
if (is_slow && !showTunedART)
|
||||
{
|
||||
row[1]["value"] = llformat( "%.f", LLPerfStats::raw_to_us( avatar->getLastART() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// use GPU time in us
|
||||
row[1]["value"] = llformat( "%.f", render_av_gpu_ms * 1000.f);
|
||||
}
|
||||
// use GPU time in us
|
||||
row[1]["value"] = llformat( "%.f", render_av_gpu_ms * 1000.f);
|
||||
row[1]["font"]["name"] = "SANSSERIF";
|
||||
|
||||
row[3]["column"] = "name";
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ extern LLControlGroup gSavedSettings;
|
|||
|
||||
namespace LLPerfStats
|
||||
{
|
||||
// avatar timing metrics in ms (updated once per mainloop iteration)
|
||||
std::atomic<F32> sTotalAvatarTime = 0.f;
|
||||
std::atomic<F32> sAverageAvatarTime = 0.f;
|
||||
std::atomic<F32> sMaxAvatarTime = 0.f;
|
||||
|
||||
// <FS:Beq> extra profiling
|
||||
#ifdef USAGE_TRACKING
|
||||
std::atomic<int64_t> inUse{0};
|
||||
|
|
@ -151,14 +156,12 @@ namespace LLPerfStats
|
|||
resetChanges();
|
||||
}
|
||||
|
||||
StatsRecorder::StatsRecorder():q(1024*16),t(&StatsRecorder::run)
|
||||
StatsRecorder::StatsRecorder():q(1024*16)
|
||||
{
|
||||
// create a queue
|
||||
// create a thread to consume from the queue
|
||||
tunables.initialiseFromSettings();
|
||||
LLPerfStats::cpu_hertz = (F64)LLTrace::BlockTimer::countsPerSecond();
|
||||
LLPerfStats::vsync_max_fps = gViewerWindow->getWindow()->getRefreshRate();
|
||||
t.detach();
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
@ -182,11 +185,13 @@ namespace LLPerfStats
|
|||
// RENDER_MESHREPO,
|
||||
StatType_t::RENDER_IDLE };
|
||||
|
||||
#if 0
|
||||
static constexpr std::initializer_list<StatType_t> avatarStatsToAvg = {
|
||||
StatType_t::RENDER_GEOMETRY,
|
||||
StatType_t::RENDER_SHADOWS,
|
||||
StatType_t::RENDER_COMBINED,
|
||||
StatType_t::RENDER_IDLE };
|
||||
#endif
|
||||
|
||||
// <FS:Beq> restore FPSLimit reporting
|
||||
// if( /*sceneStats[static_cast<size_t>(StatType_t::RENDER_FPSLIMIT)] != 0 ||*/ sceneStats[static_cast<size_t>(StatType_t::RENDER_SLEEP)] != 0 )
|
||||
|
|
@ -212,20 +217,6 @@ namespace LLPerfStats
|
|||
}
|
||||
}
|
||||
|
||||
auto& statsMapAv = statsDoubleBuffer[writeBuffer][static_cast<size_t>(ObjType_t::OT_AVATAR)];
|
||||
for(auto& stat_entry : statsMapAv)
|
||||
{
|
||||
for(auto& stat : avatarStatsToAvg)
|
||||
{
|
||||
auto val = stat_entry.second[static_cast<size_t>(stat)];
|
||||
if(val > SMOOTHING_PERIODS)
|
||||
{
|
||||
auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast<size_t>(ObjType_t::OT_AVATAR)][stat_entry.first][static_cast<size_t>(stat)];
|
||||
stat_entry.second[static_cast<size_t>(stat)] = avg + (val / SMOOTHING_PERIODS) - (avg / SMOOTHING_PERIODS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// swap the buffers
|
||||
if(enabled())
|
||||
{
|
||||
|
|
@ -305,6 +296,37 @@ namespace LLPerfStats
|
|||
}
|
||||
}
|
||||
|
||||
// called once per main loop iteration on main thread
|
||||
void updateClass()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
|
||||
sTotalAvatarTime = LLVOAvatar::getTotalGPURenderTime();
|
||||
sAverageAvatarTime = LLVOAvatar::getAverageGPURenderTime();
|
||||
sMaxAvatarTime = LLVOAvatar::getMaxGPURenderTime();
|
||||
|
||||
auto general = LL::WorkQueue::getInstance("General");
|
||||
|
||||
if (general)
|
||||
{
|
||||
general->post([] { StatsRecorder::update(); });
|
||||
}
|
||||
}
|
||||
|
||||
// called once per main loop iteration on General thread
|
||||
void StatsRecorder::update()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
StatsRecord upd;
|
||||
auto& instance{ StatsRecorder::getInstance() };
|
||||
|
||||
//while (enabled() && !LLApp::isQuitting() && instance.q.tryPop(upd))
|
||||
while (enabled() && !LLApp::isQuitting() && instance.q.try_dequeue(upd))
|
||||
{
|
||||
instance.processUpdate(upd);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
int StatsRecorder::countNearbyAvatars(S32 distance)
|
||||
{
|
||||
|
|
@ -339,6 +361,8 @@ namespace LLPerfStats
|
|||
// static
|
||||
void StatsRecorder::updateAvatarParams()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
|
||||
if(tunables.autoTuneTimeout)
|
||||
{
|
||||
LLPerfStats::lastSleepedFrame = gFrameCount;
|
||||
|
|
@ -392,10 +416,10 @@ namespace LLPerfStats
|
|||
}
|
||||
}
|
||||
|
||||
auto av_render_max_raw = LLPerfStats::StatsRecorder::getMax(ObjType_t::OT_AVATAR, LLPerfStats::StatType_t::RENDER_COMBINED);
|
||||
auto av_render_max_raw = ms_to_raw(sMaxAvatarTime);
|
||||
// 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)
|
||||
auto tot_avatar_time_raw = LLPerfStats::StatsRecorder::getSum(ObjType_t::OT_AVATAR, LLPerfStats::StatType_t::RENDER_COMBINED);
|
||||
auto tot_avatar_time_raw = ms_to_raw(sTotalAvatarTime);
|
||||
|
||||
// The frametime budget we have based on the target FPS selected
|
||||
auto target_frame_time_raw = (U64)llround(LLPerfStats::cpu_hertz / (target_fps == 0 ? 1 : target_fps));
|
||||
|
|
@ -429,7 +453,7 @@ namespace LLPerfStats
|
|||
// if so we've got work to do
|
||||
|
||||
// how much of the frame was spent on non avatar related work?
|
||||
U64 non_avatar_time_raw = tot_frame_time_raw - tot_avatar_time_raw;
|
||||
U64 non_avatar_time_raw = tot_frame_time_raw > tot_avatar_time_raw ? tot_frame_time_raw - tot_avatar_time_raw : 0;
|
||||
|
||||
// If the target frame time < scene time (estimated as non_avatar time)
|
||||
U64 target_avatar_time_raw;
|
||||
|
|
@ -486,7 +510,11 @@ namespace LLPerfStats
|
|||
{
|
||||
new_render_limit_ns = renderAvatarMaxART_ns;
|
||||
}
|
||||
new_render_limit_ns -= LLPerfStats::ART_MIN_ADJUST_DOWN_NANOS;
|
||||
|
||||
if (new_render_limit_ns > LLPerfStats::ART_MIN_ADJUST_DOWN_NANOS)
|
||||
{
|
||||
new_render_limit_ns -= LLPerfStats::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)LLPerfStats::ART_MINIMUM_NANOS);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ namespace LLPerfStats
|
|||
extern std::atomic<int64_t> inUseAttachmentUnRigged;
|
||||
#endif
|
||||
// </FS:Beq>
|
||||
|
||||
// called once per main loop iteration
|
||||
void updateClass();
|
||||
|
||||
// Note if changing these, they should correspond with the log range of the correpsonding sliders
|
||||
static constexpr U64 ART_UNLIMITED_NANOS{50000000};
|
||||
static constexpr U64 ART_MINIMUM_NANOS{100000};
|
||||
|
|
@ -90,7 +94,7 @@ namespace LLPerfStats
|
|||
|
||||
enum class ObjType_t{
|
||||
OT_GENERAL=0, // Also Unknown. Used for n/a type stats such as scenery
|
||||
OT_AVATAR,
|
||||
OT_AVATAR, // <FS:Ansariel> Leave this in for now so I don't have to deal with the bugs in FSFloaterPerformance...
|
||||
OT_COUNT
|
||||
};
|
||||
enum class StatType_t{
|
||||
|
|
@ -186,6 +190,9 @@ namespace LLPerfStats
|
|||
// </FS:Beq>
|
||||
public:
|
||||
|
||||
// called once per main loop iteration on General thread
|
||||
static void update();
|
||||
|
||||
static inline StatsRecorder& getInstance()
|
||||
{
|
||||
static StatsRecorder instance;
|
||||
|
|
@ -269,7 +276,6 @@ namespace LLPerfStats
|
|||
|
||||
auto ot{upd.objType};
|
||||
auto& key{upd.objID};
|
||||
auto& avKey{upd.avID};
|
||||
auto type {upd.statType};
|
||||
auto val {upd.time};
|
||||
// <FS:Beq> markup to support coverage testing on stats collection
|
||||
|
|
@ -286,13 +292,6 @@ namespace LLPerfStats
|
|||
doUpd(key, ot, type,val);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ot == ObjType_t::OT_AVATAR)
|
||||
{
|
||||
// LL_INFOS("perfstats") << "Avatar update:" << LL_ENDL;
|
||||
doUpd(avKey, ot, type, val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void doUpd(const LLUUID& key, ObjType_t ot, StatType_t type, uint64_t val)
|
||||
|
|
@ -321,47 +320,7 @@ namespace LLPerfStats
|
|||
static void toggleBuffer();
|
||||
static void clearStatsBuffers();
|
||||
|
||||
// thread entry
|
||||
static void run()
|
||||
{
|
||||
StatsRecord upd[10];
|
||||
auto & instance {StatsRecorder::getInstance()};
|
||||
LL_PROFILER_SET_THREAD_NAME("PerfStats");
|
||||
|
||||
while( enabled() && !LLApp::isExiting() )
|
||||
{
|
||||
// <FS:Beq> We don't want these queues
|
||||
// auto count = 0;
|
||||
// while (count < 10)
|
||||
// {
|
||||
// if (instance.q.tryPopFor(std::chrono::milliseconds(10), upd[count]))
|
||||
// {
|
||||
// count++;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// //LL_PROFILER_THREAD_BEGIN("PerfStats");
|
||||
|
||||
auto count = instance.q.wait_dequeue_bulk_timed(upd, 10, std::chrono::milliseconds(10));
|
||||
LL_PROFILER_THREAD_BEGIN("PerfStats");
|
||||
// </FS:Beq>
|
||||
if(count)
|
||||
{
|
||||
// LL_INFOS("perfstats") << "processing " << count << " updates." << LL_ENDL;
|
||||
for(auto i =0; i < count; i++)
|
||||
{
|
||||
instance.processUpdate(upd[i]);
|
||||
}
|
||||
}
|
||||
LL_PROFILER_THREAD_END("PerfStats"); // <FS:Beq/>
|
||||
}
|
||||
}
|
||||
|
||||
Queue q;
|
||||
std::thread t;
|
||||
|
||||
~StatsRecorder() = default;
|
||||
StatsRecorder(const StatsRecorder&) = delete;
|
||||
|
|
@ -388,27 +347,27 @@ namespace LLPerfStats
|
|||
// LL_PROFILE_ZONE_COLOR(tracy::Color::Orange);
|
||||
LL_PROFILE_ZONE_COLOR(tracy::Color::Orange);
|
||||
#ifdef USAGE_TRACKING
|
||||
if(stat.objType == FSPerfStats::ObjType_t::OT_ATTACHMENT)
|
||||
if(stat.objType == LLPerfStats::ObjType_t::OT_ATTACHMENT)
|
||||
{
|
||||
LL_PROFILE_PLOT_CONFIG_SQUARE("InUse");
|
||||
LL_PROFILE_PLOT_CONFIG_SQUARE("InUseAttachment");
|
||||
LL_PROFILE_PLOT_CONFIG_SQUARE("InUseAttachmentRigged");
|
||||
LL_PROFILE_PLOT_CONFIG_SQUARE("InUseAttachmentUnRigged");
|
||||
|
||||
if(!stat.isRigged && FSPerfStats::inUseAvatar){LL_PROFILE_ZONE_TEXT("OVERLAP AVATAR",14);}
|
||||
FSPerfStats::inUse++;
|
||||
LL_PROFILE_PLOT("InUse", (int64_t)FSPerfStats::inUse);
|
||||
FSPerfStats::inUseAttachment++;
|
||||
LL_PROFILE_PLOT("InUseAttachment", (int64_t)FSPerfStats::inUseAttachment);
|
||||
if(!stat.isRigged && LLPerfStats::inUseAvatar){LL_PROFILE_ZONE_TEXT("OVERLAP AVATAR",14);}
|
||||
LLPerfStats::inUse++;
|
||||
LL_PROFILE_PLOT("InUse", (int64_t)LLPerfStats::inUse);
|
||||
LLPerfStats::inUseAttachment++;
|
||||
LL_PROFILE_PLOT("InUseAttachment", (int64_t)LLPerfStats::inUseAttachment);
|
||||
if (stat.isRigged)
|
||||
{
|
||||
FSPerfStats::inUseAttachmentRigged++;
|
||||
LL_PROFILE_PLOT("InUseAttachmentRigged", (int64_t)FSPerfStats::inUseAttachmentRigged);
|
||||
LLPerfStats::inUseAttachmentRigged++;
|
||||
LL_PROFILE_PLOT("InUseAttachmentRigged", (int64_t)LLPerfStats::inUseAttachmentRigged);
|
||||
}
|
||||
else
|
||||
{
|
||||
FSPerfStats::inUseAttachmentUnRigged++;
|
||||
LL_PROFILE_PLOT("InUseAttachmentUnRigged", (int64_t)FSPerfStats::inUseAttachmentUnRigged);
|
||||
LLPerfStats::inUseAttachmentUnRigged++;
|
||||
LL_PROFILE_PLOT("InUseAttachmentUnRigged", (int64_t)LLPerfStats::inUseAttachmentUnRigged);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -430,23 +389,6 @@ namespace LLPerfStats
|
|||
// </FS:Beq>
|
||||
};
|
||||
|
||||
template < ObjType_t OD = ObjTypeDiscriminator,
|
||||
std::enable_if_t<OD == ObjType_t::OT_AVATAR> * = nullptr>
|
||||
RecordTime( const LLUUID & av, StatType_t type ):RecordTime<ObjTypeDiscriminator>(std::move(av), LLUUID::null, type)
|
||||
{
|
||||
// <FS:Beq> extra profiling coverage tracking
|
||||
// LL_PROFILE_ZONE_COLOR(tracy::Color::Purple)
|
||||
LL_PROFILE_ZONE_COLOR(tracy::Color::Purple);
|
||||
#ifdef USAGE_TRACKING
|
||||
if(LLPerfStats::inUseAvatar){LL_PROFILE_ZONE_TEXT("OVERLAP AVATAR",14);}
|
||||
FSPerfStats::inUseAvatar++;
|
||||
LL_PROFILE_PLOT("InUseAv", (int64_t)LLPerfStats::inUseAvatar);
|
||||
LLPerfStats::inUse++;
|
||||
LL_PROFILE_PLOT("InUse", (int64_t)LLPerfStats::inUse);
|
||||
#endif
|
||||
// </FS:Beq>
|
||||
};
|
||||
|
||||
~RecordTime()
|
||||
{
|
||||
if(!LLPerfStats::StatsRecorder::enabled())
|
||||
|
|
@ -458,32 +400,32 @@ namespace LLPerfStats
|
|||
|
||||
// <FS:Beq> extra profiling coverage tracking
|
||||
#ifdef USAGE_TRACKING
|
||||
--FSPerfStats::inUse;
|
||||
LL_PROFILE_PLOT("InUse", (int64_t)FSPerfStats::inUse);
|
||||
if (stat.objType == FSPerfStats::ObjType_t::OT_ATTACHMENT)
|
||||
--LLPerfStats::inUse;
|
||||
LL_PROFILE_PLOT("InUse", (int64_t)LLPerfStats::inUse);
|
||||
if (stat.objType == LLPerfStats::ObjType_t::OT_ATTACHMENT)
|
||||
{
|
||||
--FSPerfStats::inUseAttachment;
|
||||
LL_PROFILE_PLOT("InUseAttachment", (int64_t)FSPerfStats::inUseAttachment);
|
||||
--LLPerfStats::inUseAttachment;
|
||||
LL_PROFILE_PLOT("InUseAttachment", (int64_t)LLPerfStats::inUseAttachment);
|
||||
if (stat.isRigged)
|
||||
{
|
||||
--FSPerfStats::inUseAttachmentRigged;
|
||||
LL_PROFILE_PLOT("InUseAttachmentRigged", (int64_t)FSPerfStats::inUseAttachmentRigged);
|
||||
--LLPerfStats::inUseAttachmentRigged;
|
||||
LL_PROFILE_PLOT("InUseAttachmentRigged", (int64_t)LLPerfStats::inUseAttachmentRigged);
|
||||
}
|
||||
else
|
||||
{
|
||||
--FSPerfStats::inUseAttachmentUnRigged;
|
||||
LL_PROFILE_PLOT("InUseAttachmentUnRigged", (int64_t)FSPerfStats::inUseAttachmentUnRigged);
|
||||
--LLPerfStats::inUseAttachmentUnRigged;
|
||||
LL_PROFILE_PLOT("InUseAttachmentUnRigged", (int64_t)LLPerfStats::inUseAttachmentUnRigged);
|
||||
}
|
||||
}
|
||||
if (stat.objType == FSPerfStats::ObjType_t::OT_GENERAL)
|
||||
if (stat.objType == LLPerfStats::ObjType_t::OT_GENERAL)
|
||||
{
|
||||
--FSPerfStats::inUseScene;
|
||||
LL_PROFILE_PLOT("InUseScene", (int64_t)FSPerfStats::inUseScene);
|
||||
--LLPerfStats::inUseScene;
|
||||
LL_PROFILE_PLOT("InUseScene", (int64_t)LLPerfStats::inUseScene);
|
||||
}
|
||||
if( stat.objType == FSPerfStats::ObjType_t::OT_AVATAR )
|
||||
if( stat.objType == LLPerfStats::ObjType_t::OT_AVATAR )
|
||||
{
|
||||
--FSPerfStats::inUseAvatar;
|
||||
LL_PROFILE_PLOT("InUseAv", (int64_t)FSPerfStats::inUseAvatar);
|
||||
--LLPerfStats::inUseAvatar;
|
||||
LL_PROFILE_PLOT("InUseAv", (int64_t)LLPerfStats::inUseAvatar);
|
||||
}
|
||||
#endif
|
||||
// </FS:Beq>
|
||||
|
|
@ -501,13 +443,19 @@ namespace LLPerfStats
|
|||
StatsRecorder::send(std::move(stat));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
inline double raw_to_ns(U64 raw) { return (static_cast<double>(raw) * 1000000000.0) / LLPerfStats::cpu_hertz; };
|
||||
inline double raw_to_us(U64 raw) { return (static_cast<double>(raw) * 1000000.0) / LLPerfStats::cpu_hertz; };
|
||||
inline double raw_to_ms(U64 raw) { return (static_cast<double>(raw) * 1000.0) / LLPerfStats::cpu_hertz; };
|
||||
|
||||
inline U64 ns_to_raw(double ns) { return (U64)(LLPerfStats::cpu_hertz * (ns / 1000000000.0)); }
|
||||
inline U64 us_to_raw(double us) { return (U64)(LLPerfStats::cpu_hertz * (us / 1000000.0)); }
|
||||
inline U64 ms_to_raw(double ms) { return (U64)(LLPerfStats::cpu_hertz * (ms / 1000.0));
|
||||
|
||||
}
|
||||
|
||||
|
||||
using RecordSceneTime = RecordTime<ObjType_t::OT_GENERAL>;
|
||||
using RecordAvatarTime = RecordTime<ObjType_t::OT_AVATAR>;
|
||||
|
||||
};// namespace LLPerfStats
|
||||
|
||||
|
|
|
|||
|
|
@ -478,7 +478,7 @@ void update_statistics()
|
|||
|
||||
auto tot_frame_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FRAME);
|
||||
// cumulative avatar time (includes idle processing, attachments and base av)
|
||||
auto tot_avatar_time_raw = LLPerfStats::StatsRecorder::getSum(LLPerfStats::ObjType_t::OT_AVATAR, LLPerfStats::StatType_t::RENDER_COMBINED);
|
||||
auto tot_avatar_time_raw = LLPerfStats::us_to_raw(LLVOAvatar::getTotalGPURenderTime());
|
||||
// cumulative avatar render specific time (a bit arbitrary as the processing is too.)
|
||||
// auto tot_av_idle_time_raw = LLPerfStats::StatsRecorder::getSum(AvType, LLPerfStats::StatType_t::RENDER_IDLE);
|
||||
// auto tot_avatar_render_time_raw = tot_avatar_time_raw - tot_av_idle_time_raw;
|
||||
|
|
|
|||
|
|
@ -2716,7 +2716,6 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
|
|||
return;
|
||||
}
|
||||
// record time and refresh "tooSlow" status
|
||||
LLPerfStats::RecordAvatarTime T(getID(), LLPerfStats::StatType_t::RENDER_IDLE); // per avatar "idle" time.
|
||||
updateTooSlow();
|
||||
|
||||
static LLCachedControl<bool> disable_all_render_types(gSavedSettings, "DisableAllRenderTypes");
|
||||
|
|
@ -9242,31 +9241,6 @@ bool LLVOAvatar::isTooSlow() const
|
|||
return mTooSlow;
|
||||
}
|
||||
|
||||
// use Avatar Render Time as complexity metric
|
||||
// <FS:Beq> refactor for clarity post LL merge
|
||||
void LLVOAvatar::clearSlowARTCache()
|
||||
{
|
||||
mARTStale = false;
|
||||
mTooSlow = false;
|
||||
mTooSlowWithoutShadows = false;
|
||||
}
|
||||
|
||||
void LLVOAvatar::setSlowARTCache(U64 full_render_time, U64 non_shadow_render_time)
|
||||
{
|
||||
mLastARTUpdateFrame = LLFrameTimer::getFrameCount();
|
||||
mRenderTime = full_render_time;
|
||||
mRenderTimeNoShadows = non_shadow_render_time;
|
||||
mARTStale = false;
|
||||
mTooSlow = true;
|
||||
}
|
||||
// </FS:Beq>
|
||||
// markARTStale - Mark stale and set the frameupdate to now so that we can wait at least one frame to get a revised number.
|
||||
void LLVOAvatar::markARTStale()
|
||||
{
|
||||
mARTStale=true;
|
||||
mLastARTUpdateFrame = LLFrameTimer::getFrameCount();
|
||||
}
|
||||
|
||||
// Udpate Avatar state based on render time
|
||||
void LLVOAvatar::updateTooSlow()
|
||||
{
|
||||
|
|
@ -9278,50 +9252,9 @@ void LLVOAvatar::updateTooSlow()
|
|||
|
||||
// mTooSlow - Is the avatar flagged as being slow (includes shadow time)
|
||||
// mTooSlowWithoutShadows - Is the avatar flagged as being slow even with shadows removed.
|
||||
// mARTStale - the rendertime we have is stale because of an update. We need to force a re-render to re-assess slowness
|
||||
|
||||
if( mARTStale )
|
||||
{
|
||||
if ( LLFrameTimer::getFrameCount() - mLastARTUpdateFrame < 5 )
|
||||
{
|
||||
// LL_INFOS() << this->getFullname() << " marked stale " << LL_ENDL;
|
||||
// we've not had a chance to update yet (allow a few to be certain a full frame has passed)
|
||||
return;
|
||||
}
|
||||
// <FS:Beq> refactor and work out why shadow derendering is no longer working
|
||||
// mARTStale = false;
|
||||
// mTooSlow = false;
|
||||
// mTooSlowWithoutShadows = false;
|
||||
// LL_INFOS() << this->getFullname() << " refreshed ART combined = " << mRenderTime << " @ " << mLastARTUpdateFrame << LL_ENDL;
|
||||
clearSlowARTCache();
|
||||
changed_slow_state = true;
|
||||
// </FS:Beq>
|
||||
}
|
||||
|
||||
// Either we're not stale or we've updated.
|
||||
|
||||
U64 render_time_raw;
|
||||
U64 render_time_no_shadows_raw; // <FS:Beq/> rename as we now include idle time
|
||||
|
||||
if( !mTooSlow )
|
||||
{
|
||||
// we are fully rendered, so we use the live values
|
||||
std::lock_guard<std::mutex> lock{LLPerfStats::bufferToggleLock};
|
||||
render_time_raw = LLPerfStats::StatsRecorder::get(LLPerfStats::ObjType_t::OT_AVATAR, id, LLPerfStats::StatType_t::RENDER_COMBINED);
|
||||
// <FS:Beq> include idle time in total render time
|
||||
// render_geom_time_raw = LLPerfStats::StatsRecorder::get(LLPerfStats::ObjType_t::OT_AVATAR, id, LLPerfStats::StatType_t::RENDER_GEOMETRY);
|
||||
render_time_no_shadows_raw = render_time_raw - LLPerfStats::StatsRecorder::get(LLPerfStats::ObjType_t::OT_AVATAR, id, LLPerfStats::StatType_t::RENDER_SHADOWS);
|
||||
// </FS:Beq>
|
||||
}
|
||||
else
|
||||
{
|
||||
// use the cached values.
|
||||
render_time_raw = mRenderTime;
|
||||
// <FS:Beq> variable name updated to refelect different meaning.
|
||||
//render_geom_time_raw = mGeomTime;
|
||||
render_time_no_shadows_raw = mRenderTimeNoShadows;
|
||||
// <FS:Beq>
|
||||
}
|
||||
|
||||
// get max render time in ms
|
||||
F32 max_art_ms = (F32) (LLPerfStats::renderAvatarMaxART_ns / 1000000.0);
|
||||
|
||||
bool autotune = LLPerfStats::tunables.userAutoTuneEnabled && !mIsControlAvatar && !isSelf();
|
||||
|
||||
|
|
@ -9337,23 +9270,13 @@ void LLVOAvatar::updateTooSlow()
|
|||
}
|
||||
|
||||
bool exceeds_max_ART =
|
||||
((LLPerfStats::renderAvatarMaxART_ns > 0) && (LLPerfStats::raw_to_ns(render_time_raw) >= LLPerfStats::renderAvatarMaxART_ns));
|
||||
((LLPerfStats::renderAvatarMaxART_ns > 0) &&
|
||||
(mGPURenderTime >= max_art_ms)); // NOTE: don't use getGPURenderTime accessor here to avoid "isTooSlow" feedback loop
|
||||
|
||||
if (exceeds_max_ART && !ignore_tune)
|
||||
{
|
||||
if( !mTooSlow ) // if we were previously not slow (with or without shadows.)
|
||||
{
|
||||
// if we weren't capped, we are now
|
||||
// <FS:Beq> refactored "geom" becomes "no shadow"
|
||||
// mLastARTUpdateFrame = LLFrameTimer::getFrameCount();
|
||||
// mRenderTime = render_time_raw;
|
||||
// mGeomTime = render_geom_time_raw;
|
||||
// mARTStale = false;
|
||||
// mTooSlow = true;
|
||||
setSlowARTCache(render_time_raw, render_time_no_shadows_raw);
|
||||
changed_slow_state = true;
|
||||
// </FS:Beq>
|
||||
}
|
||||
mTooSlow = true;
|
||||
|
||||
if(!mTooSlowWithoutShadows) // if we were not previously above the full impostor cap
|
||||
{
|
||||
bool render_friend_or_exception = ( alwaysRenderFriends && LLAvatarTracker::instance().isBuddy( id ) ) ||
|
||||
|
|
@ -9361,9 +9284,7 @@ void LLVOAvatar::updateTooSlow()
|
|||
if( (!isSelf() || allowSelfImpostor) && !render_friend_or_exception )
|
||||
{
|
||||
// Note: slow rendering Friends still get their shadows zapped.
|
||||
// <FS:Beq> changes to support idel and geom in non shadow rendering cost + improved dirty marking
|
||||
// mTooSlowWithoutShadows = (LLPerfStats::raw_to_ns(render_geom_time_raw) >= LLPerfStats::renderAvatarMaxART_ns);
|
||||
mTooSlowWithoutShadows = (LLPerfStats::raw_to_ns(render_time_no_shadows_raw) >= LLPerfStats::renderAvatarMaxART_ns);
|
||||
mTooSlowWithoutShadows = getGPURenderTime()*2.f >= max_art_ms; // NOTE: assumes shadow rendering doubles render time
|
||||
}
|
||||
if(mTooSlowWithoutShadows)
|
||||
{
|
||||
|
|
@ -9376,8 +9297,6 @@ void LLVOAvatar::updateTooSlow()
|
|||
else
|
||||
{
|
||||
// <FS:Beq> better state change flagging
|
||||
// LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") good render time = " << LLPerfStats::raw_to_ns(render_time_raw) << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL;
|
||||
// LL_INFOS() << this->getFullname() << " good render time = " << render_time_ns << " vs ("<< LLPerfStats::renderAvatarMaxART_ns << " set @ " << mLastARTUpdateFrame << ")" << LL_ENDL;
|
||||
if( mTooSlow || mTooSlowWithoutShadows )
|
||||
{
|
||||
changed_slow_state = true;
|
||||
|
|
@ -11965,7 +11884,6 @@ void LLVOAvatar::updateVisualComplexity()
|
|||
LL_DEBUGS("AvatarRender") << "avatar " << getID() << " appearance changed" << LL_ENDL;
|
||||
// Set the cache time to in the past so it's updated ASAP
|
||||
mVisualComplexityStale = true;
|
||||
markARTStale();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -12287,6 +12205,22 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
|
|||
LLSidepanelAppearance::updateAvatarComplexity(mVisualComplexity, item_complexity, temp_item_complexity, body_parts_complexity);
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
|
||||
|
||||
//schedule an update to ART next frame if needed
|
||||
if (LLPerfStats::tunables.userAutoTuneEnabled &&
|
||||
LLPerfStats::tunables.userFPSTuningStrategy != LLPerfStats::TUNE_SCENE_ONLY &&
|
||||
!isVisuallyMuted())
|
||||
{
|
||||
LLUUID id = getID(); // <== use id to make sure this avatar didn't get deleted between frames
|
||||
LL::WorkQueue::getInstance("mainloop")->post([this, id]()
|
||||
{
|
||||
if (gObjectList.findObject(id) != nullptr)
|
||||
{
|
||||
gPipeline.profileAvatar(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -12295,7 +12229,6 @@ void LLVOAvatar::setVisualMuteSettings(VisualMuteSettings set)
|
|||
mVisuallyMuteSetting = set;
|
||||
mNeedsImpostorUpdate = TRUE;
|
||||
mLastImpostorUpdateReason = 7;
|
||||
markARTStale();// <FS:Beq> Force a refresh of the ART to take into account new setting.
|
||||
|
||||
// <FS:Ansariel> [FS Persisted Avatar Render Settings]
|
||||
//LLRenderMuteList::getInstance()->saveVisualMuteSetting(getID(), S32(set));
|
||||
|
|
@ -12678,6 +12611,9 @@ void LLVOAvatar::readProfileQuery(S32 retries)
|
|||
glGetQueryObjectui64v(mGPUTimerQuery, GL_QUERY_RESULT, &time_elapsed);
|
||||
mGPURenderTime = time_elapsed / 1000000.f;
|
||||
mGPUProfilePending = false;
|
||||
|
||||
setDebugText(llformat("%d", (S32)(mGPURenderTime * 1000.f)));
|
||||
|
||||
}
|
||||
else
|
||||
{ // wait until next frame
|
||||
|
|
@ -12690,6 +12626,70 @@ void LLVOAvatar::readProfileQuery(S32 retries)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
F32 LLVOAvatar::getGPURenderTime()
|
||||
{
|
||||
return isVisuallyMuted() ? 0.f : mGPURenderTime;
|
||||
}
|
||||
|
||||
// static
|
||||
F32 LLVOAvatar::getTotalGPURenderTime()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
|
||||
F32 ret = 0.f;
|
||||
|
||||
for (LLCharacter* iter : LLCharacter::sInstances)
|
||||
{
|
||||
LLVOAvatar* inst = (LLVOAvatar*) iter;
|
||||
ret += inst->getGPURenderTime();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
F32 LLVOAvatar::getMaxGPURenderTime()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
|
||||
F32 ret = 0.f;
|
||||
|
||||
for (LLCharacter* iter : LLCharacter::sInstances)
|
||||
{
|
||||
LLVOAvatar* inst = (LLVOAvatar*)iter;
|
||||
ret = llmax(inst->getGPURenderTime(), ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
F32 LLVOAvatar::getAverageGPURenderTime()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
|
||||
F32 ret = 0.f;
|
||||
|
||||
S32 count = 0;
|
||||
|
||||
for (LLCharacter* iter : LLCharacter::sInstances)
|
||||
{
|
||||
LLVOAvatar* inst = (LLVOAvatar*)iter;
|
||||
if (!inst->isTooSlow())
|
||||
{
|
||||
ret += inst->getGPURenderTime();
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
ret /= count;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// <FS:Ansariel> [Legacy Bake]
|
||||
//-----------------------------------------------------------------------------
|
||||
// Legacy baking
|
||||
|
|
|
|||
|
|
@ -324,11 +324,21 @@ public:
|
|||
void readProfileQuery(S32 retries);
|
||||
|
||||
// get the GPU time in ms of rendering this avatar including all attachments
|
||||
// returns -1 if this avatar has not been profiled using gPipeline.profileAvatar
|
||||
F32 getGPURenderTime() { return mGPURenderTime; }
|
||||
// returns 0.f if this avatar has not been profiled using gPipeline.profileAvatar
|
||||
// or the avatar is visually muted
|
||||
F32 getGPURenderTime();
|
||||
|
||||
// get the total GPU render time in ms of all avatars that have been benched
|
||||
static F32 getTotalGPURenderTime();
|
||||
|
||||
// get the max GPU render time in ms of all avatars that have been benched
|
||||
static F32 getMaxGPURenderTime();
|
||||
|
||||
// get the average GPU render time in ms of all avatars that have been benched
|
||||
static F32 getAverageGPURenderTime();
|
||||
|
||||
// get the CPU time in ms of rendering this avatar including all attachments
|
||||
// return -1 if this avatar has not been profiled using gPipeline.mProfileAvatar
|
||||
// return 0.f if this avatar has not been profiled using gPipeline.mProfileAvatar
|
||||
F32 getCPURenderTime() { return mCPURenderTime; }
|
||||
|
||||
|
||||
|
|
@ -419,12 +429,7 @@ public:
|
|||
void logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed);
|
||||
|
||||
void calcMutedAVColor();
|
||||
void markARTStale();
|
||||
// <FS:Beq> refactoring post LL merge
|
||||
void clearSlowARTCache();
|
||||
void setSlowARTCache(U64 full_render_time, U64 geometry_render_time);
|
||||
// </FS:Beq>
|
||||
|
||||
|
||||
protected:
|
||||
LLViewerStats::PhaseMap& getPhases() { return mPhases; }
|
||||
BOOL updateIsFullyLoaded();
|
||||
|
|
@ -445,14 +450,6 @@ private:
|
|||
LLFrameTimer mFullyLoadedTimer;
|
||||
LLFrameTimer mRuthTimer;
|
||||
|
||||
U32 mLastARTUpdateFrame{0};
|
||||
U64 mRenderTime{0};
|
||||
// <FS:Beq> variable name updated to refelect different meaning.
|
||||
//U64 mGeomTime{ 0 };
|
||||
U64 mRenderTimeNoShadows{0};
|
||||
// </FS:Beq>
|
||||
bool mARTStale{true};
|
||||
bool mARTCapped{false};
|
||||
// variables to hold "slowness" status
|
||||
bool mTooSlow{false};
|
||||
bool mTooSlowWithoutShadows{false};
|
||||
|
|
@ -584,11 +581,11 @@ private:
|
|||
// profile results
|
||||
|
||||
// GPU render time in ms
|
||||
F32 mGPURenderTime = -1.f;
|
||||
F32 mGPURenderTime = 0.f;
|
||||
bool mGPUProfilePending = false;
|
||||
|
||||
// CPU render time in ms
|
||||
F32 mCPURenderTime = -1.f;
|
||||
F32 mCPURenderTime = 0.f;
|
||||
|
||||
// the isTooComplex method uses these mutable values to avoid recalculating too frequently
|
||||
// DEPRECATED -- obsolete avatar render cost values
|
||||
|
|
@ -1276,8 +1273,6 @@ public:
|
|||
// COF version of last appearance message received for this av.
|
||||
S32 mLastUpdateReceivedCOFVersion;
|
||||
|
||||
U64 getLastART() const { return mRenderTime; }
|
||||
|
||||
/** Diagnostics
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
|
|
|||
|
|
@ -1956,7 +1956,11 @@ F32 LLWorld::getNearbyAvatarsAndMaxGPUTime(std::vector<LLCharacter*> &valid_near
|
|||
char_iter++;
|
||||
continue;
|
||||
}
|
||||
gPipeline.profileAvatar(avatar);
|
||||
|
||||
if (!avatar->isTooSlow())
|
||||
{
|
||||
gPipeline.profileAvatar(avatar);
|
||||
}
|
||||
nearby_max_complexity = llmax(nearby_max_complexity, avatar->getGPURenderTime());
|
||||
valid_nearby_avs.push_back(*char_iter);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2353,12 +2353,18 @@ bool LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3&
|
|||
|
||||
static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling");
|
||||
|
||||
// static
|
||||
bool LLPipeline::isWaterClip()
|
||||
{
|
||||
return (!sRenderTransparentWater || gCubeSnapshot) && !sRenderingHUDs;
|
||||
}
|
||||
|
||||
void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, bool hud_attachments)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_CULL);
|
||||
LL_PROFILE_GPU_ZONE("updateCull"); // should always be zero GPU time, but drop a timer to flush stuff out
|
||||
|
||||
bool water_clip = !sRenderTransparentWater && !sRenderingHUDs;
|
||||
bool water_clip = isWaterClip();
|
||||
|
||||
if (water_clip)
|
||||
{
|
||||
|
|
@ -10235,6 +10241,9 @@ void LLPipeline::profileAvatar(LLVOAvatar* avatar, bool profile_attachments)
|
|||
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
|
||||
|
||||
// don't continue to profile an avatar that is known to be too slow
|
||||
llassert(!avatar->isTooSlow());
|
||||
|
||||
LLGLSLShader* cur_shader = LLGLSLShader::sCurBoundShaderPtr;
|
||||
|
||||
mRT->deferredScreen.bindTarget();
|
||||
|
|
@ -10513,25 +10522,28 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar, bool
|
|||
resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512);
|
||||
resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512);
|
||||
|
||||
if (!avatar->mImpostor.isComplete())
|
||||
{
|
||||
avatar->mImpostor.allocate(resX, resY, GL_RGBA, true);
|
||||
if (!for_profile)
|
||||
{
|
||||
if (!avatar->mImpostor.isComplete())
|
||||
{
|
||||
avatar->mImpostor.allocate(resX, resY, GL_RGBA, true);
|
||||
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{
|
||||
addDeferredAttachments(avatar->mImpostor, true);
|
||||
}
|
||||
|
||||
gGL.getTexUnit(0)->bind(&avatar->mImpostor);
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
}
|
||||
else if(resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight())
|
||||
{
|
||||
avatar->mImpostor.resize(resX,resY);
|
||||
}
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{
|
||||
addDeferredAttachments(avatar->mImpostor, true);
|
||||
}
|
||||
|
||||
avatar->mImpostor.bindTarget();
|
||||
gGL.getTexUnit(0)->bind(&avatar->mImpostor);
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
}
|
||||
else if (resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight())
|
||||
{
|
||||
avatar->mImpostor.resize(resX, resY);
|
||||
}
|
||||
|
||||
avatar->mImpostor.bindTarget();
|
||||
}
|
||||
}
|
||||
|
||||
F32 old_alpha = LLDrawPoolAvatar::sMinimumAlpha;
|
||||
|
|
@ -10647,7 +10659,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar, bool
|
|||
gGL.popMatrix();
|
||||
}
|
||||
|
||||
if (!preview_avatar)
|
||||
if (!preview_avatar && !for_profile)
|
||||
{
|
||||
avatar->mImpostor.flush();
|
||||
avatar->setImpostorDim(tdim);
|
||||
|
|
|
|||
|
|
@ -376,6 +376,8 @@ public:
|
|||
bool hasRenderType(const U32 type) const;
|
||||
bool hasAnyRenderType(const U32 type, ...) const;
|
||||
|
||||
static bool isWaterClip();
|
||||
|
||||
void setRenderTypeMask(U32 type, ...);
|
||||
// This is equivalent to 'setRenderTypeMask'
|
||||
//void orRenderTypeMask(U32 type, ...);
|
||||
|
|
|
|||
Loading…
Reference in New Issue