diff options
| -rw-r--r-- | indra/llrender/llgl.cpp | 90 | ||||
| -rw-r--r-- | indra/llrender/llgl.h | 45 | ||||
| -rw-r--r-- | indra/llrender/llgltexture.cpp | 14 | ||||
| -rw-r--r-- | indra/llrender/llgltexture.h | 7 | ||||
| -rw-r--r-- | indra/llrender/llimagegl.cpp | 119 | ||||
| -rw-r--r-- | indra/llrender/llimagegl.h | 17 | ||||
| -rw-r--r-- | indra/llwindow/llwindowwin32.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/lldrawpoolbump.cpp | 203 | ||||
| -rw-r--r-- | indra/newview/lldrawpoolbump.h | 2 | ||||
| -rw-r--r-- | indra/newview/llviewerdisplay.cpp | 3 | ||||
| -rw-r--r-- | indra/newview/llviewermedia.cpp | 7 | ||||
| -rw-r--r-- | indra/newview/llvieweroctree.cpp | 93 | ||||
| -rw-r--r-- | indra/newview/llviewertexture.cpp | 24 | ||||
| -rw-r--r-- | indra/newview/pipeline.cpp | 5 | 
14 files changed, 316 insertions, 314 deletions
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 50a5972d28..639d1fba32 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -2150,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)  { @@ -2460,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 c7de8bc338..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 defer_copy) +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, defer_copy) ; +	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 use_new_name /* = false */) +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, 0, use_new_name) ; +	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 use_new_name /* = false */) +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, 0, use_new_name) ; +	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 216e7f640d..8cfe7b62de 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -132,13 +132,14 @@ public:      // 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 -    BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER, bool defer_copy = false); +    // 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 use_new_name = false); -	BOOL       setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool use_new_name = false); +	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 694c4a7b06..110074bdc0 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() @@ -1075,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 /* = FALSE */, bool use_new_name /* = false */) +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 (0 == (use_new_name ? mNewTexName : mTexName)) +    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; @@ -1098,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, use_new_name ? mNewTexName : mTexName); +		setImage(datap, FALSE, tex_name);  	}  	else  	{ @@ -1150,7 +1152,7 @@ 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, use_new_name ? mNewTexName : mTexName); +		BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, tex_name);  		if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL;  		stop_glerror(); @@ -1171,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 /* = FALSE */, bool use_new_name /* = false */) +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, use_new_name); +	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 @@ -1361,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 defer_copy) +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(); @@ -1474,15 +1476,17 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S  	setCategory(category);   	const U8* rawdata = imageraw->getData(); -	return createGLTexture(discard_level, rawdata, FALSE, usename, defer_copy); +	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 defer_copy) +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(); +    bool main_thread = on_main_thread(); +      if (defer_copy)      {          data_in = nullptr; @@ -1501,29 +1505,40 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_      }      discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); -    if (!defer_copy // <--- hacky way to force creation of mNewTexName from media texture update +    if (main_thread // <--- always force creation of mNewTexName when not on main thread          && 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; @@ -1531,9 +1546,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. @@ -1550,11 +1568,11 @@ 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 (!main_thread)      {          if (!defer_copy)          { -            syncToMainThread(); +            syncToMainThread(new_texname);          }      }      else  @@ -1564,8 +1582,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_          {              LLImageGL::deleteTextures(1, &old_texname);          } -        mTexName = mNewTexName; -        mNewTexName = 0; +        mTexName = new_texname;      }      mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel); @@ -1579,13 +1596,36 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_      return TRUE;  } -void LLImageGL::syncToMainThread() +void update_free_vram() +{ +    LL_PROFILE_ZONE_SCOPED; + +    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; +    } +} + +void LLImageGL::syncToMainThread(LLGLuint new_tex_name)  { +    LL_PROFILE_ZONE_SCOPED;      {          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( @@ -1615,17 +1655,27 @@ void LLImageGL::syncToMainThread()          [=]()          {              LL_PROFILE_ZONE_NAMED("cglt - delete callback"); -            if (mNewTexName != 0) +            if (new_tex_name != 0)              {                  if (mTexName != 0)                  {                      LLImageGL::deleteTextures(1, &mTexName);                  } -                mTexName = mNewTexName; -                mNewTexName = 0; +                mTexName = new_tex_name;                  unref();              }          }); + + +    //update free vram periodically +    static LLFrameTimer timer; +     +    if (timer.getElapsedTimeF32() > 1.f) //call this once per second. +    { +        update_free_vram(); +        timer.reset(); +    } +      }  BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const @@ -1756,14 +1806,6 @@ void LLImageGL::destroyGLTexture()  		mTexName = 0;		  		mGLTextureCreated = FALSE ;  	} - -    // clean up any in-flight name change -    if (0 != mNewTexName) -    { -        // Memory is transient, not tracked by sGlobalTextuerMemory -        LLImageGL::deleteTextures(1, &mNewTexName); -        mNewTexName = 0; -    }  }  //force to invalidate the gl texture, most likely a sculpty texture @@ -2306,6 +2348,8 @@ void LLImageGL::checkActiveThread()  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL,  nummips);  */   +std::atomic<S32> LLImageGLThread::sFreeVRAMMegabytes; +  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() @@ -2332,3 +2376,14 @@ void LLImageGLThread::run()      gGL.shutdown();      mWindow->destroySharedContext(mContext);  } + +S32 LLImageGLThread::getFreeVRAMMegabytes() +{ +    if (!sEnabled) +    { +        update_free_vram(); +    } + +    return sFreeVRAMMegabytes; +} + diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 6c6e327e42..50706890f9 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -110,17 +110,17 @@ public:  	BOOL createGLTexture() ;  	BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, -		S32 category = sMaxCategories-1, bool defer_copy = false); -	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0, bool defer_copy = false); +		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 use_new_name = 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 use_new_name = 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(); +    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; @@ -224,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; @@ -324,6 +324,9 @@ public:      // follows gSavedSettings "RenderGLMultiThreaded"      static bool sEnabled; +    // free video memory in megabytes +    static std::atomic<S32> sFreeVRAMMegabytes; +      LLImageGLThread(LLWindow* window);      // post a function to be executed on the LLImageGL background thread @@ -335,6 +338,8 @@ public:      void run() override; +    static S32 getFreeVRAMMegabytes(); +  private:      LLWindow* mWindow;      void* mContext = nullptr; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 8c792daac0..5ce51bb43e 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -3564,6 +3564,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/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 471b0e2c48..20287a7777 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; @@ -761,6 +763,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 +913,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,10 +1044,7 @@ 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());  			}  		} @@ -1166,108 +1164,161 @@ 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); + +                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 +                { +                    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(); +                bump_ptr->ref(); +                dst_ptr->ref(); -					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 = [bump_ptr, dst_ptr]() +                { +                    LL_PROFILE_ZONE_NAMED("bil - create texture deferred"); +                    bump_ptr->createGLTexture(0, dst_ptr); +                }; -					LLVector2 v((F32) bump->getWidth()/gPipeline.mScreen.getWidth(), -								(F32) bump->getHeight()/gPipeline.mScreen.getHeight()); +                auto gen_normal_map = [bump_ptr, dst_ptr]() +                { +                    LL_PROFILE_ZONE_NAMED("bil - generate normal map"); +                    gPipeline.mScreen.bindTarget(); -					gGL.getTexUnit(0)->bind(bump); -					 -					S32 width = bump->getWidth(); -					S32 height = bump->getHeight(); +                    LLGLDepthTest depth(GL_FALSE); +                    LLGLDisable cull(GL_CULL_FACE); +                    LLGLDisable blend(GL_BLEND); +                    gGL.setColorMask(TRUE, TRUE); +                    gNormalMapGenProgram.bind(); -					S32 screen_width = gPipeline.mScreen.getWidth(); -					S32 screen_height = gPipeline.mScreen.getHeight(); +                    static LLStaticHashedString sNormScale("norm_scale"); +                    static LLStaticHashedString sStepX("stepX"); +                    static LLStaticHashedString sStepY("stepY"); -					glViewport(0, 0, screen_width, screen_height); +                    gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); +                    gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth()); +                    gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->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; +                    LLVector2 v((F32)bump_ptr->getWidth() / gPipeline.mScreen.getWidth(), +                        (F32)bump_ptr->getHeight() / gPipeline.mScreen.getHeight()); -						for (S32 bottom = 0; bottom < height; bottom += screen_height) -						{ -							S32 top = bottom+screen_height; -							top = llmin(top, height); +                    gGL.getTexUnit(0)->bind(bump_ptr); -							F32 bottom_tc = (F32) bottom/height; -							F32 top_tc = (F32)(bottom+screen_height)/height; -							top_tc = llmin(top_tc, 1.f); +                    S32 width = bump_ptr->getWidth(); +                    S32 height = bump_ptr->getHeight(); -							F32 screen_right = (F32) (right-left)/screen_width; -							F32 screen_top = (F32) (top-bottom)/screen_height; +                    S32 screen_width = gPipeline.mScreen.getWidth(); +                    S32 screen_height = gPipeline.mScreen.getHeight(); -							gGL.begin(LLRender::TRIANGLE_STRIP); -							gGL.texCoord2f(left_tc, bottom_tc); -							gGL.vertex2f(0, 0); +                    glViewport(0, 0, screen_width, screen_height); -							gGL.texCoord2f(left_tc, top_tc); -							gGL.vertex2f(0, screen_top); +                    for (S32 left = 0; left < width; left += screen_width) +                    { +                        S32 right = left + screen_width; +                        right = llmin(right, width); -							gGL.texCoord2f(right_tc, bottom_tc); -							gGL.vertex2f(screen_right, 0); +                        F32 left_tc = (F32)left / width; +                        F32 right_tc = (F32)right / width; -							gGL.texCoord2f(right_tc, top_tc); -							gGL.vertex2f(screen_right, screen_top); +                        for (S32 bottom = 0; bottom < height; bottom += screen_height) +                        { +                            S32 top = bottom + screen_height; +                            top = llmin(top, height); -							gGL.end(); +                            F32 bottom_tc = (F32)bottom / height; +                            F32 top_tc = (F32)(bottom + screen_height) / height; +                            top_tc = llmin(top_tc, 1.f); -							gGL.flush(); +                            F32 screen_right = (F32)(right - left) / screen_width; +                            F32 screen_top = (F32)(top - bottom) / screen_height; -							S32 w = right-left; -							S32 h = top-bottom; +                            gGL.begin(LLRender::TRIANGLE_STRIP); +                            gGL.texCoord2f(left_tc, bottom_tc); +                            gGL.vertex2f(0, 0); -							glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h); -						} -					} +                            gGL.texCoord2f(left_tc, top_tc); +                            gGL.vertex2f(0, screen_top); -					glGenerateMipmap(GL_TEXTURE_2D); +                            gGL.texCoord2f(right_tc, bottom_tc); +                            gGL.vertex2f(screen_right, 0); -					gPipeline.mScreen.flush(); +                            gGL.texCoord2f(right_tc, top_tc); +                            gGL.vertex2f(screen_right, screen_top); -					gNormalMapGenProgram.unbind(); -										 -					//generateNormalMapFromAlpha(dst_image, nrm_image); -				} +                            gGL.end(); + +                            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); + +                    bump_ptr->unref(); +                    dst_ptr->unref(); +                }; + +                auto main_queue = LLImageGLThread::sEnabled ? sMainQueue.lock() : nullptr; + +                if (main_queue) +                { //dispatch creation to background thread +                    LLImageRaw* dst_ptr = dst_image; +                    LLViewerTexture* bump_ptr = bump; +                    dst_ptr->ref(); +                    bump_ptr->ref(); + +                    main_queue->postTo(sTexUpdateQueue, create_texture, gen_normal_map); +                } +                else +                { +                    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/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index b5d3dc5d30..4fc1bdbec3 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(); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index bd60b9f1e2..42bd5d8367 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2986,11 +2986,12 @@ void LLViewerMediaImpl::doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* da      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 -    media_tex->createGLTexture(0, raw, 0, TRUE, LLGLTexture::OTHER, true); +    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, sync); -    media_tex->getGLTexture()->syncToMainThread(); +    media_tex->setSubImage(data, data_width, data_height, x_pos, y_pos, width, height, tex_name); +    media_tex->getGLTexture()->syncToMainThread(tex_name);      // release the data pointer before freeing raw so LLImageRaw destructor doesn't      // free memory at data pointer diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index 3cdef0ebff..65e9fa533d 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -787,42 +787,73 @@ void LLViewerOctreeGroup::checkStates()  //occulsion culling functions and classes  //-------------------------------------------------------------------------------------------  std::set<U32> LLOcclusionCullingGroup::sPendingQueries; -class LLOcclusionQueryPool : public LLGLNamePool + +static std::queue<GLuint> sFreeQueries; + +U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName()  { -public: -	LLOcclusionQueryPool() -	{ -	} +    LL_PROFILE_ZONE_SCOPED; +    // TODO: refactor this to a general purpose name pool +    static GLuint occlusion_queries[2][1024]; +    static std::atomic<S32> query_count[2]; +    static S32 query_page = -1; +     +    //reuse any query names that have been freed  +    if (!sFreeQueries.empty()) +    { +        GLuint ret = sFreeQueries.front(); +        sFreeQueries.pop(); +        return ret; +    } -protected: +    // first call, immediately fill entire name pool +    if (query_page == -1) +    { +        glGenQueriesARB(1024, occlusion_queries[0]); +        glGenQueriesARB(1024, occlusion_queries[1]); +        query_page = 0; +        query_count[0] = 1024; +        query_count[1] = 1024; +    } -	virtual GLuint allocateName() -	{ -		GLuint ret = 0; +    if (query_count[query_page] == 0) //this page is empty +    { +        //check the other page +        query_page = (query_page + 1) % 2; -		glGenQueriesARB(1, &ret); -	 -		return ret; -	} +        if (query_count[query_page] == 0) +        { +            //the other page is also empty, generate immediately and return +            GLuint ret; +            glGenQueriesARB(1, &ret); +            return ret; +        } +    } -	virtual void releaseName(GLuint name) -	{ -#if LL_TRACK_PENDING_OCCLUSION_QUERIES -		LLOcclusionCullingGroup::sPendingQueries.erase(name); -#endif -		glDeleteQueriesARB(1, &name); -	} -}; +    GLuint ret = occlusion_queries[query_page][--query_count[query_page]]; -static LLOcclusionQueryPool sQueryPool; -U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName() -{ -	return sQueryPool.allocate(); +    if (query_count[query_page] == 0) +    { //exhausted this page, replenish on background thread +        S32 page = query_page; +        LL::WorkQueue::postMaybe(LL::WorkQueue::getInstance("LLImageGL"), +            [=]() +            { +                LL_PROFILE_ZONE_NAMED("glGenQueries bg"); +                if (query_count[page] == 0) // <-- protect against redundant attempts to replenish +                { +                    glGenQueriesARB(1024, occlusion_queries[page]); +                    query_count[page] = 1024; +                    glFlush(); +                } +            }); +    } + +    return ret;  }  void LLOcclusionCullingGroup::releaseOcclusionQueryObjectName(GLuint name)  { -	sQueryPool.release(name); +    sFreeQueries.push(name);  }  //===================================== @@ -1243,7 +1274,10 @@ 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"); +                            glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); +                        }  						LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;  						llassert(shader); @@ -1282,7 +1316,10 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh  							}  						} -						glEndQueryARB(mode); +                        { +                            LL_PROFILE_ZONE_NAMED("glEndQuery"); +                            glEndQueryARB(mode); +                        }  					}  				} diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 5fed46f437..fa2c070ea0 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; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 8d45e64bf8..ac242c2bf7 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7267,11 +7267,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;  | 
