diff options
Diffstat (limited to 'indra')
52 files changed, 1335 insertions, 746 deletions
| diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index 29a5ca6f24..5cbd346411 100644 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -29,6 +29,9 @@  #include "llerror.h" +// maximum reference count before sounding memory leak alarm +const S32 gMaxRefCount = 65536; +  LLRefCount::LLRefCount(const LLRefCount& other)  :	mRef(0)  { @@ -47,7 +50,7 @@ LLRefCount::LLRefCount() :  LLRefCount::~LLRefCount()  {  -	if (mRef != 0) +	if (mRef != LL_REFCOUNT_FREE && mRef != 0)  	{  		LL_ERRS() << "deleting non-zero reference" << LL_ENDL;  	} diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 7e4af6ea66..2080da1565 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -37,6 +37,10 @@ class LLMutex;  // see llthread.h for LLThreadSafeRefCount  //---------------------------------------------------------------------------- +//nonsense but recognizable value for freed LLRefCount (aids in debugging) +#define LL_REFCOUNT_FREE 1234567890 +extern const S32 gMaxRefCount; +  class LL_COMMON_API LLRefCount  {  protected: @@ -47,17 +51,25 @@ protected:  public:  	LLRefCount(); +    inline void validateRefCount() const +    { +        llassert(mRef > 0); // ref count below 0, likely corrupted +        llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak +    } +  	inline void ref() const  	{   		mRef++;  +        validateRefCount();  	}   	inline S32 unref() const  	{ -		llassert(mRef >= 1); +        validateRefCount();  		if (0 == --mRef)  		{ -			delete this;  +            mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging +			delete this;  			return 0;  		}  		return mRef; diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 15b07e5318..5fa19ce9c6 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -860,6 +860,12 @@ U8* LLImageRaw::reallocateData(S32 size)  	return res;  } +void LLImageRaw::releaseData() +{ +    LLImageBase::setSize(0, 0, 0); +    LLImageBase::setDataAndSize(nullptr, 0); +} +  // virtual  void LLImageRaw::deleteData()  { diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 354926ee58..7a588cfb03 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -191,6 +191,12 @@ public:  	/*virtual*/ void deleteData();  	/*virtual*/ U8* allocateData(S32 size = -1);  	/*virtual*/ U8* reallocateData(S32 size); + +    // use in conjunction with "no_copy" constructor to release data pointer before deleting +    // so that deletion of this LLImageRaw will not free the memory at the "data" parameter  +    // provided to "no_copy" constructor +    void releaseData(); +  	bool resize(U16 width, U16 height, S8 components); diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index fd20024f7e..efa1a4076b 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -88,7 +88,7 @@ const F32 SKEW_MAX	=  0.95f;  const F32 SCULPT_MIN_AREA = 0.002f;  const S32 SCULPT_MIN_AREA_DETAIL = 1; -BOOL gDebugGL = FALSE; +BOOL gDebugGL = FALSE; // See settings.xml "RenderDebugGL"  BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)  {     diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 12da961cef..639d1fba32 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -757,17 +757,6 @@ bool LLGLManager::initGL()  	stop_glerror(); -#if LL_WINDOWS -	if (mHasDebugOutput && gDebugGL) -	{ //setup debug output callback -		//glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE); -		glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL); -		glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); -	} -#endif - -	stop_glerror(); -  	//HACK always disable texture multisample, use FXAA instead  	mHasTextureMultisample = FALSE;  #if LL_WINDOWS @@ -1029,7 +1018,9 @@ void LLGLManager::initExtensions()  	mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);  	mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);  	mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts); -	mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts); +    // NOTE: Using extensions breaks reflections when Shadows are set to projector.  See: SL-16727 +    //mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts); +    mHasDepthClamp = FALSE;  	// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad  #ifdef GL_ARB_framebuffer_object  	mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts); @@ -2159,95 +2150,6 @@ LLGLUserClipPlane::~LLGLUserClipPlane()  	disable();  } -LLGLNamePool::LLGLNamePool() -{ -} - -LLGLNamePool::~LLGLNamePool() -{ -} - -void LLGLNamePool::upkeep() -{ -	std::sort(mNameList.begin(), mNameList.end(), CompareUsed()); -} - -void LLGLNamePool::cleanup() -{ -	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter) -	{ -		releaseName(iter->name); -	} - -	mNameList.clear(); -} - -GLuint LLGLNamePool::allocate() -{ -    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; -#if LL_GL_NAME_POOLING -	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter) -	{ -		if (!iter->used) -		{ -			iter->used = TRUE; -			return iter->name; -		} -	} - -	NameEntry entry; -	entry.name = allocateName(); -	entry.used = TRUE; -	mNameList.push_back(entry); - -	return entry.name; -#else -	return allocateName(); -#endif -} - -void LLGLNamePool::release(GLuint name) -{ -#if LL_GL_NAME_POOLING -	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter) -	{ -		if (iter->name == name) -		{ -			if (iter->used) -			{ -				iter->used = FALSE; -				return; -			} -			else -			{ -				LL_ERRS() << "Attempted to release a pooled name that is not in use!" << LL_ENDL; -			} -		} -	} -	LL_ERRS() << "Attempted to release a non pooled name!" << LL_ENDL; -#else -	releaseName(name); -#endif -} - -//static -void LLGLNamePool::upkeepPools() -{ -	for (auto& pool : instance_snapshot()) -	{ -		pool.upkeep(); -	} -} - -//static -void LLGLNamePool::cleanupPools() -{ -	for (auto& pool : instance_snapshot()) -	{ -		pool.cleanup(); -	} -} -  LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, GLenum depth_func)  : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled)  { @@ -2469,3 +2371,4 @@ extern "C"  }  #endif + diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index ec97eb0faa..52338364e6 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -367,51 +367,6 @@ public:  };  /* -	Generic pooling scheme for things which use GL names (used for occlusion queries and vertex buffer objects). -	Prevents thrashing of GL name caches by avoiding calls to glGenFoo and glDeleteFoo. -*/ -class LLGLNamePool : public LLInstanceTracker<LLGLNamePool> -{ -public: -	typedef LLInstanceTracker<LLGLNamePool> tracker_t; - -	struct NameEntry -	{ -		GLuint name; -		BOOL used; -	}; - -	struct CompareUsed -	{ -		bool operator()(const NameEntry& lhs, const NameEntry& rhs) -		{ -			return lhs.used < rhs.used;  //FALSE entries first -		} -	}; - -	typedef std::vector<NameEntry> name_list_t; -	name_list_t mNameList; - -	LLGLNamePool(); -	virtual ~LLGLNamePool(); -	 -	void upkeep(); -	void cleanup(); -	 -	GLuint allocate(); -	void release(GLuint name); -	 -	static void upkeepPools(); -	static void cleanupPools(); - -protected: -	typedef std::vector<LLGLNamePool*> pool_list_t; -	 -	virtual GLuint allocateName() = 0; -	virtual void releaseName(GLuint name) = 0; -}; - -/*  	Interface for objects that need periodic GL updates applied to them.  	Used to synchronize GL updates with GL thread.  */ diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index b6a02f1c0a..e012eb9a62 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -164,11 +164,11 @@ BOOL LLGLTexture::createGLTexture()  	return mGLTexturep->createGLTexture() ;  } -BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category) +BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category, bool defer_copy, LLGLuint* tex_name)  { -	llassert(mGLTexturep.notNull()) ;	 +	llassert(mGLTexturep.notNull()); -	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ; +	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category, defer_copy, tex_name) ;  	if(ret)  	{ @@ -260,20 +260,20 @@ LLTexUnit::eTextureType LLGLTexture::getTarget(void) const  	return mGLTexturep->getTarget() ;  } -BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height) +BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;  	llassert(mGLTexturep.notNull()) ; -	return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ; +	return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height, 0, use_name) ;  } -BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) +BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;  	llassert(mGLTexturep.notNull()) ; -	return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ; +	return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height, 0, use_name) ;  }  void LLGLTexture::setGLTextureCreated (bool initialized) diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 028457c510..8cfe7b62de 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -124,13 +124,22 @@ public:  	BOOL       hasGLTexture() const ;  	LLGLuint   getTexName() const ;		  	BOOL       createGLTexture() ; -	BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER); +	 +    // Create a GL Texture from an image raw +    // discard_level - mip level, 0 for highest resultion mip +    // imageraw - the image to copy from +    // usename - explicit GL name override +    // to_create - set to FALSE to force gl texture to not be created +    // category - LLGLTexture category for this LLGLTexture +    // defer_copy - set to true to allocate GL texture but NOT initialize with imageraw data +    // tex_name - if not null, will be set to the GL name of the texture created +    BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER, bool defer_copy = false, LLGLuint* tex_name = nullptr);  	void       setFilteringOption(LLTexUnit::eTextureFilterOptions option);  	void       setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);  	void       setAddressMode(LLTexUnit::eTextureAddressMode mode); -	BOOL       setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height); -	BOOL       setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height); +	BOOL       setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name = 0); +	BOOL       setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name = 0);  	void       setGLTextureCreated (bool initialized);  	void       setCategory(S32 category) ;      void       setTexName(LLGLuint); // for forcing w/ externally created textures only diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 1e9b9f642e..f43671dee5 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -40,6 +40,7 @@  #include "llglslshader.h"  #include "llrender.h"  #include "llwindow.h" +#include "llframetimer.h"  #if !LL_IMAGEGL_THREAD_CHECK  #define checkActiveThread() @@ -436,7 +437,7 @@ LLImageGL::LLImageGL(  LLImageGL::~LLImageGL()  { -    if (!mExternalTexture) +    if (!mExternalTexture && gGLManager.mInited)      {  	    LLImageGL::cleanup();  	    sImageList.erase(this); @@ -550,7 +551,7 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve  	if (width != mWidth || height != mHeight || ncomponents != mComponents)  	{  		// Check if dimensions are a power of two! -		if (!checkSize(width,height)) +		if (!checkSize(width, height))  		{  			LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL;  			return false; @@ -674,7 +675,7 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)  	setImage(rawdata, FALSE);  } -BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename) +BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 usename /* = 0 */)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;  	bool is_compressed = false; @@ -709,8 +710,14 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename)      gGL.getTexUnit(0)->bind(this, false, false, usename); - -    if (mUseMipMaps) +    if (data_in == nullptr) +    { +        S32 w = getWidth(); +        S32 h = getHeight(); +        LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, +            mFormatPrimary, mFormatType, (GLvoid*)data_in, mAllowCompression); +    } +    else if (mUseMipMaps)  	{  		if (data_hasmips)  		{ @@ -1069,14 +1076,15 @@ void LLImageGL::postAddToAtlas()  	stop_glerror();	  } -BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) +BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;  	if (!width || !height)  	{  		return TRUE;  	} -	if (mTexName == 0) +    LLGLuint tex_name = use_name != 0 ? use_name : mTexName; +	if (0 == tex_name)  	{  		// *TODO: Re-enable warning?  Ran into thread locking issues? DK 2011-02-18  		//LL_WARNS() << "Setting subimage on image without GL texture" << LL_ENDL; @@ -1092,7 +1100,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3  	// HACK: allow the caller to explicitly force the fast path (i.e. using glTexSubImage2D here instead of calling setImage) even when updating the full texture.  	if (!force_fast_update && x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height)  	{ -		setImage(datap, FALSE); +		setImage(datap, FALSE, tex_name);  	}  	else  	{ @@ -1144,12 +1152,11 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3  		datap += (y_pos * data_width + x_pos) * getComponents();  		// Update the GL texture -		BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName); +		BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, tex_name);  		if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL;  		stop_glerror(); -		glTexSubImage2D(mTarget, 0, x_pos, y_pos,  -						width, height, mFormatPrimary, mFormatType, datap); +		glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap);  		gGL.getTexUnit(0)->disable();  		stop_glerror(); @@ -1166,10 +1173,10 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3  	return TRUE;  } -BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) +BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; -	return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update); +	return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update, use_name);  }  // Copy sub image from frame buffer @@ -1356,7 +1363,7 @@ BOOL LLImageGL::createGLTexture()  	return TRUE ;  } -BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category) +BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category, bool defer_copy, LLGLuint* tex_name)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;      checkActiveThread(); @@ -1386,6 +1393,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S  	// Actual image width/height = raw image width/height * 2^discard_level  	S32 raw_w = imageraw->getWidth() ;  	S32 raw_h = imageraw->getHeight() ; +  	S32 w = raw_w << discard_level;  	S32 h = raw_h << discard_level; @@ -1468,15 +1476,26 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S  	setCategory(category);   	const U8* rawdata = imageraw->getData(); -	return createGLTexture(discard_level, rawdata, FALSE, usename); +	return createGLTexture(discard_level, rawdata, FALSE, usename, defer_copy, tex_name);  } -BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) +BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename, bool defer_copy, LLGLuint* tex_name) +// Call with void data, vmem is allocated but unitialized  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;      checkActiveThread(); -    llassert(data_in); +    bool main_thread = on_main_thread(); + +    if (defer_copy) +    { +        data_in = nullptr; +    } +    else +    { +        llassert(data_in); +    } +      stop_glerror();      if (discard_level < 0) @@ -1486,28 +1505,41 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_      }      discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); -    if (mTexName != 0 && discard_level == mCurrentDiscardLevel) +    if (main_thread // <--- always force creation of new_texname when not on main thread ... +        && !defer_copy // <--- ... or defer copy is set +        && mTexName != 0 && discard_level == mCurrentDiscardLevel)      { +        LL_PROFILE_ZONE_NAMED("cglt - early setImage");          // This will only be true if the size has not changed +        if (tex_name != nullptr) +        { +            *tex_name = mTexName; +        }          return setImage(data_in, data_hasmips);      }      GLuint old_texname = mTexName; -     +    GLuint new_texname = 0;      if (usename != 0)      { -        mNewTexName = usename; +        llassert(main_thread); +        new_texname = usename;      }      else      { -        LLImageGL::generateTextures(1, &mNewTexName); +        LLImageGL::generateTextures(1, &new_texname);          { -            gGL.getTexUnit(0)->bind(this, false, false, mNewTexName); +            gGL.getTexUnit(0)->bind(this, false, false, new_texname);              glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);              glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel - discard_level);          }      } -     + +    if (tex_name != nullptr) +    { +        *tex_name = new_texname; +    } +      if (mUseMipMaps)      {          mAutoGenMips = gGLManager.mHasMipMapGeneration; @@ -1515,9 +1547,12 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_      mCurrentDiscardLevel = discard_level; -    if (!setImage(data_in, data_hasmips, mNewTexName))      { -        return FALSE; +        LL_PROFILE_ZONE_NAMED("cglt - late setImage"); +        if (!setImage(data_in, data_hasmips, new_texname)) +        { +            return FALSE; +        }      }      // Set texture options to our defaults. @@ -1534,47 +1569,23 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_      }      //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread -    if (! on_main_thread()) +    if (!defer_copy)      { +        if (!main_thread)          { -            LL_PROFILE_ZONE_NAMED("cglt - sync"); -            if (gGLManager.mHasSync) -            { -                auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -                glClientWaitSync(sync, 0, 0); -                glDeleteSync(sync); -            } -            else -            { -                glFinish(); -            } +            syncToMainThread(new_texname);          } - -        ref(); -        LL::WorkQueue::postMaybe( -            mMainQueue, -            [=]() -            { -                LL_PROFILE_ZONE_NAMED("cglt - delete callback"); -                if (old_texname != 0) -                { -                    LLImageGL::deleteTextures(1, &old_texname); -                } -                mTexName = mNewTexName; -                mNewTexName = 0; -                unref(); -            }); -    } -    else  -    { -        //not on background thread, immediately set mTexName -        if (old_texname != 0) +        else          { -            LLImageGL::deleteTextures(1, &old_texname); +            //not on background thread, immediately set mTexName +            if (old_texname != 0 && old_texname != new_texname) +            { +                LLImageGL::deleteTextures(1, &old_texname); +            } +            mTexName = new_texname;          } -        mTexName = mNewTexName; -        mNewTexName = 0;      } +      mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel);      sGlobalTextureMemory += mTextureMemory; @@ -1587,6 +1598,110 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_      return TRUE;  } +void LLImageGLThread::updateClass() +{ +    LL_PROFILE_ZONE_SCOPED; + +    // update available vram one per second +    static LLFrameTimer sTimer; + +    if (sTimer.getElapsedSeconds() < 1.f) +    { +        return; +    } +     +    sTimer.reset(); + +    auto func = []() +    { +        if (gGLManager.mHasATIMemInfo) +        { +            S32 meminfo[4]; +            glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); +            LLImageGLThread::sFreeVRAMMegabytes = meminfo[0]; + +        } +        else if (gGLManager.mHasNVXMemInfo) +        { +            S32 free_memory; +            glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory); +            LLImageGLThread::sFreeVRAMMegabytes = free_memory / 1024; +        } +    }; + +     +    // post update to background thread if available, otherwise execute immediately +    auto queue = LL::WorkQueue::getInstance("LLImageGL"); +    if (sEnabled) +    { +        queue->post(func); +    } +    else +    { +        llassert(queue == nullptr); +        func(); +    } +} + +void LLImageGL::syncToMainThread(LLGLuint new_tex_name) +{ +    LL_PROFILE_ZONE_SCOPED; +    llassert(!on_main_thread()); + +    { +        LL_PROFILE_ZONE_NAMED("cglt - sync"); +        if (gGLManager.mHasSync) +        { +            // post a sync to the main thread (will execute before tex name swap lambda below) +            // glFlush calls here are partly superstitious and partly backed by observation +            // on AMD hardware +            glFlush(); +            auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +            glFlush(); +            LL::WorkQueue::postMaybe( +                mMainQueue, +                [=]() +                { +                    LL_PROFILE_ZONE_NAMED("cglt - wait sync"); +                    { +                        LL_PROFILE_ZONE_NAMED("glWaitSync"); +                        glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); +                    } +                    { +                        LL_PROFILE_ZONE_NAMED("glDeleteSync"); +                        glDeleteSync(sync); +                    } +                }); +        } +        else +        { +            glFinish(); +        } +    } + +    ref(); +    LL::WorkQueue::postMaybe( +        mMainQueue, +        [=]() +        { +            LL_PROFILE_ZONE_NAMED("cglt - delete callback"); +            syncTexName(new_tex_name); +            unref(); +        }); +} + +void LLImageGL::syncTexName(LLGLuint texname) +{ +    if (texname != 0) +    { +        if (mTexName != 0 && mTexName != texname) +        { +            LLImageGL::deleteTextures(1, &mTexName); +        } +        mTexName = texname; +    } +} +  BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const  {  	llassert_always(sAllowReadBackRaw) ; @@ -1714,7 +1829,7 @@ void LLImageGL::destroyGLTexture()  		mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.  		mTexName = 0;		  		mGLTextureCreated = FALSE ; -	}	 +	}  }  //force to invalidate the gl texture, most likely a sculpty texture @@ -2257,6 +2372,8 @@ void LLImageGL::checkActiveThread()  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL,  nummips);  */   +std::atomic<S32> LLImageGLThread::sFreeVRAMMegabytes(4096); //if free vram is unknown, default to 4GB +  LLImageGLThread::LLImageGLThread(LLWindow* window)      // We want exactly one thread, but a very large capacity: we never want      // anyone, especially inner-loop render code, to have to block on post() @@ -2283,3 +2400,9 @@ void LLImageGLThread::run()      gGL.shutdown();      mWindow->destroySharedContext(mContext);  } + +S32 LLImageGLThread::getFreeVRAMMegabytes() +{ +    return sFreeVRAMMegabytes; +} + diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index d6f4b13a51..4d5b60d6bc 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -110,14 +110,18 @@ public:  	BOOL createGLTexture() ;  	BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, -		S32 category = sMaxCategories-1); -	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); +		S32 category = sMaxCategories-1, bool defer_copy = false, LLGLuint* tex_name = nullptr); +	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0, bool defer_copy = false, LLGLuint* tex_name = nullptr);  	void setImage(const LLImageRaw* imageraw);  	BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE, S32 usename = 0); -	BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); -	BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); +	BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0); +	BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0);  	BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); -	 + +    // wait for gl commands to finish on current thread and push +    // a lambda to main thread to swap mNewTexName and mTexName +    void syncToMainThread(LLGLuint new_tex_name); +  	// Read back a raw image for this discard level, if it exists  	BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;  	void destroyGLTexture(); @@ -220,7 +224,7 @@ private:  	bool     mGLTextureCreated ;  	LLGLuint mTexName; -    LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread +    //LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread  	U16      mWidth;  	U16      mHeight;  	S8       mCurrentDiscardLevel; @@ -300,6 +304,9 @@ public:      void setTexName(GLuint texName) { mTexName = texName; } +    //similar to setTexName, but will call deleteTextures on mTexName if mTexName is not 0 or texname +    void syncTexName(LLGLuint texname); +  	//for debug use: show texture size distribution   	//----------------------------------------  	static S32 sCurTexSizeBar ; @@ -319,6 +326,12 @@ class LLImageGLThread : public LLSimpleton<LLImageGLThread>, LL::ThreadPool  public:      // follows gSavedSettings "RenderGLMultiThreaded"      static bool sEnabled; +     +    // app should call this function periodically +    static void updateClass(); + +    // free video memory in megabytes +    static std::atomic<S32> sFreeVRAMMegabytes;      LLImageGLThread(LLWindow* window); @@ -331,6 +344,8 @@ public:      void run() override; +    static S32 getFreeVRAMMegabytes(); +  private:      LLWindow* mWindow;      void* mContext = nullptr; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 92d8e6193f..a03a27cf94 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -36,6 +36,17 @@  #include "lltexture.h"  #include "llshadermgr.h" +#if LL_WINDOWS +extern void APIENTRY gl_debug_callback(GLenum source, +                                GLenum type, +                                GLuint id, +                                GLenum severity, +                                GLsizei length, +                                const GLchar* message, +                                GLvoid* userParam) +; +#endif +  thread_local LLRender gGL;  // Handy copies of last good GL matrices @@ -860,6 +871,15 @@ LLRender::~LLRender()  void LLRender::init()  { +#if LL_WINDOWS +    if (gGLManager.mHasDebugOutput && gDebugGL) +    { //setup debug output callback +        //glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE); +        glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL); +        glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); +    } +#endif +      glPixelStorei(GL_PACK_ALIGNMENT, 1);      glPixelStorei(GL_UNPACK_ALIGNMENT, 1); diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 5768686659..9ca05a16f3 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -78,7 +78,6 @@ LLComboBox::Params::Params()  	combo_button("combo_button"),  	combo_list("combo_list"),  	combo_editor("combo_editor"), -    mouse_down_callback("mouse_down_callback"),  	drop_down_button("drop_down_button")  {  	addSynonym(items, "combo_item"); @@ -98,8 +97,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)  	mTextChangedCallback(p.text_changed_callback()),  	mListPosition(p.list_position),  	mLastSelectedIndex(-1), -	mLabel(p.label), -    mMouseDownSignal(NULL) +	mLabel(p.label)  {  	// Text label button @@ -115,6 +113,10 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)  	}  	mArrowImage = button_params.image_unselected; +    if (mArrowImage.notNull()) +    { +        mImageLoadedConnection = mArrowImage->addLoadedCallback(boost::bind(&LLComboBox::imageLoaded, this)); +    }  	mButton = LLUICtrlFactory::create<LLButton>(button_params); @@ -155,11 +157,6 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)  	createLineEditor(p); -    if (p.mouse_down_callback.isProvided()) -    { -        setMouseDownCallback(initCommitCallback(p.mouse_down_callback)); -    } -  	mTopLostSignalConnection = setTopLostCallback(boost::bind(&LLComboBox::hideList, this));  } @@ -190,7 +187,7 @@ LLComboBox::~LLComboBox()  	// explicitly disconect this signal, since base class destructor might fire top lost  	mTopLostSignalConnection.disconnect(); -    delete mMouseDownSignal; +    mImageLoadedConnection.disconnect();  } @@ -717,9 +714,6 @@ void LLComboBox::hideList()  void LLComboBox::onButtonMouseDown()  { -    if (mMouseDownSignal) -        (*mMouseDownSignal)( this, 0 ); -  	if (!mList->getVisible())  	{  		// this might change selection, so do it first @@ -1085,6 +1079,30 @@ void LLComboBox::onSetHighlight() const      }  } +void LLComboBox::imageLoaded() +{ +    static LLUICachedControl<S32> drop_shadow_button("DropShadowButton", 0); + +    if (mAllowTextEntry) +    { +        LLRect rect = getLocalRect(); +        S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; +        S32 shadow_size = drop_shadow_button; +        mButton->setRect(LLRect(getRect().getWidth() - llmax(8, arrow_width) - 2 * shadow_size, +            rect.mTop, rect.mRight, rect.mBottom)); +        if (mButton->getVisible()) +        { +            // recalculate field size +            if (mTextEntry) +            { +                LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); +                text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * drop_shadow_button; +                mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); +            } +        } +    } +} +  //============================================================================  // LLCtrlListInterface functions @@ -1194,11 +1212,6 @@ BOOL LLComboBox::selectItemRange( S32 first, S32 last )  	return mList->selectItemRange(first, last);  } -boost::signals2::connection LLComboBox::setMouseDownCallback( const commit_signal_t::slot_type& cb )  -{  -    if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t(); -    return mMouseDownSignal->connect(cb);  -}  static LLDefaultChildRegistry::Register<LLIconsComboBox> register_icons_combo_box("icons_combo_box"); diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 49a55c98a3..cac8850a25 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -78,8 +78,6 @@ public:  											text_entry_callback,  											text_changed_callback; -        Optional<CommitCallbackParam>       mouse_down_callback; -  		Optional<EPreferredPosition, PreferredPositionValues>	list_position;  		// components @@ -107,6 +105,8 @@ protected:      virtual std::string _getSearchText() const;      virtual void onSetHighlight() const; +    void imageLoaded(); +  public:  	// LLView interface  	virtual void	onFocusLost(); @@ -209,8 +209,6 @@ public:  	void			setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; }  	void			setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; } -    boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); -  	/**  	* Connects callback to signal called when Return key is pressed.  	*/ @@ -248,7 +246,7 @@ private:  	commit_callback_t	mTextChangedCallback;  	commit_callback_t	mSelectionCallback;  	boost::signals2::connection mTopLostSignalConnection; -    commit_signal_t*	mMouseDownSignal; +    boost::signals2::connection mImageLoadedConnection;  	commit_signal_t		mOnReturnSignal;  	S32                 mLastSelectedIndex;  }; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 09e2896392..f26e3a84d2 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -3566,6 +3566,7 @@ void LLWindowWin32::swapBuffers()  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;      ASSERT_MAIN_THREAD(); +    glFlush(); //superstitious flush for maybe frame stall removal?  	SwapBuffers(mhDC);      LL_PROFILER_GPU_COLLECT diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 73b234eb75..e7f0af84ef 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1697,6 +1697,8 @@ set(viewer_APPSETTINGS_FILES      ${CMAKE_SOURCE_DIR}/../etc/message.xml      ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg      packages-info.txt +    featuretable.txt +    featuretable_mac.txt      )  source_group("App Settings" FILES ${viewer_APPSETTINGS_FILES}) @@ -1751,10 +1753,6 @@ endif (HAVOK OR HAVOK_TPV)  # progress view disables/enables icons based on available packages  set_source_files_properties(llprogressview.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") -if (GLODLIB) -  set_source_files_properties(llfloatermodelpreview.cpp PROPERTIES COMPILE_FLAGS "-DLL_GLOD") -endif (GLODLIB) -  list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES})  set_source_files_properties(${viewer_HEADER_FILES} diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index bb83824628..bfc47d2c65 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9886,7 +9886,7 @@      <key>Value</key>      <real>2.2</real>    </map> -    <key>RenderGLCoreProfile</key> +    <key>RenderGLContextCoreProfile</key>      <map>        <key>Comment</key>        <string>Don't use a compatibility profile OpenGL context.  Requires restart.  Basic shaders MUST be enabled.</string> diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index a5e0e395de..ff7ac84803 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -70,7 +70,7 @@ RenderShadowDetail			1	2  RenderUseStreamVBO			1	1  RenderFSAASamples			1	16  RenderMaxTextureIndex		1	16 -RenderGLCoreProfile         1   1 +RenderGLContextCoreProfile         1   1  RenderGLMultiThreaded       1   1 @@ -320,12 +320,12 @@ list Intel  RenderAnisotropic			1	0  RenderFSAASamples			1	0  RenderGLMultiThreaded       1   0 -RenderGLCoreProfile         1   0 +RenderGLContextCoreProfile         1   0  // AMD cards generally perform better when not using VBOs for streaming data  // AMD cards also prefer an OpenGL Compatibility Profile Context  list AMD  RenderUseStreamVBO			1	0 -RenderGLCoreProfile         1   0 +RenderGLContextCoreProfile         1   0 diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index 5140614bab..248eb68ee9 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -70,7 +70,7 @@ RenderShadowDetail			1	2  RenderUseStreamVBO			1	1  RenderFSAASamples			1	16  RenderMaxTextureIndex		1	16 -RenderGLCoreProfile         1   0 +RenderGLContextCoreProfile         1   0  RenderGLMultiThreaded       1   0  // diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index ed6c3c307f..84a41113be 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -210,9 +210,6 @@ void LLAgentCamera::init()  	mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPresetType"); -	mCameraOffsetInitial = gSavedSettings.getControl("CameraOffsetRearView"); -	mFocusOffsetInitial = gSavedSettings.getControl("FocusOffsetRearView"); -  	mCameraCollidePlane.clearVec();  	mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale");  	mTargetCameraDistance = mCurrentCameraDistance; @@ -1672,8 +1669,8 @@ LLVector3d LLAgentCamera::calcThirdPersonFocusOffset()  		agent_rot *= ((LLViewerObject*)(gAgentAvatarp->getParent()))->getRenderRotation();  	} -	focus_offset = convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, ""); -	return focus_offset * agent_rot; +    static LLCachedControl<LLVector3d> focus_offset_initial(gSavedSettings, "FocusOffsetRearView", LLVector3d()); +	return focus_offset_initial * agent_rot;  }  void LLAgentCamera::setupSitCamera() @@ -1810,8 +1807,9 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)  		}  		else  		{ -			local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * gSavedSettings.getF32("CameraOffsetScale"); -			 +            static LLCachedControl<F32> camera_offset_scale(gSavedSettings, "CameraOffsetScale"); +            local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * camera_offset_scale; +  			// are we sitting down?  			if (isAgentAvatarValid() && gAgentAvatarp->getParent())  			{ @@ -2028,12 +2026,15 @@ bool LLAgentCamera::isJoystickCameraUsed()  LLVector3 LLAgentCamera::getCameraOffsetInitial()  { -	return convert_from_llsd<LLVector3>(mCameraOffsetInitial->get(), TYPE_VEC3, ""); +    // getCameraOffsetInitial and getFocusOffsetInitial can be called on update from idle before init() +    static LLCachedControl<LLVector3> camera_offset_initial (gSavedSettings, "CameraOffsetRearView", LLVector3()); +	return camera_offset_initial;  }  LLVector3d LLAgentCamera::getFocusOffsetInitial()  { -	return convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, ""); +    static LLCachedControl<LLVector3d> focus_offset_initial(gSavedSettings, "FocusOffsetRearView", LLVector3d()); +	return focus_offset_initial;  }  F32 LLAgentCamera::getCameraMaxZoomDistance() diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index ec1ed433d7..89680f95dc 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -131,12 +131,6 @@ private:  	/** Camera preset in Third Person Mode */  	ECameraPreset mCameraPreset;  -	/** Initial camera offset */ -	LLPointer<LLControlVariable> mCameraOffsetInitial; - -	/** Initial focus offset */ -	LLPointer<LLControlVariable> mFocusOffsetInitial; -  	LLQuaternion mInitSitRot;  	//-------------------------------------------------------------------- diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 73d0eac0ac..66c44ef6a6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -532,7 +532,7 @@ static void settings_to_globals()  	LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize")); -	LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLCoreProfile"); +	LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLContextCoreProfile");  	LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport");  	LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");  	LLImageGL::sGlobalUseAnisotropic	= gSavedSettings.getBOOL("RenderAnisotropic"); diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index d4f30fc51a..fd1b022e5b 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -183,6 +183,7 @@ public:  		PASS_GLOW,          PASS_GLOW_RIGGED,  		PASS_ALPHA, +        PASS_ALPHA_RIGGED,  		PASS_ALPHA_MASK,          PASS_ALPHA_MASK_RIGGED,  		PASS_FULLBRIGHT_ALPHA_MASK,            // Diffuse texture used as alpha mask and fullbright diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 9da20cc375..2bf8e9b911 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -129,23 +129,26 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)      LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;      deferred_render = TRUE; -    // first pass, regular forward alpha rendering -    { -        emissive_shader = (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram; -        prepare_alpha_shader(emissive_shader, true, false); - -        fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram : -            (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram; -        prepare_alpha_shader(fullbright_shader, true, false); - -        simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram : -            (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram; -        prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms) -         -        forwardRender(); -    } +    // prepare shaders +    emissive_shader = (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram; +    prepare_alpha_shader(emissive_shader, true, false); + +    fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram : +        (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram; +    prepare_alpha_shader(fullbright_shader, true, false); + +    simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram : +        (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram; +    prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms) + -    // second pass, render to depth for depth of field effects +    // first pass, render rigged objects only and render to depth buffer +    forwardRender(true); + +    // second pass, regular forward alpha rendering +    forwardRender(); + +    // final pass, render to depth for depth of field effects      if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField"))      {           //update depth buffer sampler @@ -209,10 +212,14 @@ void LLDrawPoolAlpha::render(S32 pass)      prepare_forward_shader(fullbright_shader, minimum_alpha);      prepare_forward_shader(simple_shader, minimum_alpha); +    //first pass -- rigged only and drawn to depth buffer +    forwardRender(true); + +    //second pass -- non-rigged, no depth buffer writes      forwardRender();  } -void LLDrawPoolAlpha::forwardRender() +void LLDrawPoolAlpha::forwardRender(bool rigged)  {      gPipeline.enableLightsDynamic(); @@ -221,7 +228,8 @@ void LLDrawPoolAlpha::forwardRender()      //enable writing to alpha for emissive effects      gGL.setColorMask(true, true); -    bool write_depth = LLDrawPoolWater::sSkipScreenCopy +    bool write_depth = rigged +        || LLDrawPoolWater::sSkipScreenCopy          // we want depth written so that rendered alpha will          // contribute to the alpha mask used for impostors          || LLPipeline::sImpostorRenderAlphaDepthPass; @@ -236,11 +244,17 @@ void LLDrawPoolAlpha::forwardRender()      // If the face is more than 90% transparent, then don't update the Depth buffer for Dof      // We don't want the nearly invisible objects to cause of DoF effects -    renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2); +    renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged);      gGL.setColorMask(true, false); -    renderDebugAlpha(); +    if (!rigged) +    { //render "highlight alpha" on final non-rigged pass +        // NOTE -- hacky call here protected by !rigged instead of alongside "forwardRender" +        // so renderDebugAlpha is executed while gls_pipeline_alpha and depth GL state +        // variables above are still in scope +        renderDebugAlpha(); +    }  }  void LLDrawPoolAlpha::renderDebugAlpha() @@ -291,54 +305,60 @@ void LLDrawPoolAlpha::renderDebugAlpha()  void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)  { -    LLVOAvatar* lastAvatar = nullptr; -    U64 lastMeshId = 0; +    for (int pass = 0; pass < 2; ++pass) +    { //two passes, one rigged and one not +        LLVOAvatar* lastAvatar = nullptr; +        U64 lastMeshId = 0; -	for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) -	{ -		LLSpatialGroup* group = *i; -		if (group->getSpatialPartition()->mRenderByGroup && -			!group->isDead()) -		{ -			LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];	 +        LLCullResult::sg_iterator begin = pass == 0 ? gPipeline.beginAlphaGroups() : gPipeline.beginRiggedAlphaGroups(); +        LLCullResult::sg_iterator end = pass == 0 ? gPipeline.endAlphaGroups() : gPipeline.endRiggedAlphaGroups(); -			for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	 -			{ -				LLDrawInfo& params = **k; -				 -				if (params.mParticle) -				{ -					continue; -				} - -                bool rigged = (params.mAvatar != nullptr); -                gHighlightProgram.bind(rigged); -                gGL.diffuseColor4f(1, 0, 0, 1); +        for (LLCullResult::sg_iterator i = begin; i != end; ++i) +        { +            LLSpatialGroup* group = *i; +            if (group->getSpatialPartition()->mRenderByGroup && +                !group->isDead()) +            { +                LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA+pass]; // <-- hacky + pass to use PASS_ALPHA_RIGGED on second pass  -                if (rigged) +                for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)                  { -                    if (lastAvatar != params.mAvatar || -                        lastMeshId != params.mSkinInfo->mHash) +                    LLDrawInfo& params = **k; + +                    if (params.mParticle)                      { -                        if (!uploadMatrixPalette(params)) +                        continue; +                    } + +                    bool rigged = (params.mAvatar != nullptr); +                    gHighlightProgram.bind(rigged); +                    gGL.diffuseColor4f(1, 0, 0, 1); + +                    if (rigged) +                    { +                        if (lastAvatar != params.mAvatar || +                            lastMeshId != params.mSkinInfo->mHash)                          { -                            continue; +                            if (!uploadMatrixPalette(params)) +                            { +                                continue; +                            } +                            lastAvatar = params.mAvatar; +                            lastMeshId = params.mSkinInfo->mHash;                          } -                        lastAvatar = params.mAvatar; -                        lastMeshId = params.mSkinInfo->mHash;                      } -                } -				LLRenderPass::applyModelMatrix(params); -				if (params.mGroup) -				{ -					params.mGroup->rebuildMesh(); -				} -				params.mVertexBuffer->setBufferFast(rigged ?  mask | LLVertexBuffer::MAP_WEIGHT4 : mask); -				params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); -			} -		} -	} +                    LLRenderPass::applyModelMatrix(params); +                    if (params.mGroup) +                    { +                        params.mGroup->rebuildMesh(); +                    } +                    params.mVertexBuffer->setBufferFast(rigged ? mask | LLVertexBuffer::MAP_WEIGHT4 : mask); +                    params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); +                } +            } +        } +    }      // make sure static version of highlight shader is bound before returning      gHighlightProgram.bind(); @@ -471,6 +491,8 @@ void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>&      LLVOAvatar* lastAvatar = nullptr;      U64 lastMeshId = 0; +    mask |= LLVertexBuffer::MAP_WEIGHT4; +      for (LLDrawInfo* draw : emissives)      {          bool tex_setup = TexSetup(draw, false); @@ -488,7 +510,7 @@ void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>&      }  } -void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only) +void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;      BOOL initialized_lighting = FALSE; @@ -498,7 +520,21 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)      U64 lastMeshId = 0;      LLGLSLShader* lastAvatarShader = nullptr; -    for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) +    LLCullResult::sg_iterator begin; +    LLCullResult::sg_iterator end; + +    if (rigged) +    { +        begin = gPipeline.beginRiggedAlphaGroups(); +        end = gPipeline.endRiggedAlphaGroups(); +    } +    else +    { +        begin = gPipeline.beginAlphaGroups(); +        end = gPipeline.endAlphaGroups(); +    } + +    for (LLCullResult::sg_iterator i = begin; i != end; ++i)  	{          LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group");  		LLSpatialGroup* group = *i; @@ -521,12 +557,18 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)  			bool disable_cull = is_particle_or_hud_particle;  			LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0); -			LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; +			LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA];  			for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	  			{ -                LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch")  				LLDrawInfo& params = **k; +                if ((bool)params.mAvatar != rigged) +                { +                    continue; +                } + +                LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch") +                  U32 have_mask = params.mVertexBuffer->getTypeMask() & mask;  				if (have_mask != mask)  				{ //FIXME! @@ -753,7 +795,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)  bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params)  { -    const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar->updateSkinInfoMatrixPalette(params.mSkinInfo); +    const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar.get()->updateSkinInfoMatrixPalette(params.mSkinInfo);      U32 count = mpc.mMatrixPalette.size();      if (count == 0) diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h index 1f6909e282..fa8ef0f227 100644 --- a/indra/newview/lldrawpoolalpha.h +++ b/indra/newview/lldrawpoolalpha.h @@ -55,13 +55,13 @@ public:  	/*virtual*/ S32	 getNumPasses() { return 1; }  	virtual void render(S32 pass = 0); -    void forwardRender(); +    void forwardRender(bool write_depth = false);  	/*virtual*/ void prerender();      void renderDebugAlpha();  	void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE); -	void renderAlpha(U32 mask, bool depth_only = false); +	void renderAlpha(U32 mask, bool depth_only = false, bool rigged = false);  	void renderAlphaHighlight(U32 mask);      bool uploadMatrixPalette(const LLDrawInfo& params); diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 471b0e2c48..1d5419b515 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -54,6 +54,8 @@  // static  LLStandardBumpmap gStandardBumpmapList[TEM_BUMPMAP_COUNT];  +LL::WorkQueue::weak_t LLBumpImageList::sMainQueue; +LL::WorkQueue::weak_t LLBumpImageList::sTexUpdateQueue;  // static  U32 LLStandardBumpmap::sStandardBumpmapCount = 0; @@ -74,6 +76,8 @@ static S32 cube_channel = -1;  static S32 diffuse_channel = -1;  static S32 bump_channel = -1; +#define LL_BUMPLIST_MULTITHREADED 0 +  // static   void LLStandardBumpmap::init()  { @@ -761,6 +765,8 @@ void LLBumpImageList::init()  	LLStandardBumpmap::init();  	LLStandardBumpmap::restoreGL(); +    sMainQueue = LL::WorkQueue::getInstance("mainloop"); +    sTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader.  }  void LLBumpImageList::clear() @@ -909,10 +915,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText  	}  	else  	{ -		LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1); -		raw->clear(0x77, 0x77, 0xFF, 0xFF); - -		(*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE); +		(*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( TRUE );  		bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image  	} @@ -1043,16 +1046,13 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI  							iter->second->getWidth() != src->getWidth() ||  							iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution  			{ //make sure an entry exists for this image -				LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1); -				raw->clear(0x77, 0x77, 0xFF, 0xFF); - -				entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE); +				entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(TRUE);  				iter = entries_list.find(src_vi->getID());  			}  		} -		//if (iter->second->getWidth() != src->getWidth() || -		//	iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution +		if (iter->second->getWidth() != src->getWidth() || +			iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution  		{  			LLPointer<LLImageRaw> dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1);  			U8* dst_data = dst_image->getData(); @@ -1166,108 +1166,178 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI  			}  			//--------------------------------------------------- -			// immediately assign bump to a global smart pointer in case some local smart pointer +			// immediately assign bump to a smart pointer in case some local smart pointer  			// accidentally releases it. -			LLPointer<LLViewerTexture> bump = LLViewerTextureManager::getLocalTexture( TRUE ); +            LLPointer<LLViewerTexture> bump = iter->second;  			if (!LLPipeline::sRenderDeferred)  			{  				bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA); -				bump->createGLTexture(0, dst_image); + +#if LL_BUMPLIST_MULTITHREADED +                auto tex_queue = LLImageGLThread::sEnabled ? sTexUpdateQueue.lock() : nullptr; + +                if (tex_queue) +                { //dispatch creation to background thread +                    LLImageRaw* dst_ptr = dst_image; +                    LLViewerTexture* bump_ptr = bump; +                    dst_ptr->ref(); +                    bump_ptr->ref(); +                    tex_queue->post( +                        [=]() +                        { +                            LL_PROFILE_ZONE_NAMED("bil - create texture"); +                            bump_ptr->createGLTexture(0, dst_ptr); +                            bump_ptr->unref(); +                            dst_ptr->unref(); +                        }); + +                } +                else +#endif +                { +                    bump->createGLTexture(0, dst_image); +                }  			}  			else   			{ //convert to normal map  				//disable compression on normal maps to prevent errors below  				bump->getGLTexture()->setAllowCompression(false); +                bump->getGLTexture()->setUseMipMaps(TRUE); -				{ -					bump->setExplicitFormat(GL_RGBA8, GL_ALPHA); -					bump->createGLTexture(0, dst_image); -				} +                auto* bump_ptr = bump.get(); +                auto* dst_ptr = dst_image.get(); -				{ -					gPipeline.mScreen.bindTarget(); -					 -					LLGLDepthTest depth(GL_FALSE); -					LLGLDisable cull(GL_CULL_FACE); -					LLGLDisable blend(GL_BLEND); -					gGL.setColorMask(TRUE, TRUE); -					gNormalMapGenProgram.bind(); +#if LL_BUMPLIST_MULTITHREADED +                bump_ptr->ref(); +                dst_ptr->ref(); +#endif -					static LLStaticHashedString sNormScale("norm_scale"); -					static LLStaticHashedString sStepX("stepX"); -					static LLStaticHashedString sStepY("stepY"); +                bump_ptr->setExplicitFormat(GL_RGBA8, GL_ALPHA); -					gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); -					gNormalMapGenProgram.uniform1f(sStepX, 1.f/bump->getWidth()); -					gNormalMapGenProgram.uniform1f(sStepY, 1.f/bump->getHeight()); +                auto create_texture = [=]() +                { +#if LL_IMAGEGL_THREAD_CHECK +                    bump_ptr->getGLTexture()->mActiveThread = LLThread::currentID(); +#endif +                    LL_PROFILE_ZONE_NAMED("bil - create texture deferred"); +                    bump_ptr->createGLTexture(0, dst_ptr); +                }; + +                auto gen_normal_map = [=]() +                { +#if LL_IMAGEGL_THREAD_CHECK +                    bump_ptr->getGLTexture()->mActiveThread = LLThread::currentID(); +#endif +                    LL_PROFILE_ZONE_NAMED("bil - generate normal map"); +                    if (gNormalMapGenProgram.mProgramObject == 0) +                    { +#if LL_BUMPLIST_MULTITHREADED +                        bump_ptr->unref(); +                        dst_ptr->unref(); +#endif +                        return; +                    } +                    gPipeline.mScreen.bindTarget(); -					LLVector2 v((F32) bump->getWidth()/gPipeline.mScreen.getWidth(), -								(F32) bump->getHeight()/gPipeline.mScreen.getHeight()); +                    LLGLDepthTest depth(GL_FALSE); +                    LLGLDisable cull(GL_CULL_FACE); +                    LLGLDisable blend(GL_BLEND); +                    gGL.setColorMask(TRUE, TRUE); +                    gNormalMapGenProgram.bind(); -					gGL.getTexUnit(0)->bind(bump); -					 -					S32 width = bump->getWidth(); -					S32 height = bump->getHeight(); +                    static LLStaticHashedString sNormScale("norm_scale"); +                    static LLStaticHashedString sStepX("stepX"); +                    static LLStaticHashedString sStepY("stepY"); -					S32 screen_width = gPipeline.mScreen.getWidth(); -					S32 screen_height = gPipeline.mScreen.getHeight(); +                    gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); +                    gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth()); +                    gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight()); -					glViewport(0, 0, screen_width, screen_height); +                    LLVector2 v((F32)bump_ptr->getWidth() / gPipeline.mScreen.getWidth(), +                        (F32)bump_ptr->getHeight() / gPipeline.mScreen.getHeight()); -					for (S32 left = 0; left < width; left += screen_width) -					{ -						S32 right = left + screen_width; -						right = llmin(right, width); -						 -						F32 left_tc = (F32) left/ width; -						F32 right_tc = (F32) right/width; +                    gGL.getTexUnit(0)->bind(bump_ptr); -						for (S32 bottom = 0; bottom < height; bottom += screen_height) -						{ -							S32 top = bottom+screen_height; -							top = llmin(top, height); +                    S32 width = bump_ptr->getWidth(); +                    S32 height = bump_ptr->getHeight(); -							F32 bottom_tc = (F32) bottom/height; -							F32 top_tc = (F32)(bottom+screen_height)/height; -							top_tc = llmin(top_tc, 1.f); +                    S32 screen_width = gPipeline.mScreen.getWidth(); +                    S32 screen_height = gPipeline.mScreen.getHeight(); -							F32 screen_right = (F32) (right-left)/screen_width; -							F32 screen_top = (F32) (top-bottom)/screen_height; +                    glViewport(0, 0, screen_width, screen_height); -							gGL.begin(LLRender::TRIANGLE_STRIP); -							gGL.texCoord2f(left_tc, bottom_tc); -							gGL.vertex2f(0, 0); +                    for (S32 left = 0; left < width; left += screen_width) +                    { +                        S32 right = left + screen_width; +                        right = llmin(right, width); -							gGL.texCoord2f(left_tc, top_tc); -							gGL.vertex2f(0, screen_top); +                        F32 left_tc = (F32)left / width; +                        F32 right_tc = (F32)right / width; -							gGL.texCoord2f(right_tc, bottom_tc); -							gGL.vertex2f(screen_right, 0); +                        for (S32 bottom = 0; bottom < height; bottom += screen_height) +                        { +                            S32 top = bottom + screen_height; +                            top = llmin(top, height); -							gGL.texCoord2f(right_tc, top_tc); -							gGL.vertex2f(screen_right, screen_top); +                            F32 bottom_tc = (F32)bottom / height; +                            F32 top_tc = (F32)(bottom + screen_height) / height; +                            top_tc = llmin(top_tc, 1.f); -							gGL.end(); +                            F32 screen_right = (F32)(right - left) / screen_width; +                            F32 screen_top = (F32)(top - bottom) / screen_height; -							gGL.flush(); +                            gGL.begin(LLRender::TRIANGLE_STRIP); +                            gGL.texCoord2f(left_tc, bottom_tc); +                            gGL.vertex2f(0, 0); -							S32 w = right-left; -							S32 h = top-bottom; +                            gGL.texCoord2f(left_tc, top_tc); +                            gGL.vertex2f(0, screen_top); -							glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h); -						} -					} +                            gGL.texCoord2f(right_tc, bottom_tc); +                            gGL.vertex2f(screen_right, 0); -					glGenerateMipmap(GL_TEXTURE_2D); +                            gGL.texCoord2f(right_tc, top_tc); +                            gGL.vertex2f(screen_right, screen_top); -					gPipeline.mScreen.flush(); +                            gGL.end(); -					gNormalMapGenProgram.unbind(); -										 -					//generateNormalMapFromAlpha(dst_image, nrm_image); -				} +                            gGL.flush(); + +                            S32 w = right - left; +                            S32 h = top - bottom; + +                            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h); +                        } +                    } + +                    glGenerateMipmap(GL_TEXTURE_2D); + +                    gPipeline.mScreen.flush(); + +                    gNormalMapGenProgram.unbind(); + +                    //generateNormalMapFromAlpha(dst_image, nrm_image); +#if LL_BUMPLIST_MULTITHREADED +                    bump_ptr->unref(); +                    dst_ptr->unref(); +#endif +                }; + +#if LL_BUMPLIST_MULTITHREADED +                auto main_queue = sMainQueue.lock(); + +                if (LLImageGLThread::sEnabled) +                { //dispatch creation to background thread +                    main_queue->postTo(sTexUpdateQueue, create_texture, gen_normal_map); +                } +                else +#endif +                { +                    create_texture(); +                    gen_normal_map(); +                }  			}  			iter->second = bump; // derefs (and deletes) old image diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index 38744a7d98..6e21859738 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -161,6 +161,8 @@ private:  	typedef std::unordered_map<LLUUID, LLPointer<LLViewerTexture> > bump_image_map_t;  	bump_image_map_t mBrightnessEntries;  	bump_image_map_t mDarknessEntries; +    static LL::WorkQueue::weak_t sMainQueue; +    static LL::WorkQueue::weak_t sTexUpdateQueue;  };  extern LLBumpImageList gBumpImageList; diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 0f2bcf4708..6762b38c39 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -520,9 +520,10 @@ void LLDrawPoolWater::renderWater()      LLColor4      specular(sun_up ? psky->getSunlightColor() : psky->getMoonlightColor());      F32           phase_time = (F32) LLFrameTimer::getElapsedSeconds() * 0.5f; -    bool          edge       = false;      LLGLSLShader *shader     = nullptr; -    do  // twice through, once with normal shader bound & once with edge shader bound + +    // two passes, first with standard water shader bound, second with edge water shader bound +    for( int edge = 0 ; edge < 2; edge++ )      {          // select shader          if (underwater && LLPipeline::sWaterReflections) @@ -675,7 +676,7 @@ void LLDrawPoolWater::renderWater()              gGL.getTexUnit(diffTex)->bind(face->getTexture()); -            if (edge == (bool) water->getIsEdgePatch()) +            if ((bool)edge == (bool) water->getIsEdgePatch())              {                  face->renderIndexed(); @@ -699,9 +700,7 @@ void LLDrawPoolWater::renderWater()          shader->unbind();          gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);          gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); - -        edge = !edge; -    } while (!edge); +    }      gGL.getTexUnit(0)->activate();      gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6135c4f13e..fe5120376c 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -351,15 +351,6 @@ void LLFloaterModelPreview::initModelPreview()  //static  bool LLFloaterModelPreview::showModelPreview()  { -#ifdef LL_GLOD -    if (LLRender::sGLCoreProfile) -    { -        // GLOD is incompatible with RenderGLCoreProfile, will crash on init -        LLNotificationsUtil::add("MeshUploadProfilerError"); -        return false; -    } -#endif -      LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)LLFloaterReg::getInstance("upload_model");      if (fmp && !fmp->isModelLoading())      { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 06c8f66c1e..a0de3a2af1 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -5777,12 +5777,13 @@ LLCallingCardBridge::LLCallingCardBridge(LLInventoryPanel* inventory,  	LLItemBridge(inventory, root, uuid)  {      mObserver = new LLCallingCardObserver(this); -    LLAvatarTracker::instance().addParticularFriendObserver(getItem()->getCreatorUUID(), mObserver); +    mCreatorUUID = getItem()->getCreatorUUID(); +    LLAvatarTracker::instance().addParticularFriendObserver(mCreatorUUID, mObserver);  }  LLCallingCardBridge::~LLCallingCardBridge()  { -    LLAvatarTracker::instance().removeParticularFriendObserver(getItem()->getCreatorUUID(), mObserver); +    LLAvatarTracker::instance().removeParticularFriendObserver(mCreatorUUID, mObserver);      delete mObserver;  } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index c21bfbd02d..0b0ef273e1 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -457,6 +457,7 @@ public:  	void checkSearchBySuffixChanges();  protected:  	LLCallingCardObserver* mObserver; +    LLUUID mCreatorUUID;  };  class LLNotecardBridge : public LLItemBridge diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index c9bf0b0a12..d3eb2dd4d4 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1235,6 +1235,11 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe          size_vertices += face.mNumVertices;      } +    if (size_indices < 3) +    { +        return -1; +    } +      // Allocate buffers, note that we are using U32 buffer instead of U16      U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));      U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); @@ -1279,10 +1284,10 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe      // Now that we have buffers, optimize      S32 target_indices = 0; -    F32 result_code = 0; // how far from original the model is, 1 == 100% +    F32 result_error = 0; // how far from original the model is, 1 == 100%      S32 new_indices = 0; -    target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle +    target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle      new_indices = LLMeshOptimizer::simplifyU32(          output_indices,          combined_indices, @@ -1293,17 +1298,27 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe          target_indices,          error_threshold,          sloppy, -        &result_code); +        &result_error); -    if (result_code < 0) +    if (result_error < 0)      { -        LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel +        LL_WARNS() << "Negative result error from meshoptimizer for model " << target_model->mLabel              << " target Indices: " << target_indices              << " new Indices: " << new_indices              << " original count: " << size_indices << LL_ENDL;      } +    if (new_indices < 3) +    { +        // Model should have at least one visible triangle +        ll_aligned_free<64>(combined_positions); +        ll_aligned_free_32(output_indices); +        ll_aligned_free_32(combined_indices); + +        return -1; +    } +      // repack back into individual faces      LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); @@ -1456,16 +1471,20 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target  {      const LLVolumeFace &face = base_model->getVolumeFace(face_idx);      S32 size_indices = face.mNumIndices; +    if (size_indices < 3) +    { +        return -1; +    }      // todo: do not allocate per each face, add one large buffer somewhere      // faces have limited amount of indices      S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF;      U16* output = (U16*)ll_aligned_malloc_16(size);      S32 target_indices = 0; -    F32 result_code = 0; // how far from original the model is, 1 == 100% +    F32 result_error = 0; // how far from original the model is, 1 == 100%      S32 new_indices = 0; -    target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle +    target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle      new_indices = LLMeshOptimizer::simplify(          output,          face.mIndices, @@ -1476,12 +1495,12 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target          target_indices,          error_threshold,          sloppy, -        &result_code); +        &result_error); -    if (result_code < 0) +    if (result_error < 0)      { -        LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx +        LL_WARNS() << "Negative result error from meshoptimizer for face " << face_idx              << " of model " << target_model->mLabel              << " target Indices: " << target_indices              << " new Indices: " << new_indices @@ -1693,21 +1712,21 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d                  // Run meshoptimizer for each face                  for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)                  { -                    genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true); +                    if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true) < 0) +                    { +                        // Sloppy failed and returned an invalid model +                        genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); +                    }                  } - -                LL_INFOS() << "Model " << target_model->getName() -                    << " lod " << which_lod -                    << " simplified using per face method." << LL_ENDL;              }              if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)              { -                // Switches between 'combine' method and 'per model sloppy' based on combine's result. +                // Switches between 'combine' method and 'sloppy' based on combine's result.                  F32 allowed_ratio_drift = 2.f; -                F32 res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); - -                if (res_ratio < 0) +                F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); +                 +                if (precise_ratio < 0)                  {                      // U16 vertices overflow, shouldn't happen, but just in case                      for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) @@ -1715,42 +1734,101 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d                          genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);                      }                  } -                else if (res_ratio * allowed_ratio_drift < indices_decimator) +                else if (precise_ratio * allowed_ratio_drift < indices_decimator)                  {                      // Try sloppy variant if normal one failed to simplify model enough. -                    res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); +                    // Sloppy variant can fail entirely and has issues with precision, +                    // so code needs to do multiple attempts with different decimators. +                    // Todo: this is a bit of a mess, needs to be refined and improved +                    F32 last_working_decimator = 0.f; +                    F32 last_working_ratio = F32_MAX; + +                    F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); + +                    if (sloppy_ratio > 0) +                    { +                        // Would be better to do a copy of target_model here, but if +                        // we need to use sloppy decimation, model should be cheap +                        // and fast to generate and it won't affect end result +                        last_working_decimator = indices_decimator; +                        last_working_ratio = sloppy_ratio; +                    }                      // Sloppy has a tendecy to error into lower side, so a request for 100                      // triangles turns into ~70, so check for significant difference from target decimation                      F32 sloppy_ratio_drift = 1.4f;                      if (lod_mode == LIMIT_TRIANGLES -                        && (res_ratio > indices_decimator * sloppy_ratio_drift || res_ratio < 0)) +                        && (sloppy_ratio > indices_decimator * sloppy_ratio_drift || sloppy_ratio < 0))                      {                          // Apply a correction to compensate.                          // (indices_decimator / res_ratio) by itself is likely to overshoot to a differend                          // side due to overal lack of precision, and we don't need an ideal result, which                          // likely does not exist, just a better one, so a partial correction is enough. -                        F32 sloppy_decimator = indices_decimator * (indices_decimator / res_ratio + 1) / 2; -                        res_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true); +                        F32 sloppy_decimator = indices_decimator * (indices_decimator / sloppy_ratio + 1) / 2; +                        sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true); +                    } + +                    if (last_working_decimator > 0 && sloppy_ratio < last_working_ratio) +                    { +                        // Compensation didn't work, return back to previous decimator +                        sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);                      } +                    if (sloppy_ratio < 0) +                    { +                        // Sloppy method didn't work, try with smaller decimation values +                        S32 size_vertices = 0; + +                        for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) +                        { +                            const LLVolumeFace &face = base->getVolumeFace(face_idx); +                            size_vertices += face.mNumVertices; +                        } + +                        // Complex models aren't supposed to get here, they are supposed +                        // to work on a first try of sloppy due to having more viggle room. +                        // If they didn't, something is likely wrong, no point locking the +                        // thread in a long calculation that will fail. +                        const U32 too_many_vertices = 27000; +                        if (size_vertices > too_many_vertices) +                        { +                            LL_WARNS() << "Sloppy optimization method failed for a complex model " << target_model->getName() << LL_ENDL; +                        } +                        else +                        { +                            // Find a decimator that does work +                            F32 sloppy_decimation_step = sqrt((F32)decimation); // example: 27->15->9->5->3 +                            F32 sloppy_decimator = indices_decimator / sloppy_decimation_step; + +                            while (sloppy_ratio < 0 +                                && sloppy_decimator > precise_ratio +                                && sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case +                            { +                                sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true); +                                sloppy_decimator = sloppy_decimator / sloppy_decimation_step; +                            } +                        } +                    } -                    if (res_ratio < 0) +                    if (sloppy_ratio < 0 || sloppy_ratio < precise_ratio)                      { -                        // Sloppy variant failed to generate triangles. +                        // Sloppy variant failed to generate triangles or is worse.                          // Can happen with models that are too simple as is. -                        // Fallback to normal method or use lower decimator. -                        genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); +                        // Fallback to normal method + +                        precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);                          LL_INFOS() << "Model " << target_model->getName()                              << " lod " << which_lod +                            << " resulting ratio " << precise_ratio                              << " simplified using per model method." << LL_ENDL;                      }                      else                      {                          LL_INFOS() << "Model " << target_model->getName()                              << " lod " << which_lod +                            << " resulting ratio " << sloppy_ratio                              << " sloppily simplified using per model method." << LL_ENDL;                      }                  } @@ -1758,6 +1836,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d                  {                      LL_INFOS() << "Model " << target_model->getName()                          << " lod " << which_lod +                        << " resulting ratio " << precise_ratio                          << " simplified using per model method." << LL_ENDL;                  }              } diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 937f36b6fc..1240ce7c0f 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -147,6 +147,10 @@ void LLNetMap::setScale( F32 scale )  void LLNetMap::draw()  { +    if (!LLWorld::instanceExists()) +    { +        return; +    }      LL_PROFILE_ZONE_SCOPED;   	static LLFrameTimer map_timer;  	static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index eaf6186dae..5c648c11e1 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -4022,6 +4022,7 @@ LLCullResult::LLCullResult()  {  	mVisibleGroupsAllocated = 0;  	mAlphaGroupsAllocated = 0; +    mRiggedAlphaGroupsAllocated = 0;  	mOcclusionGroupsAllocated = 0;  	mDrawableGroupsAllocated = 0;  	mVisibleListAllocated = 0; @@ -4033,6 +4034,9 @@ LLCullResult::LLCullResult()  	mAlphaGroups.clear();  	mAlphaGroups.push_back(NULL);  	mAlphaGroupsEnd = &mAlphaGroups[0]; +    mRiggedAlphaGroups.clear(); +    mRiggedAlphaGroups.push_back(NULL); +    mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[0];  	mOcclusionGroups.clear();  	mOcclusionGroups.push_back(NULL);  	mOcclusionGroupsEnd = &mOcclusionGroups[0]; @@ -4073,6 +4077,9 @@ void LLCullResult::clear()  	mAlphaGroupsSize = 0;  	mAlphaGroupsEnd = &mAlphaGroups[0]; +    mRiggedAlphaGroupsSize = 0; +    mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[0]; +  	mOcclusionGroupsSize = 0;  	mOcclusionGroupsEnd = &mOcclusionGroups[0]; @@ -4117,6 +4124,16 @@ LLCullResult::sg_iterator LLCullResult::endAlphaGroups()  	return mAlphaGroupsEnd;  } +LLCullResult::sg_iterator LLCullResult::beginRiggedAlphaGroups() +{ +    return &mRiggedAlphaGroups[0]; +} + +LLCullResult::sg_iterator LLCullResult::endRiggedAlphaGroups() +{ +    return mRiggedAlphaGroupsEnd; +} +  LLCullResult::sg_iterator LLCullResult::beginOcclusionGroups()  {  	return &mOcclusionGroups[0]; @@ -4195,6 +4212,20 @@ void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)  	mAlphaGroupsEnd = &mAlphaGroups[mAlphaGroupsSize];  } +void LLCullResult::pushRiggedAlphaGroup(LLSpatialGroup* group) +{ +    if (mRiggedAlphaGroupsSize < mRiggedAlphaGroupsAllocated) +    { +        mRiggedAlphaGroups[mRiggedAlphaGroupsSize] = group; +    } +    else +    { +        pushBack(mRiggedAlphaGroups, mRiggedAlphaGroupsAllocated, group); +    } +    ++mRiggedAlphaGroupsSize; +    mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[mRiggedAlphaGroupsSize]; +} +  void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)  {  	if (mOcclusionGroupsSize < mOcclusionGroupsAllocated) diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index afe24d7d1f..acfcd63686 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -40,6 +40,8 @@  #include "llface.h"  #include "llviewercamera.h"  #include "llvector4a.h" +#include "llvoavatar.h" +  #include <queue>  #include <unordered_map> @@ -125,7 +127,7 @@ public:  	F32  mAlphaMaskCutoff;  	U8   mDiffuseAlphaMode;  	bool mSelected; -    LLVOAvatar* mAvatar = nullptr; +    LLPointer<LLVOAvatar> mAvatar = nullptr;      LLMeshSkinInfo* mSkinInfo = nullptr; @@ -470,6 +472,9 @@ public:  	sg_iterator beginAlphaGroups();  	sg_iterator endAlphaGroups(); +    sg_iterator beginRiggedAlphaGroups(); +    sg_iterator endRiggedAlphaGroups(); +  	bool hasOcclusionGroups() { return mOcclusionGroupsSize > 0; }  	sg_iterator beginOcclusionGroups();  	sg_iterator endOcclusionGroups(); @@ -488,6 +493,7 @@ public:  	void pushVisibleGroup(LLSpatialGroup* group);  	void pushAlphaGroup(LLSpatialGroup* group); +    void pushRiggedAlphaGroup(LLSpatialGroup* group);  	void pushOcclusionGroup(LLSpatialGroup* group);  	void pushDrawableGroup(LLSpatialGroup* group);  	void pushDrawable(LLDrawable* drawable); @@ -496,6 +502,7 @@ public:  	U32 getVisibleGroupsSize()		{ return mVisibleGroupsSize; }  	U32	getAlphaGroupsSize()		{ return mAlphaGroupsSize; } +    U32	getRiggedAlphaGroupsSize() { return mRiggedAlphaGroupsSize; }  	U32	getDrawableGroupsSize()		{ return mDrawableGroupsSize; }  	U32	getVisibleListSize()		{ return mVisibleListSize; }  	U32	getVisibleBridgeSize()		{ return mVisibleBridgeSize; } @@ -509,6 +516,7 @@ private:  	U32					mVisibleGroupsSize;  	U32					mAlphaGroupsSize; +    U32                 mRiggedAlphaGroupsSize;  	U32					mOcclusionGroupsSize;  	U32					mDrawableGroupsSize;  	U32					mVisibleListSize; @@ -516,6 +524,7 @@ private:  	U32					mVisibleGroupsAllocated;  	U32					mAlphaGroupsAllocated; +    U32                 mRiggedAlphaGroupsAllocated;  	U32					mOcclusionGroupsAllocated;  	U32					mDrawableGroupsAllocated;  	U32					mVisibleListAllocated; @@ -527,6 +536,8 @@ private:  	sg_iterator			mVisibleGroupsEnd;  	sg_list_t			mAlphaGroups;  	sg_iterator			mAlphaGroupsEnd; +    sg_list_t           mRiggedAlphaGroups; +    sg_iterator         mRiggedAlphaGroupsEnd;  	sg_list_t			mOcclusionGroups;  	sg_iterator			mOcclusionGroupsEnd;  	sg_list_t			mDrawableGroups; diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index b2e8348ffd..b5eb2880ae 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -239,17 +239,8 @@ BOOL LLVisualParamHint::render()  	LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE); -	if (gAgentAvatarp->mDrawable.notNull() && -		gAgentAvatarp->mDrawable->getFace(0)) -	{ -		LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)gAgentAvatarp->mDrawable->getFace(0)->getPool(); -		LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); -        gGL.flush(); -		gGL.setSceneBlendType(LLRender::BT_REPLACE); -		avatarPoolp->renderAvatars(gAgentAvatarp);  // renders only one avatar -		gGL.setSceneBlendType(LLRender::BT_ALPHA); -        gGL.flush(); -	} +    gPipeline.previewAvatar(gAgentAvatarp); +  	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);  	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);  	LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr; diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index 728d0c9417..ab4ad5817b 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -109,7 +109,16 @@ void LLTracker::stopTracking(bool clear_ui)  // static virtual  void LLTracker::drawHUDArrow()  { -	if (!gSavedSettings.getBOOL("RenderTrackerBeacon")) return; +    if (!LLWorld::instanceExists()) +    { +        return; +    } + +    static LLCachedControl<bool> render_beacon(gSavedSettings, "RenderTrackerBeacon", true); +    if (!render_beacon) +    { +        return; +    }  	if (gViewerWindow->getProgressView()->getVisible()) return; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 4d86da5f78..40a7f0a941 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -266,9 +266,8 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)  static bool handleVSyncChanged(const LLSD& newvalue)  { -#if LL_WINDOWS      gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean()); -#endif +      return true;  } diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index a26331251c..bc8171b2fc 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -649,9 +649,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)  			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);  		} -		//upkeep gl name pools -		LLGLNamePool::upkeepPools(); -		  		stop_glerror();  		display_update_camera();  		stop_glerror(); @@ -791,6 +788,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)  				LLViewerTexture::updateClass();  			} +            LLImageGLThread::updateClass(); +  			{  				LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_BUMP);  				gBumpImageList.updateImages();  // must be called before gTextureList version so that it's textures are thrown out first. diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 2bc0eeed92..27d8df28c3 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -39,6 +39,7 @@  #include "llfilepicker.h"  #include "llfloaterwebcontent.h"	// for handling window close requests and geometry change requests in media browser windows.  #include "llfocusmgr.h" +#include "llimagegl.h"  #include "llkeyboard.h"  #include "lllogininstance.h"  #include "llmarketplacefunctions.h" @@ -606,6 +607,7 @@ static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMedi  static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE("Update Media");  static LLTrace::BlockTimerStatHandle FTM_MEDIA_SPARE_IDLE("Spare Idle");  static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_INTEREST("Update/Interest"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_VOLUME("Update/Volume");  static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT("Media Sort");  static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT2("Media Sort 2");  static LLTrace::BlockTimerStatHandle FTM_MEDIA_MISC("Misc"); @@ -625,6 +627,13 @@ void LLViewerMedia::updateMedia(void *dummy_arg)  	// Enable/disable the plugin read thread  	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); +    // SL-16418 We can't call LLViewerMediaImpl->update() if we are in the state of shutting down. +    if(LLApp::isExiting()) +    { +        setAllMediaEnabled(false); +        return; +    } +  	// HACK: we always try to keep a spare running webkit plugin around to improve launch times.  	// 2017-04-19 Removed CP - this doesn't appear to buy us much and consumes a lot of resources so  	// removing it for now. @@ -1561,6 +1570,8 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,  		media_tex->setMediaImpl();  	} +    mMainQueue = LL::WorkQueue::getInstance("mainloop"); +    mTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader.  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -1647,11 +1658,13 @@ void LLViewerMediaImpl::destroyMediaSource()  	cancelMimeTypeProbe(); +    mLock.lock();   // Delay tear-down while bg thread is updating  	if(mMediaSource)  	{  		mMediaSource->setDeleteOK(true) ;  		mMediaSource = NULL; // shared pointer  	} +    mLock.unlock();  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -2060,6 +2073,7 @@ void LLViewerMediaImpl::setMute(bool mute)  //////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::updateVolume()  { +    LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_VOLUME);  	if(mMediaSource)  	{  		// always scale the volume by the global media volume @@ -2772,199 +2786,271 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_SET_SUBIMAGE("Set Subimage");  void LLViewerMediaImpl::update()  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE); -	if(mMediaSource == NULL) -	{ -		if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) -		{ -			// This media source should not be loaded. -		} -		else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW) -		{ -			// Don't load new instances that are at PRIORITY_SLIDESHOW or below.  They're just kept around to preserve state. -		} +    if(mMediaSource == NULL) +    { +        if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) +        { +            // This media source should not be loaded. +        } +        else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW) +        { +            // Don't load new instances that are at PRIORITY_SLIDESHOW or below.  They're just kept around to preserve state. +        }          else if (!mMimeProbe.expired()) -		{ -			// this media source is doing a MIME type probe -- don't try loading it again. -		} -		else -		{ -			// This media may need to be loaded. -			if(sMediaCreateTimer.hasExpired()) -			{ -				LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; -				createMediaSource(); -				sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); -			} -			else -			{ -				LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; -			} -		} -	} -	else -	{ -		updateVolume(); +        { +            // this media source is doing a MIME type probe -- don't try loading it again. +        } +        else +        { +            // This media may need to be loaded. +            if(sMediaCreateTimer.hasExpired()) +            { +                LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; +                createMediaSource(); +                sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); +            } +            else +            { +                LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; +            } +        } +    } +    else +    { +        updateVolume(); -		// TODO: this is updated every frame - is this bad? -		// Removing this as part of the post viewer64 media update -		// Removed as not implemented in CEF embedded browser -		// See MAINT-8194 for a more fuller description -		// updateJavascriptObject(); -	} +        // TODO: this is updated every frame - is this bad? +        // Removing this as part of the post viewer64 media update +        // Removed as not implemented in CEF embedded browser +        // See MAINT-8194 for a more fuller description +        // updateJavascriptObject(); +    } -	if(mMediaSource == NULL) -	{ -		return; -	} +    if(mMediaSource == NULL) +    { +        return; +    } -	// Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. -	setNavigateSuspended(true); +    // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. +    setNavigateSuspended(true); -	mMediaSource->idle(); +    mMediaSource->idle(); -	setNavigateSuspended(false); +    setNavigateSuspended(false); -	if(mMediaSource == NULL) -	{ -		return; -	} +    if(mMediaSource == NULL) +    { +        return; +    } -	if(mMediaSource->isPluginExited()) -	{ -		resetPreviousMediaState(); -		destroyMediaSource(); -		return; -	} +    if(mMediaSource->isPluginExited()) +    { +        resetPreviousMediaState(); +        destroyMediaSource(); +        return; +    } -	if(!mMediaSource->textureValid()) -	{ -		return; -	} +    if(!mMediaSource->textureValid()) +    { +        return; +    } -	if(mSuspendUpdates || !mVisible) -	{ -		return; -	} +    if(mSuspendUpdates || !mVisible) +    { +        return; +    } -	LLViewerMediaTexture* placeholder_image = updatePlaceholderImage(); +     +    LLViewerMediaTexture* media_tex; +    U8* data; +    S32 data_width; +    S32 data_height; +    S32 x_pos; +    S32 y_pos; +    S32 width; +    S32 height; + +    if (preMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height)) +    { +        // Push update to worker thread +        auto main_queue = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr; +        if (main_queue) +        { +            mTextureUpdatePending = true; +            ref();  // protect texture from deletion while active on bg queue +            media_tex->ref(); +            main_queue->postTo( +                mTexUpdateQueue, // Worker thread queue +                [=]() // work done on update worker thread +                { +#if LL_IMAGEGL_THREAD_CHECK +                    media_tex->getGLTexture()->mActiveThread = LLThread::currentID(); +#endif +                    doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, true); +                }, +                [=]() // callback to main thread +                { +#if LL_IMAGEGL_THREAD_CHECK +                    media_tex->getGLTexture()->mActiveThread = LLThread::currentID(); +#endif +                    mTextureUpdatePending = false; +                    media_tex->unref(); +                    unref(); +                }); +        } +        else +        { +            doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, false); // otherwise, update on main thread +        } +    } +} -	if(placeholder_image) -	{ -		LLRect dirty_rect; +bool LLViewerMediaImpl::preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& data, S32& data_width, S32& data_height, S32& x_pos, S32& y_pos, S32& width, S32& height) +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; -		// Since we're updating this texture, we know it's playing.  Tell the texture to do its replacement magic so it gets rendered. -		placeholder_image->setPlaying(TRUE); +    bool retval = false; -		if(mMediaSource->getDirty(&dirty_rect)) -		{ -			// Constrain the dirty rect to be inside the texture -			S32 x_pos = llmax(dirty_rect.mLeft, 0); -			S32 y_pos = llmax(dirty_rect.mBottom, 0); -			S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos; -			S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos; +    if (!mTextureUpdatePending) +    { +        media_tex = updateMediaImage(); -			if(width > 0 && height > 0) -			{ +        if (media_tex && mMediaSource) +        { +            LLRect dirty_rect; +            S32 media_width = mMediaSource->getTextureWidth(); +            S32 media_height = mMediaSource->getTextureHeight(); +            //S32 media_depth = mMediaSource->getTextureDepth(); -				U8* data = NULL; -				{ -					LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media get data"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA); -					data = mMediaSource->getBitsData(); -				} +            // Since we're updating this texture, we know it's playing.  Tell the texture to do its replacement magic so it gets rendered. +            media_tex->setPlaying(TRUE); -				if(data != NULL) -				{ -					// Offset the pixels pointer to match x_pos and y_pos -					data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); -					data += ( y_pos * mMediaSource->getTextureDepth() ); +            if (mMediaSource->getDirty(&dirty_rect)) +            { +                // Constrain the dirty rect to be inside the texture +                x_pos = llmax(dirty_rect.mLeft, 0); +                y_pos = llmax(dirty_rect.mBottom, 0); +                width = llmin(dirty_rect.mRight, media_width) - x_pos; +                height = llmin(dirty_rect.mTop, media_height) - y_pos; -					{ -						LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media set subimage"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE); -									placeholder_image->setSubImage( -									data, -									mMediaSource->getBitsWidth(), -									mMediaSource->getBitsHeight(), -									x_pos, -									y_pos, -									width, -									height); -					} -				} +                if (width > 0 && height > 0) +                { +                    data = mMediaSource->getBitsData(); +                    data_width = mMediaSource->getWidth(); +                    data_height = mMediaSource->getHeight(); + +                    if (data != NULL) +                    { +                        // data is ready to be copied to GL +                        retval = true; +                    } +                } -			} +                mMediaSource->resetDirty(); +            } +        } +    } -			mMediaSource->resetDirty(); -		} -	} +    return retval;  } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync) +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; +    mLock.lock();   // don't allow media source tear-down during update + +    // wrap "data" in an LLImageRaw but do NOT make a copy +    LLPointer<LLImageRaw> raw = new LLImageRaw(data, media_tex->getWidth(), media_tex->getHeight(), media_tex->getComponents(), true); +         +    // Allocate GL texture based on LLImageRaw but do NOT copy to GL +    LLGLuint tex_name = 0; +    media_tex->createGLTexture(0, raw, 0, TRUE, LLGLTexture::OTHER, true, &tex_name); + +    // copy just the subimage covered by the image raw to GL +    media_tex->setSubImage(data, data_width, data_height, x_pos, y_pos, width, height, tex_name); +     +    if (sync) +    { +        media_tex->getGLTexture()->syncToMainThread(tex_name); +    } +    else +    { +        media_tex->getGLTexture()->syncTexName(tex_name); +    } +     +    // release the data pointer before freeing raw so LLImageRaw destructor doesn't +    // free memory at data pointer +    raw->releaseData(); + +    mLock.unlock(); +}  //////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::updateImagesMediaStreams()  {  } -  ////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() +LLViewerMediaTexture* LLViewerMediaImpl::updateMediaImage()  { -	if(mTextureId.isNull()) -	{ -		// The code that created this instance will read from the plugin's bits. -		return NULL; -	} - -	LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId ); - -	if (mNeedsNewTexture -		|| placeholder_image->getUseMipMaps() -		|| (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) -		|| (placeholder_image->getHeight() != mMediaSource->getTextureHeight()) -		|| (mTextureUsedWidth != mMediaSource->getWidth()) -		|| (mTextureUsedHeight != mMediaSource->getHeight()) -		) -	{ -		LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; -		LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; - -		int texture_width = mMediaSource->getTextureWidth(); -		int texture_height = mMediaSource->getTextureHeight(); -		int texture_depth = mMediaSource->getTextureDepth(); - -		// MEDIAOPT: check to see if size actually changed before doing work -		placeholder_image->destroyGLTexture(); -		// MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? -		placeholder_image->reinit(FALSE);	// probably not needed - -		// MEDIAOPT: seems insane that we actually have to make an imageraw then -		// immediately discard it -		LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth); -		// Clear the texture to the background color, ignoring alpha. -		// convert background color channels from [0.0, 1.0] to [0, 255]; -		raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff); -		int discard_level = 0; - -		// ask media source for correct GL image format constants -		placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), -											 mMediaSource->getTextureFormatPrimary(), -											 mMediaSource->getTextureFormatType(), -											 mMediaSource->getTextureFormatSwapBytes()); - -		placeholder_image->createGLTexture(discard_level, raw); - -		// MEDIAOPT: set this dynamically on play/stop -		// FIXME -//		placeholder_image->mIsMediaTexture = true; -		mNeedsNewTexture = false; - -		// If the amount of the texture being drawn by the media goes down in either width or height, -		// recreate the texture to avoid leaving parts of the old image behind. -		mTextureUsedWidth = mMediaSource->getWidth(); -		mTextureUsedHeight = mMediaSource->getHeight(); -	} +    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; +    if (!mMediaSource) +    { +        return nullptr; // not ready for updating +    } -	return placeholder_image; +    llassert(!mTextureId.isNull()); +    LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture( mTextureId ); +  +    if ( mNeedsNewTexture +        || media_tex->getUseMipMaps() +        || (media_tex->getWidth() != mMediaSource->getTextureWidth()) +        || (media_tex->getHeight() != mMediaSource->getTextureHeight()) +        || (mTextureUsedWidth != mMediaSource->getWidth()) +        || (mTextureUsedHeight != mMediaSource->getHeight()) +        ) +    { +        LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; +        LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; + +        int texture_width = mMediaSource->getTextureWidth(); +        int texture_height = mMediaSource->getTextureHeight(); +        int texture_depth = mMediaSource->getTextureDepth(); + +        // MEDIAOPT: check to see if size actually changed before doing work +        media_tex->destroyGLTexture(); +        // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? +        media_tex->reinit(FALSE);	// probably not needed + +        // MEDIAOPT: seems insane that we actually have to make an imageraw then +        // immediately discard it +        LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth); +        // Clear the texture to the background color, ignoring alpha. +        // convert background color channels from [0.0, 1.0] to [0, 255]; +        raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff); + +        // ask media source for correct GL image format constants +        media_tex->setExplicitFormat(mMediaSource->getTextureFormatInternal(), +            mMediaSource->getTextureFormatPrimary(), +            mMediaSource->getTextureFormatType(), +            mMediaSource->getTextureFormatSwapBytes()); + +        int discard_level = 0; +        media_tex->createGLTexture(discard_level, raw); + +        // MEDIAOPT: set this dynamically on play/stop +        // FIXME +//		media_tex->mIsMediaTexture = true; +        mNeedsNewTexture = false; + +        // If the amount of the texture being drawn by the media goes down in either width or height, +        // recreate the texture to avoid leaving parts of the old image behind. +        mTextureUsedWidth = mMediaSource->getWidth(); +        mTextureUsedHeight = mMediaSource->getHeight(); +    } +    return media_tex;  } diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 71cec5125d..806692929a 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -197,7 +197,7 @@ public:  		U8 media_loop);  	~LLViewerMediaImpl(); -	 +  	// Override inherited version from LLViewerMediaEventEmitter   	virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event); @@ -266,6 +266,8 @@ public:  	void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y);  	void update(); +    bool preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& data, S32& data_width, S32& data_height, S32& x_pos, S32& y_pos, S32& width, S32& height); +    void doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync);  	void updateImagesMediaStreams();  	LLUUID getMediaTextureID() const; @@ -427,6 +429,7 @@ private:  private:  	// a single media url with some data and an impl.  	boost::shared_ptr<LLPluginClassMedia> mMediaSource; +    LLMutex mLock;  	F64		mZoomFactor;  	LLUUID mTextureId;  	bool  mMovieImageHasMips; @@ -446,6 +449,7 @@ private:  	S32 mTextureUsedWidth;  	S32 mTextureUsedHeight;  	bool mSuspendUpdates; +    bool mTextureUpdatePending = false;  	bool mVisible;  	ECursorType mLastSetCursor;  	EMediaNavState mMediaNavState; @@ -479,7 +483,7 @@ private:  	LLNotificationPtr mNotification;      bool mCleanBrowser;     // force the creation of a clean browsing target with full options enabled      static std::vector<std::string> sMimeTypesFailed; - +    LLPointer<LLImageRaw> mRawImage; //backing buffer for texture updates  private:  	BOOL mIsUpdated ;  	std::list< LLVOVolume* > mObjectList ; @@ -489,7 +493,10 @@ private:      bool mCanceling;  private: -	LLViewerMediaTexture *updatePlaceholderImage(); +	LLViewerMediaTexture *updateMediaImage(); +    LL::WorkQueue::weak_t mMainQueue; +    LL::WorkQueue::weak_t mTexUpdateQueue; +  };  #endif	// LLVIEWERMEDIA_H diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index 3cdef0ebff..5eda75753e 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -787,42 +787,39 @@ void LLViewerOctreeGroup::checkStates()  //occulsion culling functions and classes  //-------------------------------------------------------------------------------------------  std::set<U32> LLOcclusionCullingGroup::sPendingQueries; -class LLOcclusionQueryPool : public LLGLNamePool -{ -public: -	LLOcclusionQueryPool() -	{ -	} - -protected: -	virtual GLuint allocateName() -	{ -		GLuint ret = 0; +static std::queue<GLuint> sFreeQueries; -		glGenQueriesARB(1, &ret); -	 -		return ret; -	} +#define QUERY_POOL_SIZE 1024 -	virtual void releaseName(GLuint name) -	{ -#if LL_TRACK_PENDING_OCCLUSION_QUERIES -		LLOcclusionCullingGroup::sPendingQueries.erase(name); -#endif -		glDeleteQueriesARB(1, &name); -	} -}; - -static LLOcclusionQueryPool sQueryPool;  U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName()  { -	return sQueryPool.allocate(); +    LL_PROFILE_ZONE_SCOPED; +     +    if (sFreeQueries.empty()) +    { +        //seed 1024 query names into the free query pool +        GLuint queries[1024]; +        glGenQueriesARB(1024, queries); +        for (int i = 0; i < 1024; ++i) +        { +            sFreeQueries.push(queries[i]); +        } +    } + +    // pull from pool +    GLuint ret = sFreeQueries.front(); +    sFreeQueries.pop(); +    return ret;  }  void LLOcclusionCullingGroup::releaseOcclusionQueryObjectName(GLuint name)  { -	sQueryPool.release(name); +    if (name != 0) +    { +        LL_PROFILE_ZONE_SCOPED; +        sFreeQueries.push(name); +    }  }  //===================================== @@ -1243,7 +1240,14 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh  						//store which frame this query was issued on  						mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount; -    					glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					 +                        { +                            LL_PROFILE_ZONE_NAMED("glBeginQuery"); + +                            //get an occlusion query that hasn't been used in awhile +                            releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +                            mOcclusionQuery[LLViewerCamera::sCurCameraID] = getNewOcclusionQueryObjectName(); +                            glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); +                        }  						LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;  						llassert(shader); @@ -1282,7 +1286,10 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh  							}  						} -						glEndQueryARB(mode); +                        { +                            LL_PROFILE_ZONE_NAMED("glEndQuery"); +                            glEndQueryARB(mode); +                        }  					}  				} diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 56370df751..e69b0347f8 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -878,7 +878,7 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const  void LLViewerParcelMgr::render()  { -	if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection")) +	if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection") && !gDisconnected)  	{  		// Rendering is done in agent-coordinates, so need to supply  		// an appropriate offset to the render code. diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 5fed46f437..e3ac56d0d3 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -515,9 +515,10 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;      static LLFrameTimer timer; +      static S32Megabytes gpu_res = S32Megabytes(S32_MAX);      static S32Megabytes physical_res = S32Megabytes(S32_MAX); - +          if (timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second.      {          gpu = gpu_res; @@ -527,22 +528,11 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p      timer.reset();      { -        if (gGLManager.mHasATIMemInfo) -        { -            S32 meminfo[4]; -            glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); -            gpu_res = (S32Megabytes)meminfo[0]; - -            //check main memory, only works for windows. -            LLMemory::updateMemoryInfo(); -            physical_res = LLMemory::getAvailableMemKB(); -        } -        else if (gGLManager.mHasNVXMemInfo) -        { -            S32 free_memory; -            glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory); -            gpu_res = (S32Megabytes)(free_memory / 1024); -        } +        gpu_res = (S32Megabytes) LLImageGLThread::getFreeVRAMMegabytes(); +         +        //check main memory, only works for windows. +        LLMemory::updateMemoryInfo(); +        physical_res = LLMemory::getAvailableMemKB();          gpu = gpu_res;          physical = physical_res; @@ -1629,7 +1619,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture()          mNeedsCreateTexture = TRUE;          if (preCreateTexture())          { -            ref();  #if LL_IMAGEGL_THREAD_CHECK              //grab a copy of the raw image data to make sure it isn't modified pending texture creation              U8* data = mRawImage->getData(); @@ -1645,6 +1634,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture()              auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;              if (mainq)              { +                ref();                  mainq->postTo(                      mImageQueue,                      // work to be done on LLImageGL worker thread @@ -1691,7 +1681,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture()              else              {                  gTextureList.mCreateTextureList.insert(this); -                unref();              }          }      } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 5487f0851e..a54c29a404 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2024,12 +2024,12 @@ LLViewerWindow::LLViewerWindow(const Params& p)  	// Init the image list.  Must happen after GL is initialized and before the images that  	// LLViewerWindow needs are requested. -	LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreaded")); +    LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreaded"));  	gTextureList.init();  	LLViewerTextureManager::init() ;  	gBumpImageList.init(); -	// Create container for all sub-views +    // Create container for all sub-views  	LLView::Params rvp;  	rvp.name("root");  	rvp.rect(mWindowRectScaled); @@ -2417,7 +2417,7 @@ void LLViewerWindow::shutdownGL()  	LLViewerTextureManager::cleanup() ;  	SUBSYSTEM_CLEANUP(LLImageGL) ; - +      	LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ;  	LL_INFOS() << "Cleaning up select manager" << LL_ENDL; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 548dadddb4..6a5cd6eabc 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -127,6 +127,9 @@ const F32 MIN_HOVER_Z = -2.0;  const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f;  const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f; +// Unlike with 'self' avatar, server doesn't inform viewer about +// expected attachments so viewer has to wait to see if anything +// else will arrive  const F32 FIRST_APPEARANCE_CLOUD_MIN_DELAY = 3.f; // seconds  const F32 FIRST_APPEARANCE_CLOUD_MAX_DELAY = 45.f; @@ -616,6 +619,7 @@ F32 LLVOAvatar::sUnbakedTime = 0.f;  F32 LLVOAvatar::sUnbakedUpdateTime = 0.f;  F32 LLVOAvatar::sGreyTime = 0.f;  F32 LLVOAvatar::sGreyUpdateTime = 0.f; +LLPointer<LLViewerTexture> LLVOAvatar::sCloudTexture = NULL;  //-----------------------------------------------------------------------------  // Helper functions @@ -746,7 +750,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	mCurrentGesticulationLevel = 0; -	mFirstSeenTimer.reset(); +    mFirstAppearanceMessageTimer.reset();  	mRuthTimer.reset();  	mRuthDebugTimer.reset();  	mDebugExistenceTimer.reset(); @@ -1133,6 +1137,7 @@ void LLVOAvatar::initClass()  	LLControlAvatar::sRegionChangedSlot = gAgent.addRegionChangedCallback(&LLControlAvatar::onRegionChanged); +    sCloudTexture = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c");  } @@ -2826,7 +2831,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)                      //override rigged attachments' octree spatial extents with this avatar's bounding box                      LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();                      bool rigged = false; -                    if (bridge) +                    if (bridge && !bridge->isDead())                      {                          //transform avatar bounding box into attachment's coordinate frame                          LLVector4a extents[2]; @@ -2843,13 +2848,21 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)                      attached_object->mDrawable->makeActive();                      attached_object->mDrawable->updateXform(TRUE); -                    if (!rigged) +                    if (bridge && !bridge->isDead())                      { -                        if (bridge) +                        if (!rigged)                          {                              gPipeline.updateMoveNormalAsync(bridge);                          } +                        else +                        { +                            //specialized impl of updateMoveNormalAsync just for rigged attachment SpatialBridge +                            bridge->setState(LLDrawable::MOVE_UNDAMPED); +                            bridge->updateMove(); +                            bridge->setState(LLDrawable::EARLY_MOVE); +                        }                      } +  					attached_object->updateText();	  				}  			} @@ -3073,8 +3086,7 @@ void LLVOAvatar::idleUpdateLoadingEffect()  			particle_parameters.mPartData.mStartColor        = LLColor4(1, 1, 1, 0.5f);  			particle_parameters.mPartData.mEndColor          = LLColor4(1, 1, 1, 0.0f);  			particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f; -			LLViewerTexture* cloud = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c"); -			particle_parameters.mPartImageID                 = cloud->getID(); +			particle_parameters.mPartImageID                 = sCloudTexture->getID();  			particle_parameters.mMaxAge                      = 0.f;  			particle_parameters.mPattern                     = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE;  			particle_parameters.mInnerAngle                  = F_PI; @@ -6428,6 +6440,16 @@ void LLVOAvatar::updateAttachmentOverrides()  #endif  } +void LLVOAvatar::notifyAttachmentMeshLoaded() +{ +    if (!isFullyLoaded()) +    { +        // We just received mesh or skin info +        // Reset timer to wait for more potential meshes or changes +        mFullyLoadedTimer.reset(); +    } +} +  //-----------------------------------------------------------------------------  // addAttachmentOverridesForObject  //----------------------------------------------------------------------------- @@ -8150,7 +8172,7 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading)                  // Note that textures can causes 60s delay on thier own                  // so this delay might end up on top of textures' delay                  mFirstUseDelaySeconds = llclamp( -                    mFirstSeenTimer.getElapsedTimeF32(), +                    mFirstAppearanceMessageTimer.getElapsedTimeF32(),                      FIRST_APPEARANCE_CLOUD_MIN_DELAY,                      FIRST_APPEARANCE_CLOUD_MAX_DELAY); @@ -8920,6 +8942,9 @@ void LLVOAvatar::onFirstTEMessageReceived()          mMeshTexturesDirty = TRUE;  		gPipeline.markGLRebuild(this); + +        mFirstAppearanceMessageTimer.reset(); +        mFullyLoadedTimer.reset();  	}  } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 282d0f6cdd..acebbc1074 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -206,7 +206,7 @@ public:      inline LLJoint* getSkeletonJoint(S32 joint_num) { return mSkeleton[joint_num]; }      inline size_t getSkeletonJointCount() const { return mSkeleton.size(); } - +    void 					notifyAttachmentMeshLoaded();  	void 					addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen = NULL, bool recursive = true);  	void					removeAttachmentOverridesForObject(const LLUUID& mesh_id);  	void					removeAttachmentOverridesForObject(LLViewerObject *vo); @@ -337,7 +337,8 @@ public:  	static F32		sLODFactor; // user-settable LOD factor  	static F32		sPhysicsLODFactor; // user-settable physics LOD factor  	static BOOL		sJointDebug; // output total number of joints being touched for each avatar -	static BOOL		sDebugAvatarRotation; + +    static LLPointer<LLViewerTexture>  sCloudTexture;  	//--------------------------------------------------------------------  	// Region state @@ -380,7 +381,7 @@ protected:  private:  	BOOL			mFirstFullyVisible;  	F32				mFirstUseDelaySeconds; -	LLFrameTimer	mFirstSeenTimer; +	LLFrameTimer	mFirstAppearanceMessageTimer;  	BOOL			mFullyLoaded;  	BOOL			mPreviousFullyLoaded; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 4d72dc8776..1625dd5276 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -225,6 +225,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re  	mNumFaces = 0;  	mLODChanged = FALSE;  	mSculptChanged = FALSE; +    mColorChanged = FALSE;  	mSpotLightPriority = 0.f;  	mMediaImplList.resize(getNumTEs()); @@ -1170,13 +1171,17 @@ void LLVOVolume::notifyMeshLoaded()  	mSculptChanged = TRUE;  	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); -    if (getAvatar() && !isAnimatedObject()) +    LLVOAvatar *av = getAvatar(); +    if (av && !isAnimatedObject())      { -        getAvatar()->addAttachmentOverridesForObject(this); +        av->addAttachmentOverridesForObject(this); +        av->notifyAttachmentMeshLoaded();      } -    if (getControlAvatar() && isAnimatedObject()) +    LLControlAvatar *cav = getControlAvatar(); +    if (cav && isAnimatedObject())      { -        getControlAvatar()->addAttachmentOverridesForObject(this); +        cav->addAttachmentOverridesForObject(this); +        cav->notifyAttachmentMeshLoaded();      }      updateVisualComplexity();  } @@ -2027,7 +2032,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)  			was_regen_faces = lodOrSculptChanged(drawable, compiled);  			drawable->setState(LLDrawable::REBUILD_VOLUME);  		} -		else if (mSculptChanged || mLODChanged) +		else if (mSculptChanged || mLODChanged || mColorChanged)  		{  			compiled = TRUE;  			was_regen_faces = lodOrSculptChanged(drawable, compiled); @@ -2039,7 +2044,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)  		genBBoxes(FALSE);  	} -	else if (mLODChanged || mSculptChanged) +	else if (mLODChanged || mSculptChanged || mColorChanged)  	{  		dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));  		compiled = TRUE; @@ -2071,6 +2076,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)  	mLODChanged = FALSE;  	mSculptChanged = FALSE;  	mFaceMappingChanged = FALSE; +    mColorChanged = FALSE;  	return LLViewerObject::updateGeometry(drawable);  } @@ -2209,6 +2215,7 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color)  		if (mDrawable.notNull() && retval)  		{  			// These should only happen on updates which are not the initial update. +            mColorChanged = TRUE;  			mDrawable->setState(LLDrawable::REBUILD_COLOR);  			dirtyMesh();  		} @@ -5139,7 +5146,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,      bool rigged = facep->isState(LLFace::RIGGED); -    if (rigged && type != LLRenderPass::PASS_ALPHA) +    if (rigged)      {          // hacky, should probably clean up -- if this face is rigged, put it in "type + 1"          // See LLRenderPass PASS_foo enum @@ -5903,23 +5910,25 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  	U32 geometryBytes = 0; +    // generate render batches for static geometry      U32 extra_mask = LLVertexBuffer::MAP_TEXTURE_INDEX; -	geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[0], simple_count[0], FALSE, batch_textures); -	geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[0], fullbright_count[0], FALSE, batch_textures); -	geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[0], alpha_count[0], TRUE, batch_textures); -	geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[0], bump_count[0], FALSE, FALSE); -	geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[0], norm_count[0], FALSE, FALSE); -	geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[0], spec_count[0], FALSE, FALSE); -	geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[0], normspec_count[0], FALSE, FALSE); - -    extra_mask |= LLVertexBuffer::MAP_WEIGHT4; -    geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[1], simple_count[1], FALSE, batch_textures, TRUE); -    geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[1], fullbright_count[1], FALSE, batch_textures, TRUE); -    geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[1], alpha_count[1], TRUE, batch_textures, TRUE); -    geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[1], bump_count[1], FALSE, TRUE); -    geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[1], norm_count[1], FALSE, TRUE); -    geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[1], spec_count[1], FALSE, TRUE); -    geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[1], normspec_count[1], FALSE, TRUE); +    BOOL alpha_sort = TRUE; +    BOOL rigged = FALSE; +    for (int i = 0; i < 2; ++i) //two sets, static and rigged) +    { +        geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[i], simple_count[i], FALSE, batch_textures, rigged); +        geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[i], fullbright_count[i], FALSE, batch_textures, rigged); +        geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[i], alpha_count[i], alpha_sort, batch_textures, rigged); +        geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[i], bump_count[i], FALSE, FALSE, rigged); +        geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[i], norm_count[i], FALSE, FALSE, rigged); +        geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[i], spec_count[i], FALSE, FALSE, rigged); +        geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[i], normspec_count[i], FALSE, FALSE, rigged); + +        // for rigged set, add weights and disable alpha sorting (rigged items use depth buffer) +        extra_mask |= LLVertexBuffer::MAP_WEIGHT4; +        alpha_sort = FALSE; +        rigged = TRUE; +    }  	group->mGeometryBytes = geometryBytes; @@ -5972,8 +5981,9 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)  				if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )  				{  					LLVOVolume* vobj = drawablep->getVOVolume(); -                    if (!vobj) continue; - +					 +					if (!vobj) continue; +					  					if (debugLoggingEnabled("AnimatedObjectsLinkset"))  					{  						if (vobj->isAnimatedObject() && vobj->isRiggedMesh()) @@ -5993,7 +6003,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)  					}  					LLVolume* volume = vobj->getVolume(); -                    if (!volume) continue; +					if (!volume) continue;  					for (S32 i = 0; i < drawablep->getNumFaces(); ++i)  					{  						LLFace* face = drawablep->getFace(i); diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index d158044f5d..4cb7a5481c 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -413,6 +413,7 @@ private:  	S32			mLOD;  	BOOL		mLODChanged;  	BOOL		mSculptChanged; +    BOOL		mColorChanged;  	F32			mSpotLightPriority;  	LLMatrix4	mRelativeXform;  	LLMatrix3	mRelativeXformInvTrans; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index a6fa58f476..a3c971153c 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3828,6 +3828,16 @@ void LLPipeline::postSort(LLCamera& camera)  					sCull->pushAlphaGroup(group);  				}  			} + +            LLSpatialGroup::draw_map_t::iterator rigged_alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA_RIGGED); + +            if (rigged_alpha != group->mDrawMap.end()) +            { //store rigged alpha groups for LLDrawPoolAlpha prepass (skip distance update, rigged attachments use depth buffer) +                if (hasRenderType(LLDrawPool::POOL_ALPHA)) +                { +                    sCull->pushRiggedAlphaGroup(group); +                } +            }  		}  	} @@ -7264,11 +7274,6 @@ void LLPipeline::doResetVertexBuffers(bool forced)  	SUBSYSTEM_CLEANUP(LLVertexBuffer); -	//delete all name pool caches -	LLGLNamePool::cleanupPools(); - -	 -  	if (LLVertexBuffer::sGLCount > 0)  	{  		LL_WARNS() << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << LL_ENDL; @@ -9332,7 +9337,11 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)                  LLColor3 col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor();                  glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); -                LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1; +                // HACK FIX -- pretend underwater camera is the world camera to fix weird visibility artifacts +                // during distortion render (doesn't break main render because the camera is the same perspective +                // as world camera and occlusion culling is disabled for this pass) +                //LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1; +                LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;                  mWaterDis.bindTarget();                  mWaterDis.getViewport(gGLViewport); @@ -11125,6 +11134,167 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)  	LLGLState::checkTextureChannels();  } +static LLTrace::BlockTimerStatHandle FTM_PREVIEW_AVATAR("Preview Avatar"); + +void LLPipeline::previewAvatar(LLVOAvatar* avatar) +{ +    LL_RECORD_BLOCK_TIME(FTM_PREVIEW_AVATAR); + +    LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); +    gGL.flush(); +    gGL.setSceneBlendType(LLRender::BT_REPLACE); + +    LLGLState::checkStates(); +    LLGLState::checkTextureChannels(); + +    static LLCullResult result; +    result.clear(); +    grabReferences(result); + +    if (!avatar || !avatar->mDrawable) +    { +        LL_WARNS_ONCE("AvatarRenderPipeline") << "Avatar is " << (avatar ? "not drawable" : "null") << LL_ENDL; +        return; +    } +    LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " is drawable" << LL_ENDL; + +    assertInitialized(); + +    pushRenderTypeMask(); + +    { +        //hide world geometry +        clearRenderTypeMask( +            RENDER_TYPE_SKY, +            RENDER_TYPE_WL_SKY, +            RENDER_TYPE_GROUND, +            RENDER_TYPE_TERRAIN, +            RENDER_TYPE_GRASS, +            RENDER_TYPE_CONTROL_AV, // Animesh +            RENDER_TYPE_TREE, +            RENDER_TYPE_VOIDWATER, +            RENDER_TYPE_WATER, +            RENDER_TYPE_PASS_GRASS, +            RENDER_TYPE_HUD, +            RENDER_TYPE_PARTICLES, +            RENDER_TYPE_CLOUDS, +            RENDER_TYPE_HUD_PARTICLES, +            END_RENDER_TYPES +        ); +    } + +    S32 occlusion = sUseOcclusion; +    sUseOcclusion = 0; + +    sReflectionRender = !sRenderDeferred; + +    sShadowRender = true; +    sImpostorRender = true; // Likely not needed for previews + +    LLViewerCamera* viewer_camera = LLViewerCamera::getInstance(); + +    { +        markVisible(avatar->mDrawable, *viewer_camera); + +        LLVOAvatar::attachment_map_t::iterator iter; +        for (iter = avatar->mAttachmentPoints.begin(); +            iter != avatar->mAttachmentPoints.end(); +            ++iter) +        { +            LLViewerJointAttachment *attachment = iter->second; +            for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +                attachment_iter != attachment->mAttachedObjects.end(); +                ++attachment_iter) +            { +                if (LLViewerObject* attached_object = attachment_iter->get()) +                { +                    markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); +                } +            } +        } +    } + +    stateSort(*LLViewerCamera::getInstance(), result); + +    LLCamera camera = *viewer_camera; + +    F32 old_alpha = LLDrawPoolAvatar::sMinimumAlpha; + +    if (LLPipeline::sRenderDeferred) +    { +        renderGeomDeferred(camera); + +        renderGeomPostDeferred(camera); +    } +    else +    { +        renderGeom(camera); +    } + +    LLDrawPoolAvatar::sMinimumAlpha = old_alpha; + +    { //create alpha mask based on depth buffer +        if (LLPipeline::sRenderDeferred) +        { +            GLuint buff = GL_COLOR_ATTACHMENT0; +            LL_PROFILER_GPU_ZONEC("gl.DrawBuffersARB", 0x8000FF); +            glDrawBuffersARB(1, &buff); +        } + +        LLGLDisable blend(GL_BLEND); + +        gGL.setColorMask(false, true); + +        gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +        LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); + +        gGL.flush(); + +        gGL.pushMatrix(); +        gGL.loadIdentity(); +        gGL.matrixMode(LLRender::MM_PROJECTION); +        gGL.pushMatrix(); +        gGL.loadIdentity(); + +        static const F32 clip_plane = 0.99999f; + +        gDebugProgram.bind(); + +        gGL.begin(LLRender::QUADS); +        gGL.vertex3f(-1, -1, clip_plane); +        gGL.vertex3f(1, -1, clip_plane); +        gGL.vertex3f(1, 1, clip_plane); +        gGL.vertex3f(-1, 1, clip_plane); +        gGL.end(); +        gGL.flush(); + +        gDebugProgram.unbind(); + +        gGL.popMatrix(); +        gGL.matrixMode(LLRender::MM_MODELVIEW); +        gGL.popMatrix(); +    } + +    sUseOcclusion = occlusion; +    sReflectionRender = false; +    sImpostorRender = false; +    sShadowRender = false; +    popRenderTypeMask(); + +    gGL.matrixMode(LLRender::MM_PROJECTION); +    gGL.popMatrix(); +    gGL.matrixMode(LLRender::MM_MODELVIEW); +    gGL.popMatrix(); + +    LLVertexBuffer::unbind(); +    LLGLState::checkStates(); +    LLGLState::checkTextureChannels(); + +    gGL.setSceneBlendType(LLRender::BT_ALPHA); +    gGL.flush(); +} +  bool LLPipeline::hasRenderBatches(const U32 type) const  {  	return sCull->getRenderMapSize(type) > 0; @@ -11150,6 +11320,16 @@ LLCullResult::sg_iterator LLPipeline::endAlphaGroups()  	return sCull->endAlphaGroups();  } +LLCullResult::sg_iterator LLPipeline::beginRiggedAlphaGroups() +{ +    return sCull->beginRiggedAlphaGroups(); +} + +LLCullResult::sg_iterator LLPipeline::endRiggedAlphaGroups() +{ +    return sCull->endRiggedAlphaGroups(); +} +  bool LLPipeline::hasRenderType(const U32 type) const  {      // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render" diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index b86b68b09d..4946bac701 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -135,6 +135,7 @@ public:  	void resetVertexBuffers(LLDrawable* drawable);  	void generateImpostor(LLVOAvatar* avatar); +    void previewAvatar(LLVOAvatar* avatar);  	void bindScreenToTexture();  	void renderFinalize(); @@ -338,6 +339,8 @@ public:  	LLCullResult::drawinfo_iterator endRenderMap(U32 type);  	LLCullResult::sg_iterator beginAlphaGroups();  	LLCullResult::sg_iterator endAlphaGroups(); +    LLCullResult::sg_iterator beginRiggedAlphaGroups(); +    LLCullResult::sg_iterator endRiggedAlphaGroups();  	void addTrianglesDrawn(S32 index_count, U32 render_type = LLRender::TRIANGLES); diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 7be0e0ad85..98f74d321b 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -8821,13 +8821,6 @@ See SecondLife.log for details      type="alert">      Error while requesting mesh upload permissons.    </notification> - -  <notification -    name="MeshUploadProfilerError" -    icon="alert.tga" -    type="alert"> -Mesh uploader is incompatible with RenderGLCoreProfile, please turn RenderGLCoreProfile off in debug settings and restart the viewer. -  </notification>    <notification      name="RegionCapabilityRequestError" | 
