# Conflicts:
#	indra/llrender/llrender2dutils.cpp
#	indra/llui/llfolderviewitem.cpp
master
Ansariel 2024-09-18 12:16:32 +02:00
commit 3c6aab0812
19 changed files with 525 additions and 643 deletions

View File

@ -6,7 +6,7 @@ add_library( ll::tracy INTERFACE IMPORTED )
# default Tracy profiling on for test builds, but off for all others
string(TOLOWER ${VIEWER_CHANNEL} channel_lower)
if(WINDOWS AND channel_lower MATCHES "^second life test")
if(channel_lower MATCHES "^second life test")
option(USE_TRACY "Use Tracy profiler." ON)
else()
option(USE_TRACY "Use Tracy profiler." OFF)
@ -30,6 +30,11 @@ if (USE_TRACY)
target_compile_definitions(ll::tracy INTERFACE -DTRACY_NO_BROADCAST=1 -DTRACY_ONLY_LOCALHOST=1)
endif ()
# GHA runners don't always provide invariant TSC support, but always build with LL_TESTS enabled
if (DARWIN AND LL_TESTS)
target_compile_definitions(ll::tracy INTERFACE -DTRACY_TIMER_FALLBACK=1)
endif ()
# See: indra/llcommon/llprofiler.h
add_compile_definitions(LL_PROFILER_CONFIGURATION=3)
endif (USE_TRACY)

View File

@ -1180,6 +1180,11 @@ bool LLGLManager::initGL()
mGLVendorShort = "INTEL";
mIsIntel = true;
}
else if (mGLVendor.find("APPLE") != std::string::npos)
{
mGLVendorShort = "APPLE";
mIsApple = true;
}
else
{
mGLVendorShort = "MISC";

View File

@ -105,6 +105,7 @@ public:
bool mIsAMD;
bool mIsNVIDIA;
bool mIsIntel;
bool mIsApple = false;
// hints to the render pipe
U32 mDownScaleMethod = 0; // see settings.xml RenderDownScaleMethod

File diff suppressed because it is too large Load Diff

View File

@ -290,22 +290,58 @@ static GLuint gen_buffer()
return ret;
}
static void delete_buffers(S32 count, GLuint* buffers)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
// wait a few frames before actually deleting the buffers to avoid
// synchronization issues with the GPU
static std::vector<GLuint> sFreeList[4];
if (gGLManager.mInited)
{
U32 idx = LLImageGL::sFrameCount % 4;
for (S32 i = 0; i < count; ++i)
{
sFreeList[idx].push_back(buffers[i]);
}
idx = (LLImageGL::sFrameCount + 3) % 4;
if (!sFreeList[idx].empty())
{
glDeleteBuffers((GLsizei)sFreeList[idx].size(), sFreeList[idx].data());
sFreeList[idx].resize(0);
}
}
}
#define ANALYZE_VBO_POOL 0
#if LL_DARWIN
// experimental -- disable VBO pooling on OS X and use glMapBuffer
// VBO Pool interface
class LLVBOPool
{
public:
virtual ~LLVBOPool() = default;
virtual void allocate(GLenum type, U32 size, GLuint& name, U8*& data) = 0;
virtual void free(GLenum type, U32 size, GLuint name, U8* data) = 0;
virtual U64 getVramBytesUsed() = 0;
};
// VBO Pool for Apple GPUs (as in M1/M2 etc, not Intel macs)
// Effectively disables VBO pooling
class LLAppleVBOPool final: public LLVBOPool
{
public:
U64 mAllocated = 0;
U64 getVramBytesUsed()
U64 getVramBytesUsed() override
{
return mAllocated;
}
void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
STOP_GLERROR;
@ -325,7 +361,7 @@ public:
}
}
void free(GLenum type, U32 size, GLuint name, U8* data)
void free(GLenum type, U32 size, GLuint name, U8* data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@ -340,19 +376,17 @@ public:
STOP_GLERROR;
if (name)
{
glDeleteBuffers(1, &name);
delete_buffers(1, &name);
}
STOP_GLERROR;
}
};
#else
class LLVBOPool
// VBO Pool for GPUs that benefit from VBO pooling
class LLDefaultVBOPool final : public LLVBOPool
{
public:
typedef std::chrono::steady_clock::time_point Time;
struct Entry
{
U8* mData;
@ -360,7 +394,7 @@ public:
Time mAge;
};
~LLVBOPool()
~LLDefaultVBOPool() override
{
clear();
}
@ -378,7 +412,7 @@ public:
U32 mMisses = 0;
U32 mHits = 0;
U64 getVramBytesUsed()
U64 getVramBytesUsed() override
{
return mAllocated + mReserved;
}
@ -394,7 +428,7 @@ public:
size += block_size - (size % block_size);
}
void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@ -450,7 +484,7 @@ public:
clean();
}
void free(GLenum type, U32 size, GLuint name, U8* data)
void free(GLenum type, U32 size, GLuint name, U8* data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@ -513,7 +547,7 @@ public:
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vbo cache timeout");
auto& entry = entries.back();
ll_aligned_free_16(entry.mData);
glDeleteBuffers(1, &entry.mGLName);
delete_buffers(1, &entry.mGLName);
llassert(mReserved >= iter->first);
mReserved -= iter->first;
entries.pop_back();
@ -549,7 +583,7 @@ public:
for (auto& entry : entries.second)
{
ll_aligned_free_16(entry.mData);
glDeleteBuffers(1, &entry.mGLName);
delete_buffers(1, &entry.mGLName);
}
}
@ -558,7 +592,7 @@ public:
for (auto& entry : entries.second)
{
ll_aligned_free_16(entry.mData);
glDeleteBuffers(1, &entry.mGLName);
delete_buffers(1, &entry.mGLName);
}
}
@ -568,7 +602,6 @@ public:
mVBOPool.clear();
}
};
#endif
static LLVBOPool* sVBOPool = nullptr;
@ -915,7 +948,16 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
void LLVertexBuffer::initClass(LLWindow* window)
{
llassert(sVBOPool == nullptr);
sVBOPool = new LLVBOPool();
if (gGLManager.mIsApple)
{
LL_INFOS() << "VBO Pooling Disabled" << LL_ENDL;
sVBOPool = new LLAppleVBOPool();
}
else
{
LL_INFOS() << "VBO Pooling Enabled" << LL_ENDL;
sVBOPool = new LLDefaultVBOPool();
}
#if ENABLE_GL_WORK_QUEUE
sQueue = new GLWorkQueue();
@ -983,7 +1025,6 @@ void LLVertexBuffer::flushBuffers()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
// must only be called from main thread
llassert(LLCoros::on_main_thread_main_coro());
for (auto& buffer : sMappedBuffers)
{
buffer->_unmapBuffer();
@ -1250,28 +1291,29 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde
count = mNumVerts - index;
}
#if !LL_DARWIN
U32 start = mOffsets[type] + sTypeSize[type] * index;
U32 end = start + sTypeSize[type] * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
if (!gGLManager.mIsApple)
{
MappedRegion& region = mMappedVertexRegions[i];
if (expand_region(region, start, end))
U32 start = mOffsets[type] + sTypeSize[type] * index;
U32 end = start + sTypeSize[type] * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
{
flagged = true;
break;
MappedRegion& region = mMappedVertexRegions[i];
if (expand_region(region, start, end))
{
flagged = true;
break;
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedVertexRegions.push_back({ start, end });
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedVertexRegions.push_back({ start, end });
}
#endif
return mMappedData+mOffsets[type]+sTypeSize[type]*index;
}
@ -1286,29 +1328,30 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
count = mNumIndices-index;
}
#if !LL_DARWIN
U32 start = sizeof(U16) * index;
U32 end = start + sizeof(U16) * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
if (!gGLManager.mIsApple)
{
MappedRegion& region = mMappedIndexRegions[i];
if (expand_region(region, start, end))
U32 start = sizeof(U16) * index;
U32 end = start + sizeof(U16) * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
{
flagged = true;
break;
MappedRegion& region = mMappedIndexRegions[i];
if (expand_region(region, start, end))
{
flagged = true;
break;
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedIndexRegions.push_back({ start, end });
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedIndexRegions.push_back({ start, end });
}
#endif
return mMappedIndexData + sizeof(U16)*index;
}
@ -1320,37 +1363,40 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
// dst -- mMappedData or mMappedIndexData
void LLVertexBuffer::flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst)
{
#if LL_DARWIN
// on OS X, flush_vbo doesn't actually write to the GL buffer, so be sure to call
// _mapBuffer to tag the buffer for flushing to GL
_mapBuffer();
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb memcpy");
STOP_GLERROR;
// copy into mapped buffer
memcpy(dst+start, data, end-start+1);
#else
llassert(target == GL_ARRAY_BUFFER ? sGLRenderBuffer == mGLBuffer : sGLRenderIndices == mGLIndices);
// skip mapped data and stream to GPU via glBufferSubData
if (end != 0)
if (gGLManager.mIsApple)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData");
LL_PROFILE_ZONE_NUM(start);
LL_PROFILE_ZONE_NUM(end);
LL_PROFILE_ZONE_NUM(end-start);
// on OS X, flush_vbo doesn't actually write to the GL buffer, so be sure to call
// _mapBuffer to tag the buffer for flushing to GL
_mapBuffer();
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb memcpy");
STOP_GLERROR;
// copy into mapped buffer
memcpy(dst+start, data, end-start+1);
}
else
{
llassert(target == GL_ARRAY_BUFFER ? sGLRenderBuffer == mGLBuffer : sGLRenderIndices == mGLIndices);
constexpr U32 block_size = 65536;
for (U32 i = start; i <= end; i += block_size)
// skip mapped data and stream to GPU via glBufferSubData
if (end != 0)
{
//LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
//LL_PROFILE_GPU_ZONE("glBufferSubData");
U32 tend = llmin(i + block_size, end);
U32 size = tend - i + 1;
glBufferSubData(target, i, size, (U8*) data + (i-start));
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData");
LL_PROFILE_ZONE_NUM(start);
LL_PROFILE_ZONE_NUM(end);
LL_PROFILE_ZONE_NUM(end-start);
constexpr U32 block_size = 65536;
for (U32 i = start; i <= end; i += block_size)
{
//LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
//LL_PROFILE_GPU_ZONE("glBufferSubData");
U32 tend = llmin(i + block_size, end);
U32 size = tend - i + 1;
glBufferSubData(target, i, size, (U8*) data + (i-start));
}
}
}
#endif
}
void LLVertexBuffer::unmapBuffer()
@ -1383,114 +1429,116 @@ void LLVertexBuffer::_unmapBuffer()
}
};
#if LL_DARWIN
STOP_GLERROR;
if (mMappedData)
if (gGLManager.mIsApple)
{
if (mGLBuffer)
STOP_GLERROR;
if (mMappedData)
{
glDeleteBuffers(1, &mGLBuffer);
if (mGLBuffer)
{
delete_buffers(1, &mGLBuffer);
}
mGLBuffer = gen_buffer();
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW);
}
mGLBuffer = gen_buffer();
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW);
}
else if (mGLBuffer != sGLRenderBuffer)
{
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
}
STOP_GLERROR;
if (mMappedIndexData)
{
if (mGLIndices)
{
glDeleteBuffers(1, &mGLIndices);
}
mGLIndices = gen_buffer();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_STATIC_DRAW);
}
else if (mGLIndices != sGLRenderIndices)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
}
STOP_GLERROR;
#else
if (!mMappedVertexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
if (sGLRenderBuffer != mGLBuffer)
else if (mGLBuffer != sGLRenderBuffer)
{
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
}
STOP_GLERROR;
U32 start = 0;
U32 end = 0;
std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
if (mMappedIndexData)
{
const MappedRegion& region = mMappedVertexRegions[i];
if (region.mStart == end + 1)
if (mGLIndices)
{
end = region.mEnd;
}
else
{
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
start = region.mStart;
end = region.mEnd;
delete_buffers(1, &mGLIndices);
}
mGLIndices = gen_buffer();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_STATIC_DRAW);
}
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
mMappedVertexRegions.clear();
}
if (!mMappedIndexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
if (mGLIndices != sGLRenderIndices)
else if (mGLIndices != sGLRenderIndices)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
}
U32 start = 0;
U32 end = 0;
std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
STOP_GLERROR;
}
else
{
if (!mMappedVertexRegions.empty())
{
const MappedRegion& region = mMappedIndexRegions[i];
if (region.mStart == end + 1)
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
if (sGLRenderBuffer != mGLBuffer)
{
end = region.mEnd;
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
}
else
U32 start = 0;
U32 end = 0;
std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
{
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
start = region.mStart;
end = region.mEnd;
const MappedRegion& region = mMappedVertexRegions[i];
if (region.mStart == end + 1)
{
end = region.mEnd;
}
else
{
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
start = region.mStart;
end = region.mEnd;
}
}
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
mMappedVertexRegions.clear();
}
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
mMappedIndexRegions.clear();
if (!mMappedIndexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
if (mGLIndices != sGLRenderIndices)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
}
U32 start = 0;
U32 end = 0;
std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
{
const MappedRegion& region = mMappedIndexRegions[i];
if (region.mStart == end + 1)
{
end = region.mEnd;
}
else
{
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
start = region.mStart;
end = region.mEnd;
}
}
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
mMappedIndexRegions.clear();
}
}
#endif
}
//----------------------------------------------------------------------------

View File

@ -1743,7 +1743,7 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr
{
LLRect local_rect = item->getLocalRect();
S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight();
S32 label_height = getLabelFontForStyle(mLabelStyle)->getLineHeight();
S32 label_height = getLabelFont()->getLineHeight();
// when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder
S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + item->getIconPad()) : local_rect.getHeight();

View File

@ -50,7 +50,6 @@ static LLDefaultChildRegistry::Register<LLFolderViewItem> r("folder_view_item");
// statics
std::map<U8, LLFontGL*> LLFolderViewItem::sFonts; // map of styles to fonts
bool LLFolderViewItem::sColorSetInitialized = false;
LLUIColor LLFolderViewItem::sFgColor;
LLUIColor LLFolderViewItem::sHighlightBgColor;
LLUIColor LLFolderViewItem::sFlashBgColor;
@ -62,6 +61,10 @@ LLUIColor LLFolderViewItem::sSuffixColor;
LLUIColor LLFolderViewItem::sSearchStatusColor;
// <FS:Ansariel> Special for protected items
LLUIColor LLFolderViewItem::sProtectedColor;
S32 LLFolderViewItem::sTopPad = 0;
LLUIImagePtr LLFolderViewItem::sFolderArrowImg;
LLUIImagePtr LLFolderViewItem::sSelectionImg;
LLFontGL* LLFolderViewItem::sSuffixFont = nullptr;
// only integers can be initialized in header
const F32 LLFolderViewItem::FOLDER_CLOSE_TIME_CONSTANT = 0.02f;
@ -87,15 +90,51 @@ LLFontGL* LLFolderViewItem::getLabelFontForStyle(U8 style)
return rtn;
}
const LLFontGL* LLFolderViewItem::getLabelFont()
{
if (!pLabelFont)
{
pLabelFont = getLabelFontForStyle(mLabelStyle);
}
return pLabelFont;
}
//static
void LLFolderViewItem::initClass()
{
const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
sTopPad = default_params.item_top_pad;
sFolderArrowImg = default_params.folder_arrow_image;
sSelectionImg = default_params.selection_image;
sSuffixFont = getLabelFontForStyle(LLFontGL::NORMAL);
// <FS:Ansariel> Make inventory selection color independent from menu color
//sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
//sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
sFgColor = LLUIColorTable::instance().getColor("InventoryItemEnabledColor", DEFAULT_WHITE);
sHighlightBgColor = LLUIColorTable::instance().getColor("InventoryItemHighlightBgColor", DEFAULT_WHITE);
// </FS:Ansariel>
sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE);
sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
// <FS:Ansariel> Fix misleading color name
//sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemSuffixColor", DEFAULT_WHITE);
// </FS:Ansariel>
sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
// <FS:Ansariel> Special for protected items
sProtectedColor = LLUIColorTable::instance().getColor("InventoryProtectedColor", DEFAULT_WHITE);
}
//static
void LLFolderViewItem::cleanupClass()
{
sFonts.clear();
sFolderArrowImg = nullptr;
sSelectionImg = nullptr;
sSuffixFont = nullptr;
}
@ -141,6 +180,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mIsItemCut(false),
mCutGeneration(0),
mLabelStyle( LLFontGL::NORMAL ),
pLabelFont(nullptr),
mHasVisibleChildren(false),
mLocalIndentation(p.folder_indentation),
mIndentation(0),
@ -168,29 +208,6 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mForInventory(p.for_inventory),
mItemTopPad(p.item_top_pad)
{
if (!sColorSetInitialized)
{
// <FS:Ansariel> Make inventory selection color independent from menu color
//sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
//sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
sFgColor = LLUIColorTable::instance().getColor("InventoryItemEnabledColor", DEFAULT_WHITE);
sHighlightBgColor = LLUIColorTable::instance().getColor("InventoryItemHighlightBgColor", DEFAULT_WHITE);
// </FS:Ansariel> Make inventory selection color independent from menu color
sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE);
sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
// <FS:Ansariel> Fix misleading color name
//sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemSuffixColor", DEFAULT_WHITE);
// </FS:Ansariel>
sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
// <FS:Ansariel> Special for protected items
sProtectedColor = LLUIColorTable::instance().getColor("InventoryProtectedColor", DEFAULT_WHITE);
sColorSetInitialized = true;
}
if (mViewModelItem)
{
mViewModelItem->setFolderViewItem(this);
@ -339,6 +356,7 @@ void LLFolderViewItem::refresh()
// Very Expensive!
// Can do a number of expensive checks, like checking active motions, wearables or friend list
mLabelStyle = vmi.getLabelStyle();
pLabelFont = nullptr; // refresh can be called from a coro, don't use getLabelFontForStyle, coro trips font list tread safety
mLabelSuffix = utf8str_to_wstring(vmi.getLabelSuffix());
mSuffixFontBuffer.reset();
}
@ -365,6 +383,7 @@ void LLFolderViewItem::refreshSuffix()
// Very Expensive!
// Can do a number of expensive checks, like checking active motions, wearables or friend list
mLabelStyle = vmi->getLabelStyle();
pLabelFont = nullptr;
mLabelSuffix = utf8str_to_wstring(vmi->getLabelSuffix());
}
@ -805,21 +824,18 @@ bool LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
return handled;
}
void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color)
void LLFolderViewItem::drawOpenFolderArrow()
{
//--------------------------------------------------------------------------------//
// Draw open folder arrow
//
// <FS:Ansariel> Inventory specials
//const S32 TOP_PAD = default_params.item_top_pad;
const S32 TOP_PAD = mItemTopPad;
if (hasVisibleChildren() || !isFolderComplete())
{
LLUIImage* arrow_image = default_params.folder_arrow_image;
gl_draw_scaled_rotated_image(
mIndentation, getRect().getHeight() - mArrowSize - mTextPad - TOP_PAD,
mArrowSize, mArrowSize, mControlLabelRotation, arrow_image->getImage(), fg_color);
// <FS:Ansariel> Inventory specials
mIndentation, getRect().getHeight() - mArrowSize - mTextPad - mItemTopPad,
mArrowSize, mArrowSize, mControlLabelRotation, sFolderArrowImg->getImage(), sFgColor);
}
}
@ -835,7 +851,7 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L
/*virtual*/ bool LLFolderViewItem::isFadeItem()
{
LLClipboard& clipboard = LLClipboard::instance();
static const LLClipboard& clipboard = LLClipboard::instance(); // Make it a 'simpleton'?
if (mCutGeneration != clipboard.getGeneration())
{
mCutGeneration = clipboard.getGeneration();
@ -971,18 +987,14 @@ void LLFolderViewItem::draw()
const bool show_context = (getRoot() ? getRoot()->getShowSelectionContext() : false);
const bool filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : false); // If we have keyboard focus, draw selection filled
const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
// <FS:Ansariel> Inventory specials
//const S32 TOP_PAD = default_params.item_top_pad;
const S32 TOP_PAD = mItemTopPad;
const LLFontGL* font = getLabelFontForStyle(mLabelStyle);
const LLFontGL* font = getLabelFont();
S32 line_height = font->getLineHeight();
getViewModelItem()->update();
if (!mSingleFolderMode)
{
drawOpenFolderArrow(default_params, sFgColor);
drawOpenFolderArrow();
}
drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
@ -991,18 +1003,19 @@ void LLFolderViewItem::draw()
// Draw open icon
//
const S32 icon_x = mIndentation + mArrowSize + mTextPad;
const S32 rect_height = getRect().getHeight();
if (!mIconOpen.isNull() && (llabs(mControlLabelRotation) > 80)) // For open folders
{
mIconOpen->draw(icon_x, getRect().getHeight() - mIconOpen->getHeight() - TOP_PAD + 1);
mIconOpen->draw(icon_x, rect_height - mIconOpen->getHeight() - mItemTopPad + 1);
}
else if (mIcon)
{
mIcon->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1);
mIcon->draw(icon_x, rect_height - mIcon->getHeight() - mItemTopPad + 1);
}
if (mIconOverlay && getRoot()->showItemLinkOverlays())
{
mIconOverlay->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1);
mIconOverlay->draw(icon_x, rect_height - mIcon->getHeight() - mItemTopPad + 1);
}
//--------------------------------------------------------------------------------//
@ -1015,24 +1028,22 @@ void LLFolderViewItem::draw()
S32 filter_string_length = mViewModelItem->hasFilterStringMatch() ? (S32)mViewModelItem->getFilterStringSize() : 0;
F32 right_x = 0;
F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
F32 y = (F32)rect_height - line_height - (F32)mTextPad - (F32)mItemTopPad;
F32 text_left = (F32)getLabelXPos();
LLWString combined_string = mLabel + mLabelSuffix;
const LLFontGL* suffix_font = getLabelFontForStyle(LLFontGL::NORMAL);
S32 filter_offset = static_cast<S32>(mViewModelItem->getFilterStringOffset());
if (filter_string_length > 0)
{
S32 bottom = getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD;
S32 top = getRect().getHeight() - TOP_PAD;
if(mLabelSuffix.empty() || (font == suffix_font))
S32 bottom = rect_height - line_height - 3 - mItemTopPad;
S32 top = rect_height - mItemTopPad;
if(mLabelSuffix.empty() || (font == sSuffixFont))
{
S32 left = ll_round(text_left) + font->getWidth(combined_string.c_str(), 0, static_cast<S32>(mViewModelItem->getFilterStringOffset())) - 2;
S32 right = left + font->getWidth(combined_string.c_str(), static_cast<S32>(mViewModelItem->getFilterStringOffset()), filter_string_length) + 2;
S32 left = ll_round(text_left) + font->getWidth(combined_string.c_str(), 0, filter_offset) - 2;
S32 right = left + font->getWidth(combined_string.c_str(), filter_offset, filter_string_length) + 2;
LLUIImage* box_image = default_params.selection_image;
LLRect box_rect(left, top, right, bottom);
box_image->draw(box_rect, sFilterBGColor);
LLRect box_rect(left, top, right, bottom);
sSelectionImg->draw(box_rect, sFilterBGColor);
}
else
{
@ -1041,19 +1052,17 @@ void LLFolderViewItem::draw()
{
S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, llmin(filter_offset, (S32)mLabel.size()))) - 2;
S32 right = left + (S32)font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length) + 2;
LLUIImage* box_image = default_params.selection_image;
LLRect box_rect(left, top, right, bottom);
box_image->draw(box_rect, sFilterBGColor);
sSelectionImg->draw(box_rect, sFilterBGColor);
}
S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length;
if(suffix_filter_length > 0)
{
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + suffix_font->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset)) - 2;
S32 right = left + (S32)suffix_font->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length) + 2;
LLUIImage* box_image = default_params.selection_image;
S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + sSuffixFont->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset)) - 2;
S32 right = left + (S32)sSuffixFont->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length) + 2;
LLRect box_rect(left, top, right, bottom);
box_image->draw(box_rect, sFilterBGColor);
sSelectionImg->draw(box_rect, sFilterBGColor);
}
}
}
@ -1092,7 +1101,7 @@ void LLFolderViewItem::draw()
//
if (!mLabelSuffix.empty())
{
mSuffixFontBuffer.render(suffix_font, mLabelSuffix, 0, right_x, y, isFadeItem() ? color : sSuffixColor.get(),
mSuffixFontBuffer.render(sSuffixFont, mLabelSuffix, 0, right_x, y, isFadeItem() ? color : sSuffixColor.get(),
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
S32_MAX, S32_MAX, &right_x);
}
@ -1102,10 +1111,10 @@ void LLFolderViewItem::draw()
//
if (filter_string_length > 0)
{
if(mLabelSuffix.empty() || (font == suffix_font))
if(mLabelSuffix.empty() || (font == sSuffixFont))
{
F32 match_string_left = text_left + font->getWidthF32(combined_string.c_str(), 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string.c_str(), filter_offset, filter_string_length);
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
F32 yy = (F32)rect_height - line_height - (F32)mTextPad - (F32)mItemTopPad;
font->render(combined_string, filter_offset, match_string_left, yy,
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
filter_string_length, S32_MAX, &right_x);
@ -1116,7 +1125,7 @@ void LLFolderViewItem::draw()
if(label_filter_length > 0)
{
F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length);
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
F32 yy = (F32)rect_height - line_height - (F32)mTextPad - (F32)mItemTopPad;
font->render(mLabel, filter_offset, match_string_left, yy,
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
label_filter_length, S32_MAX, &right_x);
@ -1126,9 +1135,9 @@ void LLFolderViewItem::draw()
if(suffix_filter_length > 0)
{
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + suffix_font->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset + suffix_filter_length) - suffix_font->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length);
F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
suffix_font->render(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor,
F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + sSuffixFont->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset + suffix_filter_length) - sSuffixFont->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length);
F32 yy = (F32)rect_height - sSuffixFont->getLineHeight() - (F32)mTextPad - (F32)mItemTopPad;
sSuffixFont->render(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor,
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
suffix_filter_length, S32_MAX, &right_x);
}

View File

@ -143,7 +143,6 @@ protected:
S32 mItemTopPad;
// For now assuming all colors are the same in derived classes.
static bool sColorSetInitialized;
static LLUIColor sFgColor;
static LLUIColor sFgDisabledColor;
static LLUIColor sHighlightBgColor;
@ -168,6 +167,7 @@ protected:
virtual void setFlashState(bool) { }
static LLFontGL* getLabelFontForStyle(U8 style);
const LLFontGL* getLabelFont();
bool mIsSelected;
@ -307,7 +307,7 @@ public:
// virtual void handleDropped();
virtual void draw();
void drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color);
void drawOpenFolderArrow();
void drawHighlight(bool showContent, bool hasKeyboardFocus, const LLUIColor& selectColor, const LLUIColor& flashColor, const LLUIColor& outlineColor, const LLUIColor& mouseOverColor);
void drawLabel(const LLFontGL* font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x);
virtual bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
@ -323,9 +323,14 @@ public:
private:
static std::map<U8, LLFontGL*> sFonts; // map of styles to fonts
static S32 sTopPad;
static LLUIImagePtr sFolderArrowImg;
static LLUIImagePtr sSelectionImg;
static LLFontGL* sSuffixFont;
LLFontVertexBuffer mLabelFontBuffer;
LLFontVertexBuffer mSuffixFontBuffer;
LLFontGL* pLabelFont{nullptr};
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -1,4 +1,4 @@
version 60
version 61
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@ -68,7 +68,8 @@ RenderFSAASamples 1 3
RenderMaxTextureIndex 1 16
RenderGLContextCoreProfile 1 1
RenderGLMultiThreadedTextures 1 0
RenderGLMultiThreadedMedia 1 0
RenderGLMultiThreadedMedia 1 1
RenderAppleUseMultGL 1 1
RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 2
RenderScreenSpaceReflections 1 1
@ -381,6 +382,15 @@ list Intel
RenderAnisotropic 1 0
RenderFSAASamples 1 0
// AppleGPU and NonAppleGPU can be thought of as Apple silicon vs Intel Mac
list AppleGPU
RenderGLMultiThreadedMedia 1 1
RenderAppleUseMultGL 1 1
list NonAppleGPU
RenderGLMultiThreadedMedia 1 0
RenderAppleUseMultGL 1 0
list GL3
RenderFSAASamples 0 0
RenderReflectionProbeDetail 0 0

View File

@ -315,7 +315,7 @@ void LLConversationViewSession::draw()
{
// update the rotation angle of open folder arrow
updateLabelRotation();
drawOpenFolderArrow(default_params, sFgColor);
drawOpenFolderArrow();
}
LLView::draw();
}

View File

@ -200,8 +200,8 @@ bool LLViewerDynamicTexture::updateAllInstances()
}
llassert(preview_target.getWidth() >= LLPipeline::MAX_PREVIEW_WIDTH);
llassert(preview_target.getHeight() >= LLPipeline::MAX_PREVIEW_WIDTH);
llassert(bake_target.getWidth() >= LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH);
llassert(bake_target.getHeight() >= LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT);
llassert(bake_target.getWidth() >= (U32) LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH);
llassert(bake_target.getHeight() >= (U32) LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT);
preview_target.bindTarget();
preview_target.clear();

View File

@ -666,6 +666,14 @@ void LLFeatureManager::applyBaseMasks()
{
maskFeatures("Intel");
}
if (gGLManager.mIsApple)
{
maskFeatures("AppleGPU");
}
else
{
maskFeatures("NonAppleGPU");
}
if (gGLManager.mGLVersion < 3.f)
{
maskFeatures("OpenGLPre30");

View File

@ -4064,6 +4064,7 @@ void LLMeshRepository::notifyLoadedMeshes()
for (auto iter = mSkinMap.begin(), ender = mSkinMap.end(); iter != ender;)
{
auto copy_iter = iter++;
LLUUID id = copy_iter->first;
//skinbytes += U64Bytes(sizeof(LLMeshSkinInfo));
//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(std::string));
@ -4077,7 +4078,6 @@ void LLMeshRepository::notifyLoadedMeshes()
}
// erase from background thread
LLUUID id = iter->first;
mThread->mWorkQueue.post([=]()
{
mThread->mSkinMap.erase(id);

View File

@ -2556,8 +2556,6 @@ void LLVOAvatar::updateMeshData()
{
if (mDrawable.notNull())
{
stop_glerror();
S32 f_num = 0 ;
const U32 VERTEX_NUMBER_THRESHOLD = 128 ;//small number of this means each part of an avatar has its own vertex buffer.
const auto num_parts = mMeshLOD.size();
@ -2684,7 +2682,6 @@ void LLVOAvatar::updateMeshData()
}
}
stop_glerror();
buff->unmapBuffer();
if(!f_num)
@ -11806,9 +11803,8 @@ void LLVOAvatar::updateRiggingInfo()
getAssociatedVolumes(volumes);
{
LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR("update rig info - get key")
HBXXH128 hash;
LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR("update rig info - get key");
size_t hash = 0;
// Get current rigging info key
for (LLVOVolume* vol : volumes)
{
@ -11817,22 +11813,20 @@ void LLVOAvatar::updateRiggingInfo()
const LLUUID& mesh_id = vol->getVolume()->getParams().getSculptID();
S32 max_lod = llmax(vol->getLOD(), vol->mLastRiggingInfoLOD);
hash.update(mesh_id.mData, sizeof(mesh_id.mData));
hash.update(&max_lod, sizeof(max_lod));
boost::hash_combine(hash, mesh_id);
boost::hash_combine(hash, max_lod);
}
}
LLUUID curr_rigging_info_key = hash.digest();
// Check for key change, which indicates some change in volume composition or LOD.
if (curr_rigging_info_key == mLastRiggingInfoKey)
if (hash == mLastRiggingInfoKey)
{
return;
}
// Something changed. Update.
mLastRiggingInfoKey = curr_rigging_info_key;
mLastRiggingInfoKey = hash;
}
mJointRiggingInfoTab.clear();

View File

@ -232,7 +232,7 @@ public:
// virtual
void updateRiggingInfo();
// This encodes mesh id and LOD, so we can see whether display is up-to-date.
LLUUID mLastRiggingInfoKey;
size_t mLastRiggingInfoKey;
std::set<LLUUID> mActiveOverrideMeshes;
virtual void onActiveOverrideMeshesChanged();

View File

@ -774,7 +774,6 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group)
}
}
buffer->unmapBuffer();
mFaceList.clear();
}

View File

@ -54,63 +54,6 @@ void LLVOPartGroup::initClass()
void LLVOPartGroup::restoreGL()
{
//TODO: optimize out binormal mask here. Specular and normal coords as well.
#if 0
sVB = new LLVertexBuffer(VERTEX_DATA_MASK | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
U32 count = LL_MAX_PARTICLE_COUNT;
if (!sVB->allocateBuffer(count*4, count*6))
{
LL_WARNS() << "Failed to allocate Vertex Buffer to "
<< count*4 << " vertices and "
<< count * 6 << " indices" << LL_ENDL;
// we are likelly to crash at following getTexCoord0Strider(), so unref and return
sVB = NULL;
return;
}
//indices and texcoords are always the same, set once
LLStrider<U16> indicesp;
LLStrider<LLVector4a> verticesp;
sVB->getIndexStrider(indicesp);
sVB->getVertexStrider(verticesp);
LLVector4a v;
v.set(0,0,0,0);
U16 vert_offset = 0;
for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++)
{
*indicesp++ = vert_offset + 0;
*indicesp++ = vert_offset + 1;
*indicesp++ = vert_offset + 2;
*indicesp++ = vert_offset + 1;
*indicesp++ = vert_offset + 3;
*indicesp++ = vert_offset + 2;
*verticesp++ = v;
vert_offset += 4;
}
LLStrider<LLVector2> texcoordsp;
sVB->getTexCoord0Strider(texcoordsp);
for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++)
{
*texcoordsp++ = LLVector2(0.f, 1.f);
*texcoordsp++ = LLVector2(0.f, 0.f);
*texcoordsp++ = LLVector2(1.f, 1.f);
*texcoordsp++ = LLVector2(1.f, 0.f);
}
sVB->unmapBuffer();
#endif
}
//static
@ -969,7 +912,6 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
}
}
buffer->unmapBuffer();
mFaceList.clear();
}

View File

@ -1078,7 +1078,6 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
gen_terrain_tangents(index_offset, indices_index, vertices, normals, tangents, indices, region_width);
}
buffer->unmapBuffer();
mFaceList.clear();
}

View File

@ -3873,6 +3873,7 @@ void LLPipeline::postSort(LLCamera &camera)
}
}
LLVertexBuffer::flushBuffers();
// LLSpatialGroup::sNoDelete = false;
LL_PUSH_CALLSTACKS();
}