SL-15709: Add Tracy support to viewer

master
Ptolemy 2021-07-27 15:31:15 -07:00
parent 2e88a32665
commit df5127136f
11 changed files with 308 additions and 210 deletions

View File

@ -270,6 +270,7 @@ Beq Janus
SL-13583
SL-14766
SL-14927
SL-15709
Beth Walcher
Bezilon Kasei
Biancaluce Robbiani

View File

@ -30,7 +30,7 @@ else (LINUX)
${BOOST_FIBER_LIBRARY}
${BOOST_CONTEXT_LIBRARY}
${BOOST_THREAD_LIBRARY}
${BOOST_SYSTEM_LIBRARY} )
${BOOST_SYSTEM_LIBRARY})
endif (LINUX)
set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a static library.")

View File

@ -201,6 +201,7 @@ set(llcommon_HEADER_FILES
llmortician.h
llnametable.h
llpointer.h
llprofiler.h
llpounceable.h
llpredicate.h
llpreprocessor.h

View File

@ -60,4 +60,6 @@
#include "llerror.h"
#include "llfile.h"
#include "llprofiler.h" // must be before fast timer; needed due to LLThreads potentially needing access to tracy
#endif

View File

@ -38,7 +38,10 @@
#define LL_FAST_TIMER_ON 1
#define LL_FASTTIMER_USE_RDTSC 1
// NOTE: Also see llprofiler.h
#if !defined(LL_PROFILER_CONFIGURATION) // defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER)
#define LL_RECORD_BLOCK_TIME(timer_stat) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
#endif // LL_PROFILER_CONFIGURATION
namespace LLTrace
{

View File

@ -0,0 +1,64 @@
/**
* @file llprofiler.h
* @brief Wrapper for Tracy and/or other profilers
*
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2021, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_PROFILER_H
#define LL_PROFILER_H
#define LL_PROFILER_CONFIG_NONE 0 // No profiling
#define LL_PROFILER_CONFIG_FAST_TIMER 1 // Profiling on: Only Fast Timers
#define LL_PROFILER_CONFIG_TRACY 2 // Profiling on: Only Tracy
#define LL_PROFILER_CONFIG_TRACY_FAST_TIMER 3 // Profiling on: Fast Timers + Tracy
#if defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION > LL_PROFILER_CONFIG_NONE)
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
#define TRACY_ENABLE 1
#define TRACY_NO_BROADCAST 1
#define TRACY_ONLY_LOCALHOST 1
#define TRACY_ONLY_IPV4 1
#include "Tracy.hpp"
#endif
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY
#define LL_PROFILER_FRAME_END FrameMark
#define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name )
#define LL_RECORD_BLOCK_TIME(name) ZoneNamedN( ___tracy_scoped_zone, #name, true );
#endif
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER
#define LL_PROFILER_FRAME_END
#define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
#define LL_RECORD_BLOCK_TIME(name) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
#endif
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
#define LL_PROFILER_FRAME_END FrameMark
#define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name )
#define LL_RECORD_BLOCK_TIME(name) ZoneNamedN( ___tracy_scoped_zone, #timer_stat, true ) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
#endif
#else
#define LL_PROFILER_FRAME_END
#define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
#endif // LL_PROFILER
#endif // LL_PROFILER_H

View File

@ -135,6 +135,8 @@ void LLThread::threadRun()
set_thread_name(-1, mName.c_str());
#endif
LL_PROFILER_SET_THREAD_NAME( mName.c_str() );
// this is the first point at which we're actually running in the new thread
mID = currentID();

View File

@ -1667,6 +1667,8 @@ bool LLAppViewer::doFrame()
LL_INFOS() << "Exiting main_loop" << LL_ENDL;
}
LL_PROFILER_FRAME_END
return ! LLApp::isRunning();
}

View File

@ -1259,7 +1259,7 @@ bool setup_hud_matrices(const LLRect& screen_region)
void render_ui(F32 zoom_factor, int subfield)
{
LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
LLGLState::checkStates();
@ -1274,7 +1274,7 @@ void render_ui(F32 zoom_factor, int subfield)
if(LLSceneMonitor::getInstance()->needsUpdate())
{
LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_SCENE_MON);
LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_SCENE_MON);
gGL.pushMatrix();
gViewerWindow->setup2DRender();
LLSceneMonitor::getInstance()->compare();
@ -1282,55 +1282,64 @@ void render_ui(F32 zoom_factor, int subfield)
gGL.popMatrix();
}
// Finalize scene
gPipeline.renderFinalize();
LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
render_hud_elements();
render_hud_attachments();
LLGLSDefault gls_default;
LLGLSUIDefault gls_ui;
{
gPipeline.disableLights();
}
// Finalize scene
gPipeline.renderFinalize();
{
gGL.color4f(1,1,1,1);
if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
// SL-15709
// NOTE: Tracy only allows one ZoneScoped per function.
// Solutions are:
// 1. Use a new scope
// 2. Use named zones
// 3. Use transient zones
LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
render_hud_elements();
render_hud_attachments();
LLGLSDefault gls_default;
LLGLSUIDefault gls_ui;
{
if (!gDisconnected)
gPipeline.disableLights();
}
{
gGL.color4f(1,1,1,1);
if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
{
LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
render_ui_3d();
if (!gDisconnected)
{
LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
render_ui_3d();
LLGLState::checkStates();
}
else
{
render_disconnected_background();
}
LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
render_ui_2d();
LLGLState::checkStates();
}
else
gGL.flush();
{
render_disconnected_background();
LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_DEBUG_TEXT);
gViewerWindow->setup2DRender();
gViewerWindow->updateDebugText();
gViewerWindow->drawDebugText();
}
LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
render_ui_2d();
LLGLState::checkStates();
LLVertexBuffer::unbind();
}
gGL.flush();
if (!gSnapshot)
{
LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_DEBUG_TEXT);
gViewerWindow->setup2DRender();
gViewerWindow->updateDebugText();
gViewerWindow->drawDebugText();
set_current_modelview(saved_view);
gGL.popMatrix();
}
LLVertexBuffer::unbind();
}
if (!gSnapshot)
{
set_current_modelview(saved_view);
gGL.popMatrix();
}
} // Tracy integration
}
static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap");

View File

@ -6045,123 +6045,130 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY))
{
LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);
LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers
{
// SL-15709 -- NOTE: Tracy only allows one ZoneScoped per function.
// Solutions are:
// 1. Use a new scope
// 2. Use named zones
// 3. Use transient zones
LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers
group->mBuilt = 1.f;
group->mBuilt = 1.f;
S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ;
S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ;
const U32 MAX_BUFFER_COUNT = 4096;
LLVertexBuffer* locked_buffer[MAX_BUFFER_COUNT];
U32 buffer_count = 0;
const U32 MAX_BUFFER_COUNT = 4096;
LLVertexBuffer* locked_buffer[MAX_BUFFER_COUNT];
for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
{
LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
U32 buffer_count = 0;
if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
{
LLVOVolume* vobj = drawablep->getVOVolume();
if (debugLoggingEnabled("AnimatedObjectsLinkset"))
{
if (vobj->isAnimatedObject() && vobj->isRiggedMesh())
{
std::string vobj_name = llformat("Vol%p", vobj);
F32 est_tris = vobj->getEstTrianglesMax();
LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL;
}
}
if (vobj->isNoLOD()) continue;
vobj->preRebuild();
if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
{
vobj->updateRelativeXform(true);
}
LLVolume* volume = vobj->getVolume();
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
if (face)
{
LLVertexBuffer* buff = face->getVertexBuffer();
if (buff)
{
llassert(!face->isState(LLFace::RIGGED));
if (!face->getGeometryVolume(*volume, face->getTEOffset(),
vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()))
{ //something's gone wrong with the vertex buffer accounting, rebuild this group
group->dirtyGeom();
gPipeline.markRebuild(group, TRUE);
}
if (buff->isLocked() && buffer_count < MAX_BUFFER_COUNT)
{
locked_buffer[buffer_count++] = buff;
}
}
}
}
if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
{
vobj->updateRelativeXform();
}
drawablep->clearState(LLDrawable::REBUILD_ALL);
}
}
{
LL_RECORD_BLOCK_TIME(FTM_REBUILD_MESH_FLUSH);
for (LLVertexBuffer** iter = locked_buffer, ** end_iter = locked_buffer+buffer_count; iter != end_iter; ++iter)
{
(*iter)->flush();
}
// don't forget alpha
if(group != NULL &&
!group->mVertexBuffer.isNull() &&
group->mVertexBuffer->isLocked())
{
group->mVertexBuffer->flush();
}
}
//if not all buffers are unmapped
if(num_mapped_vertex_buffer != LLVertexBuffer::sMappedCount)
{
LL_WARNS() << "Not all mapped vertex buffers are unmapped!" << LL_ENDL ;
for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
{
LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
if(!drawablep)
if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
{
continue;
}
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
if (face)
LLVOVolume* vobj = drawablep->getVOVolume();
if (debugLoggingEnabled("AnimatedObjectsLinkset"))
{
LLVertexBuffer* buff = face->getVertexBuffer();
if (buff && buff->isLocked())
if (vobj->isAnimatedObject() && vobj->isRiggedMesh())
{
buff->flush();
std::string vobj_name = llformat("Vol%p", vobj);
F32 est_tris = vobj->getEstTrianglesMax();
LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL;
}
}
if (vobj->isNoLOD()) continue;
vobj->preRebuild();
if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
{
vobj->updateRelativeXform(true);
}
LLVolume* volume = vobj->getVolume();
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
if (face)
{
LLVertexBuffer* buff = face->getVertexBuffer();
if (buff)
{
llassert(!face->isState(LLFace::RIGGED));
if (!face->getGeometryVolume(*volume, face->getTEOffset(),
vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()))
{ //something's gone wrong with the vertex buffer accounting, rebuild this group
group->dirtyGeom();
gPipeline.markRebuild(group, TRUE);
}
if (buff->isLocked() && buffer_count < MAX_BUFFER_COUNT)
{
locked_buffer[buffer_count++] = buff;
}
}
}
}
if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
{
vobj->updateRelativeXform();
}
drawablep->clearState(LLDrawable::REBUILD_ALL);
}
}
{
LL_RECORD_BLOCK_TIME(FTM_REBUILD_MESH_FLUSH);
for (LLVertexBuffer** iter = locked_buffer, ** end_iter = locked_buffer+buffer_count; iter != end_iter; ++iter)
{
(*iter)->flush();
}
// don't forget alpha
if(group != NULL &&
!group->mVertexBuffer.isNull() &&
group->mVertexBuffer->isLocked())
{
group->mVertexBuffer->flush();
}
}
//if not all buffers are unmapped
if(num_mapped_vertex_buffer != LLVertexBuffer::sMappedCount)
{
LL_WARNS() << "Not all mapped vertex buffers are unmapped!" << LL_ENDL ;
for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
{
LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
if(!drawablep)
{
continue;
}
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
if (face)
{
LLVertexBuffer* buff = face->getVertexBuffer();
if (buff && buff->isLocked())
{
buff->flush();
}
}
}
}
}
}
group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
}
group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
}
} // Tracy integration
// llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO));
}

View File

@ -4564,52 +4564,79 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS);
LLGLEnable cull(GL_CULL_FACE);
for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
{
LLDrawPool *poolp = *iter;
if (hasRenderType(poolp->getType()))
// SL-15709 -- NOTE: Tracy only allows one ZoneScoped per function.
// Solutions are:
// 1. Use a new scope
// 2. Use named zones
// 3. Use transient zones
LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS);
LLGLEnable cull(GL_CULL_FACE);
for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
{
poolp->prerender();
}
}
LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
LLVertexBuffer::unbind();
LLGLState::checkStates();
LLGLState::checkTextureChannels();
LLGLState::checkClientArrays();
U32 cur_type = 0;
gGL.setColorMask(true, true);
pool_set_t::iterator iter1 = mPools.begin();
while ( iter1 != mPools.end() )
{
LLDrawPool *poolp = *iter1;
cur_type = poolp->getType();
pool_set_t::iterator iter2 = iter1;
if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
{
LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER);
gGLLastMatrix = NULL;
gGL.loadMatrix(gGLModelView);
for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
LLDrawPool *poolp = *iter;
if (hasRenderType(poolp->getType()))
{
LLVertexBuffer::unbind();
poolp->beginDeferredPass(i);
poolp->prerender();
}
}
LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
LLVertexBuffer::unbind();
LLGLState::checkStates();
LLGLState::checkTextureChannels();
LLGLState::checkClientArrays();
U32 cur_type = 0;
gGL.setColorMask(true, true);
pool_set_t::iterator iter1 = mPools.begin();
while ( iter1 != mPools.end() )
{
LLDrawPool *poolp = *iter1;
cur_type = poolp->getType();
pool_set_t::iterator iter2 = iter1;
if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
{
LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER);
gGLLastMatrix = NULL;
gGL.loadMatrix(gGLModelView);
for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
{
LLVertexBuffer::unbind();
poolp->beginDeferredPass(i);
for (iter2 = iter1; iter2 != mPools.end(); iter2++)
{
LLDrawPool *p = *iter2;
if (p->getType() != cur_type)
{
break;
}
if ( !p->getSkipRenderFlag() ) { p->renderDeferred(i); }
}
poolp->endDeferredPass(i);
LLVertexBuffer::unbind();
if (gDebugGL || gDebugPipeline)
{
LLGLState::checkStates();
}
}
}
else
{
// Skip all pools of this type
for (iter2 = iter1; iter2 != mPools.end(); iter2++)
{
LLDrawPool *p = *iter2;
@ -4617,39 +4644,19 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
{
break;
}
if ( !p->getSkipRenderFlag() ) { p->renderDeferred(i); }
}
poolp->endDeferredPass(i);
LLVertexBuffer::unbind();
if (gDebugGL || gDebugPipeline)
{
LLGLState::checkStates();
}
}
iter1 = iter2;
stop_glerror();
}
else
{
// Skip all pools of this type
for (iter2 = iter1; iter2 != mPools.end(); iter2++)
{
LLDrawPool *p = *iter2;
if (p->getType() != cur_type)
{
break;
}
}
}
iter1 = iter2;
stop_glerror();
}
gGLLastMatrix = NULL;
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.loadMatrix(gGLModelView);
gGLLastMatrix = NULL;
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.loadMatrix(gGLModelView);
gGL.setColorMask(true, false);
gGL.setColorMask(true, false);
} // Tracy ZoneScoped
}
void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)