SL-16436 and SL-16327 Fix for RenderDebugGL test failures and fix for grey textures

master
Dave Parks 2021-12-03 15:07:31 +00:00
parent 511de439a3
commit e7830b39f0
21 changed files with 166 additions and 1132 deletions

View File

@ -88,24 +88,32 @@ void APIENTRY gl_debug_callback(GLenum source,
{
if (gGLDebugLoggingEnabled)
{
if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
{
LL_WARNS() << "----- GL ERROR --------" << LL_ENDL;
}
else
{
LL_WARNS() << "----- GL WARNING -------" << LL_ENDL;
}
LL_WARNS() << "Type: " << std::hex << type << LL_ENDL;
LL_WARNS() << "ID: " << std::hex << id << LL_ENDL;
LL_WARNS() << "Severity: " << std::hex << severity << LL_ENDL;
LL_WARNS() << "Message: " << message << LL_ENDL;
LL_WARNS() << "-----------------------" << LL_ENDL;
if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
{
LL_ERRS() << "Halting on GL Error" << LL_ENDL;
}
}
if (severity != GL_DEBUG_SEVERITY_HIGH_ARB &&
severity != GL_DEBUG_SEVERITY_MEDIUM_ARB &&
severity != GL_DEBUG_SEVERITY_LOW_ARB)
{ //suppress out-of-spec messages sent by nvidia driver (mostly vertexbuffer hints)
return;
}
if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
{
LL_WARNS() << "----- GL ERROR --------" << LL_ENDL;
}
else
{
LL_WARNS() << "----- GL WARNING -------" << LL_ENDL;
}
LL_WARNS() << "Type: " << std::hex << type << LL_ENDL;
LL_WARNS() << "ID: " << std::hex << id << LL_ENDL;
LL_WARNS() << "Severity: " << std::hex << severity << LL_ENDL;
LL_WARNS() << "Message: " << message << LL_ENDL;
LL_WARNS() << "-----------------------" << LL_ENDL;
if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
{
LL_ERRS() << "Halting on GL Error" << LL_ENDL;
}
}
}
#endif

View File

@ -41,6 +41,10 @@
#include "llrender.h"
#include "llwindow.h"
#if !LL_IMAGEGL_THREAD_CHECK
#define checkActiveThread()
#endif
//----------------------------------------------------------------------------
const F32 MIN_TEXTURE_LIFETIME = 10.f;
@ -437,6 +441,10 @@ LLImageGL::~LLImageGL()
void LLImageGL::init(BOOL usemipmaps)
{
#if LL_IMAGEGL_THREAD_CHECK
mActiveThread = LLThread::currentID();
#endif
// keep these members in the same order as declared in llimagehl.h
// so that it is obvious by visual inspection if we forgot to
// init a field.
@ -1317,6 +1325,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
BOOL LLImageGL::createGLTexture()
{
LL_PROFILE_ZONE_SCOPED;
checkActiveThread();
if (gGLManager.mIsDisabled)
{
LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
@ -1349,6 +1359,8 @@ BOOL LLImageGL::createGLTexture()
BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
{
LL_PROFILE_ZONE_SCOPED;
checkActiveThread();
if (gGLManager.mIsDisabled)
{
LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
@ -1462,6 +1474,8 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
{
LL_PROFILE_ZONE_SCOPED;
checkActiveThread();
llassert(data_in);
stop_glerror();
@ -1576,6 +1590,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
// mark this as bound at this point, so we don't throw it out immediately
mLastBindTime = sLastFrameTime;
checkActiveThread();
return TRUE;
}
@ -1690,18 +1705,10 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
return TRUE ;
}
void LLImageGL::deleteDeadTextures()
{
bool reset = false;
if (reset)
{
gGL.getTexUnit(0)->activate();
}
}
void LLImageGL::destroyGLTexture()
{
checkActiveThread();
if (mTexName != 0)
{
if(mTextureMemory != S32Bytes(0))
@ -1720,6 +1727,7 @@ void LLImageGL::destroyGLTexture()
//force to invalidate the gl texture, most likely a sculpty texture
void LLImageGL::forceToInvalidateGLTexture()
{
checkActiveThread();
if (mTexName != 0)
{
destroyGLTexture();
@ -2196,6 +2204,12 @@ void LLImageGL::resetCurTexSizebar()
sCurTexPickSize = -1 ;
}
//----------------------------------------------------------------------------
#if LL_IMAGEGL_THREAD_CHECK
void LLImageGL::checkActiveThread()
{
llassert(mActiveThread == LLThread::currentID());
}
#endif
//----------------------------------------------------------------------------

View File

@ -40,7 +40,8 @@
#include "threadpool.h"
#include "workqueue.h"
class LLTextureAtlas ;
#define LL_IMAGEGL_THREAD_CHECK 0 //set to 1 to enable thread debugging for ImageGL
class LLWindow;
#define BYTES_TO_MEGA_BYTES(x) ((x) >> 20)
@ -54,7 +55,6 @@ public:
// These 2 functions replace glGenTextures() and glDeleteTextures()
static void generateTextures(S32 numTextures, U32 *textures);
static void deleteTextures(S32 numTextures, const U32 *textures);
static void deleteDeadTextures();
// Size calculation
static S32 dataFormatBits(S32 dataformat);
@ -189,6 +189,12 @@ public:
BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image);
void postAddToAtlas() ;
#if LL_IMAGEGL_THREAD_CHECK
// thread debugging
std::thread::id mActiveThread;
void checkActiveThread();
#endif
public:
// Various GL/Rendering options
S32Bytes mTextureMemory;

View File

@ -181,7 +181,11 @@ void LLTexUnit::bindFast(LLTexture* texture)
mCurrTexture = gl_tex->getTexName();
if (!mCurrTexture)
{
mCurrTexture = LLImageGL::sDefaultGLTexture->getTexName();
LL_PROFILE_ZONE_NAMED("MISSING TEXTURE");
//if deleted, will re-generate it immediately
texture->forceImmediateUpdate();
gl_tex->forceUpdateBindStats();
texture->bindDefaultImage(mIndex);
}
glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture);
mHasMipMaps = gl_tex->mHasMipMaps;

View File

@ -590,8 +590,6 @@ set(viewer_SOURCE_FILES
llsyswellwindow.cpp
llteleporthistory.cpp
llteleporthistorystorage.cpp
lltextureatlas.cpp
lltextureatlasmanager.cpp
lltexturecache.cpp
lltexturectrl.cpp
lltexturefetch.cpp
@ -1219,8 +1217,6 @@ set(viewer_HEADER_FILES
lltable.h
llteleporthistory.h
llteleporthistorystorage.h
lltextureatlas.h
lltextureatlasmanager.h
lltexturecache.h
lltexturectrl.h
lltexturefetch.h

View File

@ -40,11 +40,11 @@ VARYING vec4 post_pos;
VARYING float pos_w;
VARYING float target_pos_x;
VARYING vec2 vary_texcoord0;
VARYING vec4 vertex_color;
uniform vec4 color;
void main()
{
float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a * vertex_color.a;
float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a * color.a;
if (alpha < 0.05) // treat as totally transparent
{

View File

@ -30,7 +30,6 @@ uniform float shadow_target_width;
mat4 getSkinnedTransform();
void passTextureIndex();
ATTRIBUTE vec4 diffuse_color;
ATTRIBUTE vec3 position;
ATTRIBUTE vec3 normal;
ATTRIBUTE vec2 texcoord0;
@ -41,7 +40,6 @@ VARYING vec4 post_pos;
VARYING float pos_w;
VARYING float target_pos_x;
VARYING vec2 vary_texcoord0;
VARYING vec4 vertex_color;
void main()
{
@ -68,7 +66,6 @@ void main()
vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
vertex_color = diffuse_color;
#if !DEPTH_CLAMP
post_pos = pos;

View File

@ -64,6 +64,8 @@ class LLDrawable
{
LL_ALIGN_NEW;
public:
typedef std::vector<LLFace*> face_list_t;
LLDrawable(const LLDrawable& rhs)
: LLViewerOctreeEntryData(rhs)
{
@ -129,6 +131,7 @@ public:
inline LLFace* getFace(const S32 i) const;
inline S32 getNumFaces() const;
face_list_t& getFaces() { return mFaces; }
//void removeFace(const S32 i); // SJB: Avoid using this, it's slow
LLFace* addFace(LLFacePool *poolp, LLViewerTexture *texturep);
@ -297,8 +300,6 @@ public:
static F32 sCurPixelAngle; //current pixels per radian
private:
typedef std::vector<LLFace*> face_list_t;
U32 mState;
S32 mRenderType;
LLPointer<LLViewerObject> mVObjp;

View File

@ -92,8 +92,9 @@ void LLDrawPoolTree::render(S32 pass)
LLGLState test(GL_ALPHA_TEST, 0);
gGL.getTexUnit(sDiffTex)->bind(mTexturep);
gGL.getTexUnit(sDiffTex)->bindFast(mTexturep);
gPipeline.touchTexture(mTexturep, 1024.f * 1024.f); // <=== keep Linden tree textures at full res
for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
iter != mDrawFace.end(); iter++)
{
@ -116,9 +117,8 @@ void LLDrawPoolTree::render(S32 pass)
gPipeline.mMatrixOpCount++;
}
buff->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
buff->drawRange(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0);
gPipeline.addTrianglesDrawn(buff->getNumIndices());
buff->setBufferFast(LLDrawPoolTree::VERTEX_DATA_MASK);
buff->drawRangeFast(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0);
}
}
}

View File

@ -47,7 +47,6 @@ class LLTextureEntry;
class LLVertexProgram;
class LLViewerTexture;
class LLGeometryManager;
class LLTextureAtlasSlot;
class LLDrawInfo;
class LLMeshSkinInfo;

View File

@ -1115,6 +1115,14 @@ F32 gpu_benchmark()
// ensure matched pair of bind() and unbind() calls
ShaderBinder binder(gBenchmarkProgram);
U32 glarray = 0;
if (LLRender::sGLCoreProfile)
{
glGenVertexArrays(1, &glarray);
glBindVertexArray(glarray);
}
buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
glFinish();
@ -1147,6 +1155,13 @@ F32 gpu_benchmark()
}
}
if (LLRender::sGLCoreProfile)
{
glBindVertexArray(0);
glDeleteVertexArrays(1, &glarray);
}
std::sort(results.begin(), results.end());
F32 gbps = results[results.size()/2];

View File

@ -51,7 +51,6 @@
#include "llphysicsshapebuilderutil.h"
#include "llvoavatar.h"
#include "llvolumemgr.h"
#include "lltextureatlas.h"
#include "llviewershadermgr.h"
#include "llcontrolavatar.h"
@ -128,129 +127,6 @@ LLSpatialGroup::~LLSpatialGroup()
sNodeCount--;
clearDrawMap();
clearAtlasList() ;
}
BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp)
{
S8 type = atlasp->getComponents() - 1 ;
for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
{
if(atlasp == *iter)
{
return TRUE ;
}
}
return FALSE ;
}
void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level)
{
if(!hasAtlas(atlasp))
{
mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ;
atlasp->addSpatialGroup(this) ;
}
--recursive_level;
if(recursive_level)//levels propagating up.
{
LLSpatialGroup* parent = getParent() ;
if(parent)
{
parent->addAtlas(atlasp, recursive_level) ;
}
}
}
void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level)
{
mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ;
if(remove_group)
{
atlasp->removeSpatialGroup(this) ;
}
--recursive_level;
if(recursive_level)//levels propagating up.
{
LLSpatialGroup* parent = getParent() ;
if(parent)
{
parent->removeAtlas(atlasp, recursive_level) ;
}
}
}
void LLSpatialGroup::clearAtlasList()
{
std::list<LLTextureAtlas*>::iterator iter ;
for(S8 i = 0 ; i < 4 ; i++)
{
if(mAtlasList[i].size() > 0)
{
for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter)
{
((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ;
}
mAtlasList[i].clear() ;
}
}
}
LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level)
{
S8 type = ncomponents - 1 ;
if(mAtlasList[type].size() > 0)
{
for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
{
if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved))
{
return *iter ;
}
}
}
--recursive_level;
if(recursive_level)
{
LLSpatialGroup* parent = getParent() ;
if(parent)
{
return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ;
}
}
return NULL ;
}
void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp)
{
mCurUpdatingSlotp = slotp;
//if(!hasAtlas(mCurUpdatingSlotp->getAtlas()))
//{
// addAtlas(mCurUpdatingSlotp->getAtlas()) ;
//}
}
LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level)
{
if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep)
{
return mCurUpdatingSlotp ;
}
//--recursive_level ;
//if(recursive_level)
//{
// LLSpatialGroup* parent = getParent() ;
// if(parent)
// {
// return parent->getCurUpdatingSlot(imagep, recursive_level) ;
// }
//}
return NULL ;
}
void LLSpatialGroup::clearDrawMap()
@ -665,11 +541,7 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLO
mDistance(0.f),
mDepth(0.f),
mLastUpdateDistance(-1.f),
mLastUpdateTime(gFrameTimeSeconds),
mAtlasList(4),
mCurUpdatingTime(0),
mCurUpdatingSlotp(NULL),
mCurUpdatingTexture (NULL)
mLastUpdateTime(gFrameTimeSeconds)
{
ll_assert_aligned(this,16);

View File

@ -50,8 +50,6 @@ class LLViewerOctreePartition;
class LLSpatialPartition;
class LLSpatialBridge;
class LLSpatialGroup;
class LLTextureAtlas;
class LLTextureAtlasSlot;
class LLViewerRegion;
void pushVerts(LLFace* face, U32 mask);
@ -91,6 +89,10 @@ public:
LLPointer<LLViewerTexture> mTexture;
std::vector<LLPointer<LLViewerTexture> > mTextureList;
// virtual size of mTexture and mTextureList textures
// used to update the decode priority of textures in this DrawInfo
std::vector<F32> mTextureListVSize;
S32 mDebugColor;
const LLMatrix4* mTextureMatrix;
const LLMatrix4* mModelMatrix;
@ -304,49 +306,15 @@ public:
virtual void handleDestruction(const TreeNode* node);
virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child);
//-------------------
//for atlas use
//-------------------
//atlas
void setCurUpdatingTime(U32 t) {mCurUpdatingTime = t ;}
U32 getCurUpdatingTime() const { return mCurUpdatingTime ;}
void setCurUpdatingSlot(LLTextureAtlasSlot* slotp) ;
LLTextureAtlasSlot* getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level = 3) ;
void setCurUpdatingTexture(LLViewerTexture* tex){ mCurUpdatingTexture = tex ;}
LLViewerTexture* getCurUpdatingTexture() const { return mCurUpdatingTexture ;}
BOOL hasAtlas(LLTextureAtlas* atlasp) ;
LLTextureAtlas* getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level = 3) ;
void addAtlas(LLTextureAtlas* atlasp, S8 recursive_level = 3) ;
void removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group = TRUE, S8 recursive_level = 3) ;
void clearAtlasList() ;
public:
LL_ALIGN_16(LLVector4a mViewAngle);
LL_ALIGN_16(LLVector4a mLastUpdateViewAngle);
F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3()
private:
U32 mCurUpdatingTime ;
//do not make the below two to use LLPointer
//because mCurUpdatingTime invalidates them automatically.
LLTextureAtlasSlot* mCurUpdatingSlotp ;
LLViewerTexture* mCurUpdatingTexture ;
std::vector< std::list<LLTextureAtlas*> > mAtlasList ;
//-------------------
//end for atlas use
//-------------------
protected:
virtual ~LLSpatialGroup();
static S32 sLODSeed;
public:
bridge_list_t mBridgeList;
buffer_map_t mBufferMap; //used by volume buffers to attempt to reuse vertex buffers

View File

@ -1,416 +0,0 @@
/**
* @file lltextureatlas.cpp
* @brief LLTextureAtlas class implementation.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#include "llviewerprecompiledheaders.h"
#include "linden_common.h"
#include "llerror.h"
#include "llimage.h"
#include "llmath.h"
#include "llgl.h"
#include "llrender.h"
#include "lltextureatlas.h"
//-------------------
S16 LLTextureAtlas::sMaxSubTextureSize = 64 ;
S16 LLTextureAtlas::sSlotSize = 32 ;
#ifndef DEBUG_ATLAS
#define DEBUG_ATLAS 0
#endif
#ifndef DEBUG_USAGE_BITS
#define DEBUG_USAGE_BITS 0
#endif
//**************************************************************************************************************
LLTextureAtlas::LLTextureAtlas(U8 ncomponents, S16 atlas_dim) :
LLViewerTexture(atlas_dim * sSlotSize, atlas_dim * sSlotSize, ncomponents, TRUE),
mAtlasDim(atlas_dim),
mNumSlotsReserved(0),
mMaxSlotsInAtlas(atlas_dim * atlas_dim)
{
generateEmptyUsageBits() ;
//generate an empty texture
generateGLTexture() ;
LLPointer<LLImageRaw> image_raw = new LLImageRaw(mFullWidth, mFullHeight, mComponents);
createGLTexture(0, image_raw, 0);
image_raw = NULL;
}
LLTextureAtlas::~LLTextureAtlas()
{
if(mSpatialGroupList.size() > 0)
{
LL_ERRS() << "Not clean up the spatial groups!" << LL_ENDL ;
}
releaseUsageBits() ;
}
//virtual
S8 LLTextureAtlas::getType() const
{
return 0; //LLViewerTexture::ATLAS_TEXTURE ;
}
void LLTextureAtlas::getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yoffset)
{
xoffset = (F32)col / mAtlasDim ;
yoffset = (F32)row / mAtlasDim ;
}
void LLTextureAtlas::getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale)
{
xscale = (F32)w / (mAtlasDim * sSlotSize) ;
yscale = (F32)h / (mAtlasDim * sSlotSize) ;
}
//insert a texture piece into the atlas
LLGLuint LLTextureAtlas::insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row)
{
if(!getTexName())
{
return 0 ;
}
S32 w = raw_image->getWidth() ;
S32 h = raw_image->getHeight() ;
if(w < 8 || w > sMaxSubTextureSize || h < 8 || h > sMaxSubTextureSize)
{
//size overflow
return 0 ;
}
BOOL res = gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, getTexName());
if (!res)
{
LL_ERRS() << "bindTexture failed" << LL_ENDL;
}
GLint xoffset = sSlotSize * slot_col ;
GLint yoffset = sSlotSize * slot_row ;
if(!source_gl_tex->preAddToAtlas(discard_level, raw_image))
{
return 0 ;
}
glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h,
mGLTexturep->getPrimaryFormat(), mGLTexturep->getFormatType(), raw_image->getData());
source_gl_tex->postAddToAtlas() ;
return getTexName();
}
//release a sub-texture slot from the atlas
void LLTextureAtlas::releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width)
{
unmarkUsageBits(slot_width, slot_col, slot_row) ;
mNumSlotsReserved -= slot_width * slot_width ;
}
BOOL LLTextureAtlas::isEmpty() const
{
return !mNumSlotsReserved ;
}
BOOL LLTextureAtlas::isFull(S8 to_be_reserved) const
{
return mNumSlotsReserved + to_be_reserved > mMaxSlotsInAtlas ;
}
F32 LLTextureAtlas::getFullness() const
{
return (F32)mNumSlotsReserved / mMaxSlotsInAtlas ;
}
void LLTextureAtlas::addSpatialGroup(LLSpatialGroup* groupp)
{
if(groupp && !hasSpatialGroup(groupp))
{
mSpatialGroupList.push_back(groupp);
}
}
void LLTextureAtlas::removeSpatialGroup(LLSpatialGroup* groupp)
{
if(groupp)
{
mSpatialGroupList.remove(groupp);
}
}
void LLTextureAtlas::clearSpatialGroup()
{
mSpatialGroupList.clear();
}
void LLTextureAtlas::removeLastSpatialGroup()
{
mSpatialGroupList.pop_back() ;
}
LLSpatialGroup* LLTextureAtlas::getLastSpatialGroup()
{
if(mSpatialGroupList.size() > 0)
{
return mSpatialGroupList.back() ;
}
return NULL ;
}
BOOL LLTextureAtlas::hasSpatialGroup(LLSpatialGroup* groupp)
{
for(std::list<LLSpatialGroup*>::iterator iter = mSpatialGroupList.begin(); iter != mSpatialGroupList.end() ; ++iter)
{
if(*iter == groupp)
{
return TRUE ;
}
}
return FALSE ;
}
//--------------------------------------------------------------------------------------
//private
void LLTextureAtlas::generateEmptyUsageBits()
{
S32 col_len = (mAtlasDim + 7) >> 3 ;
mUsageBits = new U8*[mAtlasDim] ;
*mUsageBits = new U8[mAtlasDim * col_len] ;
mUsageBits[0] = *mUsageBits ;
for(S32 i = 1 ; i < mAtlasDim ; i++)
{
mUsageBits[i] = mUsageBits[i-1] + col_len ;
for(S32 j = 0 ; j < col_len ; j++)
{
//init by 0 for all bits.
mUsageBits[i][j] = 0 ;
}
}
//do not forget mUsageBits[0]!
for(S32 j = 0 ; j < col_len ; j++)
{
//init by 0 for all bits.
mUsageBits[0][j] = 0 ;
}
mTestBits = NULL ;
#if DEBUG_USAGE_BITS
//------------
//test
mTestBits = new U8*[mAtlasDim] ;
*mTestBits = new U8[mAtlasDim * mAtlasDim] ;
mTestBits[0] = *mTestBits ;
for(S32 i = 1 ; i < mAtlasDim ; i++)
{
mTestBits[i] = mTestBits[i-1] + mAtlasDim ;
for(S32 j = 0 ; j < mAtlasDim ; j++)
{
//init by 0 for all bits.
mTestBits[i][j] = 0 ;
}
}
for(S32 j = 0 ; j < mAtlasDim ; j++)
{
//init by 0 for all bits.
mTestBits[0][j] = 0 ;
}
#endif
}
void LLTextureAtlas::releaseUsageBits()
{
if(mUsageBits)
{
delete[] *mUsageBits ;
delete[] mUsageBits ;
}
mUsageBits = NULL ;
//test
if( mTestBits)
{
delete[] *mTestBits;
delete[] mTestBits;
}
mTestBits = NULL ;
}
void LLTextureAtlas::markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row)
{
S16 x = col >> 3 ;
for(S8 i = 0 ; i < bits_len ; i++)
{
mUsageBits[row + i][x] |= mask ;
}
#if DEBUG_USAGE_BITS
//test
for(S8 i = row ; i < row + bits_len ; i++)
{
for(S8 j = col ; j < col + bits_len ; j++)
{
mTestBits[i][j] = 1 ;
}
}
#endif
}
void LLTextureAtlas::unmarkUsageBits(S8 bits_len, S16 col, S16 row)
{
S16 x = col >> 3 ;
U8 mask = 1 ;
for(S8 i = 1 ; i < bits_len ; i++)
{
mask |= (1 << i) ;
}
mask <<= (col & 7) ;
mask = ~mask ;
for(S8 i = 0 ; i < bits_len ; i++)
{
mUsageBits[row + i][x] &= mask ;
}
#if DEBUG_USAGE_BITS
//test
for(S8 i = row ; i < row + bits_len ; i++)
{
for(S8 j = col ; j < col + bits_len ; j++)
{
mTestBits[i][j] = 0 ;
}
}
#endif
}
//return true if any of bits in the range marked.
BOOL LLTextureAtlas::areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row)
{
BOOL ret = FALSE ;
S16 x = col >> 3 ;
for(S8 i = 0 ; i < bits_len ; i++)
{
if(mUsageBits[row + i][x] & mask)
{
ret = TRUE ;
break ;
//return TRUE ;
}
}
#if DEBUG_USAGE_BITS
//test
BOOL ret2 = FALSE ;
for(S8 i = row ; i < row + bits_len ; i++)
{
for(S8 j = col ; j < col + bits_len ; j++)
{
if(mTestBits[i][j])
{
ret2 = TRUE ;
}
}
}
if(ret != ret2)
{
LL_ERRS() << "bits map corrupted." << LL_ENDL ;
}
#endif
return ret ;//FALSE ;
}
//----------------------------------------------------------------------
//
//index order: Z order, i.e.:
// |-----|-----|-----|-----|
// | 10 | 11 | 14 | 15 |
// |-----|-----|-----|-----|
// | 8 | 9 | 12 | 13 |
// |-----|-----|-----|-----|
// | 2 | 3 | 6 | 7 |
// |-----|-----|-----|-----|
// | 0 | 1 | 4 | 5 |
// |-----|-----|-----|-----|
void LLTextureAtlas::getPositionFromIndex(S16 index, S16& col, S16& row)
{
col = 0 ;
row = 0 ;
S16 index_copy = index ;
for(S16 i = 0 ; index_copy && i < 16 ; i += 2)
{
col |= ((index & (1 << i)) >> i) << (i >> 1) ;
row |= ((index & (1 << (i + 1))) >> (i + 1)) << (i >> 1) ;
index_copy >>= 2 ;
}
}
void LLTextureAtlas::getIndexFromPosition(S16 col, S16 row, S16& index)
{
index = 0 ;
S16 col_copy = col ;
S16 row_copy = row ;
for(S16 i = 0 ; (col_copy || row_copy) && i < 16 ; i++)
{
index |= ((col & 1 << i) << i) | ((row & 1 << i) << ( i + 1)) ;
col_copy >>= 1 ;
row_copy >>= 1 ;
}
}
//----------------------------------------------------------------------
//return TRUE if succeeds.
BOOL LLTextureAtlas::getNextAvailableSlot(S8 bits_len, S16& col, S16& row)
{
S16 index_step = bits_len * bits_len ;
U8 mask = 1 ;
for(S8 i = 1 ; i < bits_len ; i++)
{
mask |= (1 << i) ;
}
U8 cur_mask ;
for(S16 index = 0 ; index < mMaxSlotsInAtlas ; index += index_step)
{
getPositionFromIndex(index, col, row) ;
cur_mask = mask << (col & 7) ;
if(!areUsageBitsMarked(bits_len, cur_mask, col, row))
{
markUsageBits(bits_len, cur_mask, col, row) ;
mNumSlotsReserved += bits_len * bits_len ;
return TRUE ;
}
}
return FALSE ;
}

View File

@ -1,90 +0,0 @@
/**
* @file lltextureatlas.h
* @brief LLTextureAtlas base class.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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_TEXTUREATLAS_H
#define LL_TEXTUREATLAS_H
#include "llviewertexture.h"
class LLSpatialGroup ;
class LLTextureAtlas : public LLViewerTexture
{
protected:
/*virtual*/ ~LLTextureAtlas() ;
public:
LLTextureAtlas(U8 ncomponents, S16 atlas_dim = 16) ;
/*virtual*/ S8 getType() const;
LLGLuint insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row) ;
void releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width);
BOOL getNextAvailableSlot(S8 bits_len, S16& col, S16& row) ;
void getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yOffset) ;
void getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale) ;
BOOL isEmpty() const ;
BOOL isFull(S8 to_be_reserved = 1) const ;
F32 getFullness() const ;
void addSpatialGroup(LLSpatialGroup* groupp) ;
void removeSpatialGroup(LLSpatialGroup* groupp) ;
LLSpatialGroup* getLastSpatialGroup() ;
void removeLastSpatialGroup() ;
BOOL hasSpatialGroup(LLSpatialGroup* groupp) ;
void clearSpatialGroup() ;
std::list<LLSpatialGroup*>* getSpatialGroupList() {return &mSpatialGroupList;}
private:
void generateEmptyUsageBits() ;
void releaseUsageBits() ;
void markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row) ;
void unmarkUsageBits(S8 bits_len, S16 col, S16 row) ;
void getPositionFromIndex(S16 index, S16& col, S16& row) ;
void getIndexFromPosition(S16 col, S16 row, S16& index) ;
BOOL areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row) ;
private:
S16 mAtlasDim ; //number of slots per edge, i.e, there are "mAtlasDim * mAtlasDim" total slots in the atlas.
S16 mNumSlotsReserved ;
S16 mMaxSlotsInAtlas ;
U8 **mUsageBits ;
std::list<LLSpatialGroup*> mSpatialGroupList ;
public:
//debug use only
U8 **mTestBits ;
public:
static S16 sMaxSubTextureSize ;
static S16 sSlotSize ;
};
#endif

View File

@ -1,268 +0,0 @@
/**
* @file lltextureatlasmanager.cpp
* @brief LLTextureAtlasManager class implementation.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#include "llviewerprecompiledheaders.h"
#include "linden_common.h"
#include "llerror.h"
#include "llmath.h"
#include "lltextureatlas.h"
#include "lltextureatlasmanager.h"
#include "llspatialpartition.h"
const S8 MAX_NUM_EMPTY_ATLAS = 2 ;
const F32 MIN_ATLAS_FULLNESS = 0.6f ;
//*********************************************************************************************
//implementation of class LLTextureAtlasInfo
//*********************************************************************************************
LLTextureAtlasSlot::LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) :
mAtlasp(atlasp),
mGroupp(groupp),
mCol(col),
mRow(row),
mReservedSlotWidth(slot_width),
mValid(FALSE),
mUpdatedTime(0),
mTexCoordOffset(xoffset, yoffset),
mTexCoordScale(1.f, 1.f)
{
llassert_always(mAtlasp || mGroupp || mReservedSlotWidth) ;
}
LLTextureAtlasSlot::~LLTextureAtlasSlot()
{
if(mAtlasp)
{
mAtlasp->releaseSlot(mCol, mRow, mReservedSlotWidth) ;
if(mAtlasp->isEmpty())
{
LLTextureAtlasManager::getInstance()->releaseAtlas(mAtlasp) ;
}
mAtlasp = NULL ;
}
}
//void LLTextureAtlasSlot::setAtlas(LLTextureAtlas* atlasp)
//{
// mAtlasp = atlasp ;
//}
//void LLTextureAtlasSlot::setSlotPos(S16 col, S16 row)
//{
// mCol = col ;
// mRow = row ;
//}
//void LLTextureAtlasSlot::setSlotWidth(S8 width)
//{
// //slot is a square with each edge length a power-of-two number
// mReservedSlotWidth = width ;
//}
//void LLTextureAtlasSlot::setTexCoordOffset(F32 xoffset, F32 yoffset)
//{
// mTexCoordOffset.mV[0] = xoffset ;
// mTexCoordOffset.mV[1] = yoffset ;
//}
void LLTextureAtlasSlot::setSpatialGroup(LLSpatialGroup* groupp)
{
mGroupp = groupp ;
}
void LLTextureAtlasSlot::setTexCoordScale(F32 xscale, F32 yscale)
{
mTexCoordScale.mV[0] = xscale ;
mTexCoordScale.mV[1] = yscale ;
}
//*********************************************************************************************
//END of implementation of class LLTextureAtlasInfo
//*********************************************************************************************
//*********************************************************************************************
//implementation of class LLTextureAtlasManager
//*********************************************************************************************
LLTextureAtlasManager::LLTextureAtlasManager() :
mAtlasMap(4),
mEmptyAtlasMap(4)
{
}
LLTextureAtlasManager::~LLTextureAtlasManager()
{
for(S32 i = 0 ; i < 4 ; i++)
{
for(ll_texture_atlas_list_t::iterator j = mAtlasMap[i].begin() ; j != mAtlasMap[i].end() ; ++j)
{
*j = NULL ;
}
for(ll_texture_atlas_list_t::iterator j = mEmptyAtlasMap[i].begin() ; j != mEmptyAtlasMap[i].end() ; ++j)
{
*j = NULL ;
}
mAtlasMap[i].clear() ;
mEmptyAtlasMap[i].clear() ;
}
mAtlasMap.clear() ;
mEmptyAtlasMap.clear() ;
}
//return TRUE if qualified
BOOL LLTextureAtlasManager::canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target)
{
if(ncomponents < 1 || ncomponents > 4)
{
return FALSE ;
}
//only support GL_TEXTURE_2D
if(GL_TEXTURE_2D != target)
{
return FALSE ;
}
//real image size overflows
if(w < 8 || w > LLTextureAtlas::sMaxSubTextureSize || h < 8 || h > LLTextureAtlas::sMaxSubTextureSize)
{
return FALSE ;
}
//if non-power-of-two number
if((w & (w - 1)) || (h & (h - 1)))
{
return FALSE ;
}
return TRUE ;
}
void LLTextureAtlasManager::releaseAtlas(LLTextureAtlas* atlasp)
{
LLSpatialGroup* groupp = atlasp->getLastSpatialGroup() ;
while(groupp)
{
groupp->removeAtlas(atlasp, FALSE) ;
atlasp->removeLastSpatialGroup() ;
groupp = atlasp->getLastSpatialGroup() ;
}
S8 type = atlasp->getComponents() - 1 ;
//insert to the empty list
if(mEmptyAtlasMap[type].size() < MAX_NUM_EMPTY_ATLAS)
{
mEmptyAtlasMap[type].push_back(atlasp) ;
}
//delete the atlasp
mAtlasMap[type].remove(atlasp) ;
}
//
//this function reserves an appropriate slot from atlas pool for an image.
//return non-NULL if succeeds.
//Note:
//1, this function does not check if the image this slot assigned for qualifies for atlas or not,
// call LLTextureAtlasManager::canAddToAtlas(...) to do the check before calling this function.
//2, this function also dose not check if the image is already in atlas. It always assigns a new slot anyway.
//3, this function tries to group sub-textures from same spatial group into ONE atlas to improve render batching.
//
LLPointer<LLTextureAtlasSlot> LLTextureAtlasManager::reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents,
LLSpatialGroup* groupp, LLViewerTexture* imagep)
{
if(!groupp)
{
//do not insert to atlas if does not have a group.
return NULL ;
}
//bits_len must <= 8 and is a power of two number, i.e.: must be one of these numbers: 1, 2, 4, 8.
if(sub_texture_size > LLTextureAtlas::sMaxSubTextureSize)
{
sub_texture_size = LLTextureAtlas::sMaxSubTextureSize ;
}
S8 bits_len = sub_texture_size / LLTextureAtlas::sSlotSize ;
if(bits_len < 1)
{
bits_len = 1 ;
}
S16 col = -1, row = -1;
S8 total_bits = bits_len * bits_len ;
//insert to the atlas reserved by the same spatial group
LLPointer<LLTextureAtlas> atlasp = groupp->getAtlas(ncomponents, total_bits) ;
if(atlasp.notNull())
{
if(!atlasp->getNextAvailableSlot(bits_len, col, row))
{
//failed
atlasp = NULL ;
}
}
//search an atlas to fit for 'size'
if(!atlasp)
{
S8 atlas_index = ncomponents - 1 ;
ll_texture_atlas_list_t::iterator iter = mAtlasMap[atlas_index].begin() ;
for(; iter != mAtlasMap[atlas_index].end(); ++iter)
{
LLTextureAtlas* cur = (LLTextureAtlas*)*iter ;
if(cur->getFullness() < MIN_ATLAS_FULLNESS)//this atlas is empty enough for this group to insert more sub-textures later if necessary.
{
if(cur->getNextAvailableSlot(bits_len, col, row))
{
atlasp = cur ;
groupp->addAtlas(atlasp) ;
break ;
}
}
}
}
//create a new atlas if necessary
if(!atlasp)
{
if(mEmptyAtlasMap[ncomponents - 1].size() > 0)
{
//there is an empty one
atlasp = mEmptyAtlasMap[ncomponents - 1].back() ;
mEmptyAtlasMap[ncomponents - 1].pop_back() ;
}
else
{
atlasp = new LLTextureAtlas(ncomponents, 16) ;
}
mAtlasMap[ncomponents - 1].push_back(atlasp) ;
atlasp->getNextAvailableSlot(bits_len, col, row) ;
groupp->addAtlas(atlasp) ;
}
F32 xoffset, yoffset ;
atlasp->getTexCoordOffset(col, row, xoffset, yoffset) ;
LLPointer<LLTextureAtlasSlot> slot_infop = new LLTextureAtlasSlot(atlasp, groupp, col, row, xoffset, yoffset, bits_len) ;
return slot_infop ;
}
//*********************************************************************************************
//END of implementation of class LLTextureAtlasManager
//*********************************************************************************************

View File

@ -1,105 +0,0 @@
/**
* @file lltextureatlasmanager.h
* @brief LLTextureAtlasManager base class.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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_TEXTUREATLASMANAGER_H
#define LL_TEXTUREATLASMANAGER_H
#include "llmemory.h"
class LLSpatialGroup ;
class LLViewerTexture ;
//just use it as a structure.
class LLTextureAtlasSlot : public LLRefCount
{
public:
LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) ;
protected:
virtual ~LLTextureAtlasSlot();
public:
//
//do not allow to change those values
//
//void setAtlas(LLTextureAtlas* atlasp) ;
//void setSlotPos(S16 col, S16 row) ;
//void setSlotWidth(S8 width) ;
//void setTexCoordOffset(F32 xoffser, F32 yoffset) ;
//
void setSpatialGroup(LLSpatialGroup* groupp) ;
void setTexCoordScale(F32 xscale, F32 yscale) ;
void setValid() {mValid = TRUE ;}
LLTextureAtlas* getAtlas()const {return mAtlasp;}
LLSpatialGroup* getSpatialGroup() const {return mGroupp ;}
S16 getSlotCol()const {return mCol;}
S16 getSlotRow()const {return mRow;}
S8 getSlotWidth()const{return mReservedSlotWidth;}
BOOL isValid()const { return mValid;}
const LLVector2* getTexCoordOffset()const {return &mTexCoordOffset;}
const LLVector2* getTexCoordScale() const {return &mTexCoordScale;}
void setUpdatedTime(U32 t) {mUpdatedTime = t;}
U32 getUpdatedTime()const {return mUpdatedTime;}
private:
LLTextureAtlas* mAtlasp;
S16 mCol ;//col of the slot
S16 mRow ;//row of the slot
S8 mReservedSlotWidth ; //slot is a square with each edge length a power-of-two number
LLSpatialGroup* mGroupp ;
BOOL mValid ;
LLVector2 mTexCoordOffset ;
LLVector2 mTexCoordScale ;
U32 mUpdatedTime ;
} ;
class LLTextureAtlasManager : public LLSingleton<LLTextureAtlasManager>
{
LLSINGLETON(LLTextureAtlasManager);
~LLTextureAtlasManager();
typedef std::list<LLPointer<LLTextureAtlas> > ll_texture_atlas_list_t ;
public:
LLPointer<LLTextureAtlasSlot> reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents,
LLSpatialGroup* groupp, LLViewerTexture* imagep) ;
void releaseAtlas(LLTextureAtlas* atlasp);
BOOL canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) ;
private:
std::vector<ll_texture_atlas_list_t> mAtlasMap ;
std::vector<ll_texture_atlas_list_t> mEmptyAtlasMap ; //delay some empty atlases deletion to avoid possible creation of new atlas immediately.
};
#endif

View File

@ -1476,6 +1476,10 @@ void LLViewerFetchedTexture::addToCreateTexture()
BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)
{
LL_PROFILE_ZONE_SCOPED;
#if LL_IMAGEGL_THREAD_CHECK
mGLTexturep->checkActiveThread();
#endif
if (!mNeedsCreateTexture)
{
destroyRawImage();
@ -1603,6 +1607,9 @@ void LLViewerFetchedTexture::postCreateTexture()
{
return;
}
#if LL_IMAGEGL_THREAD_CHECK
mGLTexturep->checkActiveThread();
#endif
notifyAboutCreatingTexture();
@ -1619,36 +1626,45 @@ void LLViewerFetchedTexture::postCreateTexture()
void LLViewerFetchedTexture::scheduleCreateTexture()
{
ref();
mNeedsCreateTexture = TRUE;
if (preCreateTexture())
if (!mNeedsCreateTexture)
{
ref();
mNeedsCreateTexture = TRUE;
if (preCreateTexture())
{
mNeedsCreateTexture = TRUE;
#if LL_WINDOWS //flip to 0 to revert to single-threaded OpenGL texture uploads
auto mainq = mMainQueue.lock();
if (mainq)
{
mainq->postTo(
mImageQueue,
// work to be done on LLImageGL worker thread
[this]()
{
//actually create the texture on a background thread
createTexture();
},
// callback to be run on main thread
[this]()
{
//finalize on main thread
postCreateTexture();
unref();
});
}
else
auto mainq = mMainQueue.lock();
if (mainq)
{
mainq->postTo(
mImageQueue,
// work to be done on LLImageGL worker thread
[this]()
{
#if LL_IMAGEGL_THREAD_CHECK
mGLTexturep->mActiveThread = LLThread::currentID();
#endif
{
gTextureList.mCreateTextureList.insert(this);
unref();
//actually create the texture on a background thread
createTexture();
},
// callback to be run on main thread
[this]()
{
#if LL_IMAGEGL_THREAD_CHECK
mGLTexturep->mActiveThread = LLThread::currentID();
#endif
//finalize on main thread
postCreateTexture();
unref();
});
}
else
#endif
{
gTextureList.mCreateTextureList.insert(this);
unref();
}
}
}
}
@ -2967,7 +2983,8 @@ void LLViewerFetchedTexture::destroyRawImage()
void LLViewerFetchedTexture::switchToCachedImage()
{
LL_PROFILE_ZONE_SCOPED;
if(mCachedRawImage.notNull())
if(mCachedRawImage.notNull() &&
!mNeedsCreateTexture) // <--- texture creation is pending, don't step on it
{
mRawImage = mCachedRawImage;

View File

@ -5189,6 +5189,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
}
}
F32 vsize = facep->getVirtualSize(); //TODO -- adjust by texture scale?
if (index < FACE_DO_NOT_BATCH_TEXTURES && idx >= 0)
{
@ -5202,10 +5203,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
{
batchable = true;
draw_vec[idx]->mTextureList[index] = tex;
draw_vec[idx]->mTextureListVSize[index] = vsize;
}
else if (draw_vec[idx]->mTextureList[index] == tex)
{ //this face's texture index can be used with this batch
batchable = true;
draw_vec[idx]->mTextureListVSize[index] = llmax(vsize, draw_vec[idx]->mTextureListVSize[index]);
}
}
else
@ -5236,12 +5239,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
{
draw_vec[idx]->mCount += facep->getIndicesCount();
draw_vec[idx]->mEnd += facep->getGeomCount();
draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
if (index < FACE_DO_NOT_BATCH_TEXTURES && index >= draw_vec[idx]->mTextureList.size())
{
draw_vec[idx]->mTextureList.resize(index+1);
draw_vec[idx]->mTextureList[index] = tex;
draw_vec[idx]->mTextureListVSize.resize(index + 1);
draw_vec[idx]->mTextureListVSize[index] = vsize;
}
draw_vec[idx]->validate();
update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
@ -5256,7 +5261,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex,
facep->getVertexBuffer(), selected, fullbright, bump);
draw_info->mGroup = group;
draw_info->mVSize = facep->getVirtualSize();
draw_info->mVSize = vsize;
draw_vec.push_back(draw_info);
draw_info->mTextureMatrix = tex_mat;
draw_info->mModelMatrix = model_mat;
@ -5331,6 +5336,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
{ //initialize texture list for texture batching
draw_info->mTextureList.resize(index+1);
draw_info->mTextureList[index] = tex;
draw_info->mTextureListVSize.resize(index + 1);
draw_info->mTextureListVSize[index] = vsize;
}
draw_info->validate();
}

View File

@ -3711,25 +3711,31 @@ void renderSoundHighlights(LLDrawable* drawablep)
}
}
void LLPipeline::touchTextures(LLDrawInfo* info)
void LLPipeline::touchTexture(LLViewerTexture* tex, F32 vsize)
{
LL_PROFILE_ZONE_SCOPED;
for (auto& tex : info->mTextureList)
if (tex)
{
if (tex.notNull())
LLImageGL* gl_tex = tex->getGLTexture();
if (gl_tex && gl_tex->updateBindStats(gl_tex->mTextureMemory))
{
LLImageGL* gl_tex = tex->getGLTexture();
if (gl_tex && gl_tex->updateBindStats(gl_tex->mTextureMemory))
{
tex->setActive();
}
tex->setActive();
tex->addTextureStats(vsize);
}
}
if (info->mTexture.notNull())
}
void LLPipeline::touchTextures(LLDrawInfo* info)
{
LL_PROFILE_ZONE_SCOPED;
for (int i = 0; i < info->mTextureList.size(); ++i)
{
info->mTexture->addTextureStats(info->mVSize);
touchTexture(info->mTextureList[i], info->mTextureListVSize[i]);
}
touchTexture(info->mTexture, info->mVSize);
touchTexture(info->mSpecularMap, info->mVSize);
touchTexture(info->mNormalMap, info->mVSize);
}
void LLPipeline::postSort(LLCamera& camera)

View File

@ -260,8 +260,11 @@ public:
void stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed = FALSE);
void stateSort(LLDrawable* drawablep, LLCamera& camera);
void postSort(LLCamera& camera);
//update stats for textures in given DrawInfo
void touchTextures(LLDrawInfo* info);
void touchTexture(LLViewerTexture* tex, F32 vsize);
void forAllVisibleDrawables(void (*func)(LLDrawable*));
void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);