diff options
Diffstat (limited to 'indra/llrender')
| -rw-r--r-- | indra/llrender/llfontfreetype.cpp | 2 | ||||
| -rw-r--r-- | indra/llrender/llgl.cpp | 168 | ||||
| -rw-r--r-- | indra/llrender/llgl.h | 17 | ||||
| -rw-r--r-- | indra/llrender/llglheaders.h | 10 | ||||
| -rw-r--r-- | indra/llrender/llimagegl.cpp | 16 | ||||
| -rw-r--r-- | indra/llrender/llrender.cpp | 3 | ||||
| -rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 303 | ||||
| -rw-r--r-- | indra/llrender/llvertexbuffer.h | 33 | 
8 files changed, 392 insertions, 160 deletions
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index b84e696e2d..91c8a37022 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -482,7 +482,7 @@ void LLFontFreetype::renderGlyph(U32 glyph_index) const  	if (mFTFace == NULL)  		return; -	int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_DEFAULT ); +	int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT );  	llassert(!error);  	error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode); diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index c0edd92bc1..b1a4051e96 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -57,9 +57,12 @@  BOOL gDebugSession = FALSE;  BOOL gDebugGL = FALSE;  BOOL gClothRipple = FALSE; -BOOL gNoRender = FALSE; +BOOL gHeadlessClient = FALSE;  BOOL gGLActive = FALSE; +static const std::string HEADLESS_VENDOR_STRING("Linden Lab"); +static const std::string HEADLESS_RENDERER_STRING("Headless"); +static const std::string HEADLESS_VERSION_STRING("1.0");  std::ofstream gFailLog; @@ -102,7 +105,6 @@ LLMatrix4 gGLObliqueProjectionInverse;  #define LL_GL_NAME_POOLING 0 -LLGLNamePool::pool_list_t LLGLNamePool::sInstances;  std::list<LLGLUpdate*> LLGLUpdate::sGLQ;  #if (LL_WINDOWS || LL_LINUX || LL_SOLARIS)  && !LL_MESA_HEADLESS @@ -538,9 +540,19 @@ void LLGLManager::setToDebugGPU()  void LLGLManager::getGLInfo(LLSD& info)  { -	info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR)); -	info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER)); -	info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION)); +	if (gHeadlessClient) +	{ +		info["GLInfo"]["GLVendor"] = HEADLESS_VENDOR_STRING; +		info["GLInfo"]["GLRenderer"] = HEADLESS_RENDERER_STRING; +		info["GLInfo"]["GLVersion"] = HEADLESS_VERSION_STRING; +		return; +	} +	else +	{ +		info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR)); +		info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER)); +		info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION)); +	}  #if !LL_MESA_HEADLESS  	std::string all_exts = ll_safe_string((const char *)gGLHExts.mSysExts); @@ -556,14 +568,22 @@ void LLGLManager::getGLInfo(LLSD& info)  std::string LLGLManager::getGLInfoString()  {  	std::string info_str; -	std::string all_exts, line; -	info_str += std::string("GL_VENDOR      ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n"); -	info_str += std::string("GL_RENDERER    ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n"); -	info_str += std::string("GL_VERSION     ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n"); +	if (gHeadlessClient) +	{ +		info_str += std::string("GL_VENDOR      ") + HEADLESS_VENDOR_STRING + std::string("\n"); +		info_str += std::string("GL_RENDERER    ") + HEADLESS_RENDERER_STRING + std::string("\n"); +		info_str += std::string("GL_VERSION     ") + HEADLESS_VERSION_STRING + std::string("\n"); +	} +	else +	{ +		info_str += std::string("GL_VENDOR      ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n"); +		info_str += std::string("GL_RENDERER    ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n"); +		info_str += std::string("GL_VERSION     ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n"); +	}  #if !LL_MESA_HEADLESS  -	all_exts = (const char *)gGLHExts.mSysExts; +	std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts));  	LLStringUtil::replaceChar(all_exts, ' ', '\n');  	info_str += std::string("GL_EXTENSIONS:\n") + all_exts + std::string("\n");  #endif @@ -573,15 +593,21 @@ std::string LLGLManager::getGLInfoString()  void LLGLManager::printGLInfoString()  { -	std::string info_str; -	std::string all_exts, line; -	 -	LL_INFOS("RenderInit") << "GL_VENDOR:     " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL; -	LL_INFOS("RenderInit") << "GL_RENDERER:   " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL; -	LL_INFOS("RenderInit") << "GL_VERSION:    " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL; +	if (gHeadlessClient) +	{ +		LL_INFOS("RenderInit") << "GL_VENDOR:     " << HEADLESS_VENDOR_STRING << LL_ENDL; +		LL_INFOS("RenderInit") << "GL_RENDERER:   " << HEADLESS_RENDERER_STRING << LL_ENDL; +		LL_INFOS("RenderInit") << "GL_VERSION:    " << HEADLESS_VERSION_STRING << LL_ENDL; +	} +	else +	{ +		LL_INFOS("RenderInit") << "GL_VENDOR:     " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL; +		LL_INFOS("RenderInit") << "GL_RENDERER:   " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL; +		LL_INFOS("RenderInit") << "GL_VERSION:    " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL; +	}  #if !LL_MESA_HEADLESS -	all_exts = std::string(gGLHExts.mSysExts); +	std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts));  	LLStringUtil::replaceChar(all_exts, ' ', '\n');  	LL_DEBUGS("RenderInit") << "GL_EXTENSIONS:\n" << all_exts << LL_ENDL;  #endif @@ -590,7 +616,14 @@ void LLGLManager::printGLInfoString()  std::string LLGLManager::getRawGLString()  {  	std::string gl_string; -	gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER)); +	if (gHeadlessClient) +	{ +		gl_string = HEADLESS_VENDOR_STRING + " " + HEADLESS_RENDERER_STRING; +	} +	else +	{ +		gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER)); +	}  	return gl_string;  } @@ -610,46 +643,51 @@ void LLGLManager::shutdownGL()  void LLGLManager::initExtensions()  {  #if LL_MESA_HEADLESS -# if GL_ARB_multitexture +# ifdef GL_ARB_multitexture  	mHasMultitexture = TRUE;  # else  	mHasMultitexture = FALSE; -# endif -# if GL_ARB_texture_env_combine +# endif // GL_ARB_multitexture +# ifdef GL_ARB_texture_env_combine  	mHasARBEnvCombine = TRUE;	  # else  	mHasARBEnvCombine = FALSE; -# endif -# if GL_ARB_texture_compression +# endif // GL_ARB_texture_env_combine +# ifdef GL_ARB_texture_compression  	mHasCompressedTextures = TRUE;  # else  	mHasCompressedTextures = FALSE; -# endif -# if GL_ARB_vertex_buffer_object +# endif // GL_ARB_texture_compression +# ifdef GL_ARB_vertex_buffer_object  	mHasVertexBufferObject = TRUE;  # else  	mHasVertexBufferObject = FALSE; -# endif -# if GL_EXT_framebuffer_object +# endif // GL_ARB_vertex_buffer_object +# ifdef GL_EXT_framebuffer_object  	mHasFramebufferObject = TRUE;  # else  	mHasFramebufferObject = FALSE; -# endif -# if GL_EXT_framebuffer_multisample +# endif // GL_EXT_framebuffer_object +# ifdef GL_EXT_framebuffer_multisample  	mHasFramebufferMultisample = TRUE;  # else  	mHasFramebufferMultisample = FALSE; -# endif -# if GL_ARB_draw_buffers +# endif // GL_EXT_framebuffer_multisample +# ifdef GL_ARB_draw_buffers  	mHasDrawBuffers = TRUE;  #else  	mHasDrawBuffers = FALSE; -# endif +# endif // GL_ARB_draw_buffers +# if defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp) +	mHasDepthClamp = TRUE; +#else +	mHasDepthClamp = FALSE; +#endif // defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)  # if GL_EXT_blend_func_separate  	mHasBlendFuncSeparate = TRUE;  #else  	mHasBlendFuncSeparate = FALSE; -# endif +# endif // GL_EXT_blend_func_separate  	mHasMipMapGeneration = FALSE;  	mHasSeparateSpecularColor = FALSE;  	mHasAnisotropic = FALSE; @@ -671,6 +709,7 @@ void LLGLManager::initExtensions()  	mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression");  	mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);  	mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts); +	mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);  	// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad  	mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts)  		&& ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); @@ -694,6 +733,7 @@ void LLGLManager::initExtensions()  	if (getenv("LL_GL_NOEXT"))  	{  		//mHasMultitexture = FALSE; // NEEDED! +		mHasDepthClamp = FALSE;  		mHasARBEnvCombine = FALSE;  		mHasCompressedTextures = FALSE;  		mHasVertexBufferObject = FALSE; @@ -755,6 +795,7 @@ void LLGLManager::initExtensions()  		if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE;  		if (strchr(blacklist,'t')) mHasTextureRectangle = FALSE;  		if (strchr(blacklist,'u')) mHasBlendFuncSeparate = FALSE;//S +		if (strchr(blacklist,'v')) mHasDepthClamp = FALSE;  	}  #endif // LL_LINUX || LL_SOLARIS @@ -1047,6 +1088,33 @@ void flush_glerror()  	glGetError();  } +//this function outputs gl error to the log file, does not crash the code. +void log_glerror() +{ +	if (LL_UNLIKELY(!gGLManager.mInited)) +	{ +		return ; +	} +	//  Create or update texture to be used with this data  +	GLenum error; +	error = glGetError(); +	while (LL_UNLIKELY(error)) +	{ +		GLubyte const * gl_error_msg = gluErrorString(error); +		if (NULL != gl_error_msg) +		{ +			llwarns << "GL Error: " << error << " GL Error String: " << gl_error_msg << llendl ;			 +		} +		else +		{ +			// gluErrorString returns NULL for some extensions' error codes. +			// you'll probably have to grep for the number in glext.h. +			llwarns << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << llendl; +		} +		error = glGetError(); +	} +} +  void do_assert_glerror()  {  	if (LL_UNLIKELY(!gGLManager.mInited)) @@ -1110,7 +1178,7 @@ void assert_glerror()  		}  	} -	if (!gNoRender && gDebugGL)  +	if (gDebugGL)   	{  		do_assert_glerror();  	} @@ -1851,22 +1919,8 @@ LLGLNamePool::LLGLNamePool()  {  } -void LLGLNamePool::registerPool(LLGLNamePool* pool) -{ -	pool_list_t::iterator iter = std::find(sInstances.begin(), sInstances.end(), pool); -	if (iter == sInstances.end()) -	{ -		sInstances.push_back(pool); -	} -} -  LLGLNamePool::~LLGLNamePool()  { -	pool_list_t::iterator iter = std::find(sInstances.begin(), sInstances.end(), this); -	if (iter != sInstances.end()) -	{ -		sInstances.erase(iter); -	}  }  void LLGLNamePool::upkeep() @@ -1935,20 +1989,22 @@ void LLGLNamePool::release(GLuint name)  void LLGLNamePool::upkeepPools()  {  	LLMemType mt(LLMemType::MTYPE_UPKEEP_POOLS); -	for (pool_list_t::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) +	tracker_t::LLInstanceTrackerScopedGuard guard; +	for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)  	{ -		LLGLNamePool* pool = *iter; -		pool->upkeep(); +		LLGLNamePool & pool = *iter; +		pool.upkeep();  	}  }  //static  void LLGLNamePool::cleanupPools()  { -	for (pool_list_t::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) +	tracker_t::LLInstanceTrackerScopedGuard guard; +	for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)  	{ -		LLGLNamePool* pool = *iter; -		pool->cleanup(); +		LLGLNamePool & pool = *iter; +		pool.cleanup();  	}  } @@ -2037,7 +2093,7 @@ void LLGLDepthTest::checkState()  	}  } -LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P) +LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P)  {  	for (U32 i = 0; i < 4; i++)  	{ @@ -2050,7 +2106,7 @@ LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P)  	glMatrixMode(GL_MODELVIEW);  } -LLGLClampToFarClip::~LLGLClampToFarClip() +LLGLSquashToFarClip::~LLGLSquashToFarClip()  {  	glMatrixMode(GL_PROJECTION);  	glPopMatrix(); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 5e8965c06a..51b0a1e45f 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -40,6 +40,7 @@  #include "v4math.h"  #include "llplane.h"  #include "llgltypes.h" +#include "llinstancetracker.h"  #include "llglheaders.h"  #include "glh/glh_linear.h" @@ -92,6 +93,7 @@ public:  	BOOL mHasOcclusionQuery;  	BOOL mHasPointParameters;  	BOOL mHasDrawBuffers; +	BOOL mHasDepthClamp;  	BOOL mHasTextureRectangle;  	// Other extensions. @@ -157,6 +159,7 @@ void rotate_quat(LLQuaternion& rotation);  void flush_glerror(); // Flush GL errors when we know we're handling them correctly. +void log_glerror();  void assert_glerror();  void clear_glerror(); @@ -315,20 +318,22 @@ private:    leaves this class.    Does not stack.  */ -class LLGLClampToFarClip +class LLGLSquashToFarClip  {  public: -	LLGLClampToFarClip(glh::matrix4f projection); -	~LLGLClampToFarClip(); +	LLGLSquashToFarClip(glh::matrix4f projection); +	~LLGLSquashToFarClip();  };  /*  	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 +class LLGLNamePool : public LLInstanceTracker<LLGLNamePool>  {  public: +	typedef LLInstanceTracker<LLGLNamePool> tracker_t; +  	struct NameEntry  	{  		GLuint name; @@ -355,13 +360,11 @@ public:  	GLuint allocate();  	void release(GLuint name); -	static void registerPool(LLGLNamePool* pool);  	static void upkeepPools();  	static void cleanupPools();  protected:  	typedef std::vector<LLGLNamePool*> pool_list_t; -	static pool_list_t sInstances;  	virtual GLuint allocateName() = 0;  	virtual void releaseName(GLuint name) = 0; @@ -413,7 +416,7 @@ void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals  void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );  extern BOOL gClothRipple; -extern BOOL gNoRender; +extern BOOL gHeadlessClient;  extern BOOL gGLActive;  #endif // LL_LLGL_H diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 5a34b46d0c..576969b81a 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -829,5 +829,15 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);  #endif // LL_MESA / LL_WINDOWS / LL_DARWIN +// Even when GL_ARB_depth_clamp is available in the driver, the (correct) +// headers, and therefore GL_DEPTH_CLAMP might not be defined. +// In that case GL_DEPTH_CLAMP_NV should be defined, but why not just +// use the known numeric. +// +// To avoid #ifdef's in the code. Just define this here. +#ifndef GL_DEPTH_CLAMP +// Probably (still) called GL_DEPTH_CLAMP_NV. +#define GL_DEPTH_CLAMP 0x864F +#endif  #endif // LL_LLGLHEADERS_H diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 72dd283bc7..d4ffd6f88e 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -967,12 +967,14 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3  	}  	if (mTexName == 0)  	{ -		llwarns << "Setting subimage on image without GL texture" << llendl; +		// *TODO: Re-enable warning?  Ran into thread locking issues? DK 2011-02-18 +		//llwarns << "Setting subimage on image without GL texture" << llendl;  		return FALSE;  	}  	if (datap == NULL)  	{ -		llwarns << "Setting subimage on image with NULL datap" << llendl; +		// *TODO: Re-enable warning?  Ran into thread locking issues? DK 2011-02-18 +		//llwarns << "Setting subimage on image with NULL datap" << llendl;  		return FALSE;  	} @@ -1063,14 +1065,6 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_  {  	if (gGL.getTexUnit(0)->bind(this, false, true))  	{ -		if(gGLManager.mDebugGPU) -		{ -			llinfos << "Calling glCopyTexSubImage2D(...)" << llendl ; -			checkTexSize(true) ; -			llcallstacks << fb_x << " : " << fb_y << " : " << x_pos << " : " << y_pos << " : " << width << " : " << height << -				" : " << (S32)mComponents << llcallstacksendl ; -		} -  		glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);  		mGLTextureCreated = true;  		stop_glerror(); @@ -1108,6 +1102,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt  //the texture is assiciate with some image by calling glTexImage outside LLImageGL  BOOL LLImageGL::createGLTexture()  { +	if (gHeadlessClient) return FALSE;  	if (gGLManager.mIsDisabled)  	{  		llwarns << "Trying to create a texture while GL is disabled!" << llendl; @@ -1136,6 +1131,7 @@ BOOL LLImageGL::createGLTexture()  BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)  { +	if (gHeadlessClient) return FALSE;  	if (gGLManager.mIsDisabled)  	{  		llwarns << "Trying to create a texture while GL is disabled!" << llendl; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index e26acd53a3..8eb160f4e7 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -431,6 +431,9 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio  			if (gGL.mMaxAnisotropy < 1.f)  			{  				glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGL.mMaxAnisotropy); + +				llinfos << "gGL.mMaxAnisotropy: " << gGL.mMaxAnisotropy << llendl ; +				gGL.mMaxAnisotropy = llmax(1.f, gGL.mMaxAnisotropy) ;  			}  			glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, gGL.mMaxAnisotropy);  		} diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index de4501dd0f..1a5a4f734d 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -27,7 +27,7 @@  #include "linden_common.h"  #include <boost/static_assert.hpp> - +#include "llsys.h"  #include "llvertexbuffer.h"  // #include "llrender.h"  #include "llglheaders.h" @@ -47,6 +47,7 @@ U32 LLVertexBuffer::sSetCount = 0;  S32 LLVertexBuffer::sCount = 0;  S32 LLVertexBuffer::sGLCount = 0;  S32 LLVertexBuffer::sMappedCount = 0; +BOOL LLVertexBuffer::sDisableVBOMapping = FALSE ;  BOOL LLVertexBuffer::sEnableVBOs = TRUE;  U32 LLVertexBuffer::sGLRenderBuffer = 0;  U32 LLVertexBuffer::sGLRenderIndices = 0; @@ -251,6 +252,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi  void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const  {  	llassert(mRequestedNumIndices >= 0); +  	if (indices_offset >= (U32) mRequestedNumIndices ||  	    indices_offset + count > (U32) mRequestedNumIndices)  	{ @@ -282,6 +284,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const  void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const  {  	llassert(mRequestedNumVerts >= 0); +  	if (first >= (U32) mRequestedNumVerts ||  	    first + count > (U32) mRequestedNumVerts)  	{ @@ -305,13 +308,21 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const  }  //static -void LLVertexBuffer::initClass(bool use_vbo) +void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)  { -	sEnableVBOs = use_vbo; -	LLGLNamePool::registerPool(&sDynamicVBOPool); -	LLGLNamePool::registerPool(&sDynamicIBOPool); -	LLGLNamePool::registerPool(&sStreamVBOPool); -	LLGLNamePool::registerPool(&sStreamIBOPool); +	sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject ; +	if(sEnableVBOs) +	{ +		//llassert_always(glBindBufferARB) ; //double check the extention for VBO is loaded. + +		llinfos << "VBO is enabled." << llendl ; +	} +	else +	{ +		llinfos << "VBO is disabled." << llendl ; +	} + +	sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ;  }  //static  @@ -364,7 +375,9 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :  	mGLBuffer(0),  	mGLIndices(0),   	mMappedData(NULL), -	mMappedIndexData(NULL), mLocked(FALSE), +	mMappedIndexData(NULL),  +	mVertexLocked(FALSE), +	mIndexLocked(FALSE),  	mFinal(FALSE),  	mFilthy(FALSE),  	mEmpty(TRUE), @@ -422,6 +435,8 @@ LLVertexBuffer::~LLVertexBuffer()  	destroyGLBuffer();  	destroyGLIndices();  	sCount--; + +	llassert_always(!mMappedData && !mMappedIndexData) ;  };  //---------------------------------------------------------------------------- @@ -567,6 +582,8 @@ void LLVertexBuffer::destroyGLBuffer()  	{  		if (useVBOs())  		{ +			freeClientBuffer() ; +  			if (mMappedData || mMappedIndexData)  			{  				llerrs << "Vertex buffer destroyed while mapped!" << llendl; @@ -594,11 +611,13 @@ void LLVertexBuffer::destroyGLIndices()  	{  		if (useVBOs())  		{ +			freeClientBuffer() ; +  			if (mMappedData || mMappedIndexData)  			{  				llerrs << "Vertex buffer destroyed while mapped." << llendl;  			} -			releaseIndices(); +			releaseIndices();			  		}  		else  		{ @@ -799,6 +818,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)  	if (mResized && useVBOs())  	{ +		freeClientBuffer() ;  		setBuffer(0);  	}  } @@ -822,110 +842,239 @@ BOOL LLVertexBuffer::useVBOs() const  }  //---------------------------------------------------------------------------- +void LLVertexBuffer::freeClientBuffer() +{ +	if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData)) +	{ +		delete[] mMappedData ; +		delete[] mMappedIndexData ; +		mMappedData = NULL ; +		mMappedIndexData = NULL ; +	} +} + +void LLVertexBuffer::allocateClientVertexBuffer() +{ +	if(!mMappedData) +	{ +		U32 size = getSize() ; +		mMappedData = new U8[size]; +		memset(mMappedData, 0, size); +	} +} + +void LLVertexBuffer::allocateClientIndexBuffer() +{ +	if(!mMappedIndexData) +	{ +		U32 size = getIndicesSize(); +		mMappedIndexData = new U8[size]; +		memset(mMappedIndexData, 0, size); +	} +}  // Map for data access -U8* LLVertexBuffer::mapBuffer(S32 access) +U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 access)  {  	LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);  	if (mFinal)  	{ -		llerrs << "LLVertexBuffer::mapBuffer() called on a finalized buffer." << llendl; +		llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl;  	}  	if (!useVBOs() && !mMappedData && !mMappedIndexData)  	{ -		llerrs << "LLVertexBuffer::mapBuffer() called on unallocated buffer." << llendl; +		llerrs << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << llendl;  	} -	if (!mLocked && useVBOs()) +	if (!mVertexLocked && useVBOs())  	{  		{  			LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES); -			setBuffer(0); -			mLocked = TRUE; +			setBuffer(0, type); +			mVertexLocked = TRUE;  			stop_glerror();	 -			mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + +			if(sDisableVBOMapping) +			{ +				allocateClientVertexBuffer() ; +			} +			else +			{ +				mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); +			}  			stop_glerror();  		} +		 +		if (!mMappedData)  		{ -			LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES); -			mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); -			stop_glerror(); +			log_glerror(); + +			//check the availability of memory +			U32 avail_phy_mem, avail_vir_mem; +			LLMemoryInfo::getAvailableMemoryKB(avail_phy_mem, avail_vir_mem) ; +			llinfos << "Available physical mwmory(KB): " << avail_phy_mem << llendl ;  +			llinfos << "Available virtual memory(KB): " << avail_vir_mem << llendl; + +			if(!sDisableVBOMapping) +			{ +				//-------------------- +				//print out more debug info before crash +				llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ; +				GLint size ; +				glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ; +				llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ; +				//-------------------- + +				GLint buff; +				glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); +				if ((GLuint)buff != mGLBuffer) +				{ +					llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; +				} + +				 +				llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl; +			} +			else +			{ +				llerrs << "memory allocation for vertex data failed." << llendl ; +			}  		} +		sMappedCount++; +	} +	 +	return mMappedData; +} -		if (!mMappedData) +U8* LLVertexBuffer::mapIndexBuffer(S32 access) +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER); +	if (mFinal) +	{ +		llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl; +	} +	if (!useVBOs() && !mMappedData && !mMappedIndexData) +	{ +		llerrs << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << llendl; +	} + +	if (!mIndexLocked && useVBOs()) +	{  		{ -			//-------------------- -			//print out more debug info before crash -			llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ; -			GLint size ; -			glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ; -			llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ; -			//-------------------- +			LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES); -			GLint buff; -			glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); -			if ((GLuint)buff != mGLBuffer) +			setBuffer(0, TYPE_INDEX); +			mIndexLocked = TRUE; +			stop_glerror();	 + +			if(sDisableVBOMapping)  			{ -				llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; +				allocateClientIndexBuffer() ;  			} - -			 -			llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl; +			else +			{ +				mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); +			} +			stop_glerror();  		}  		if (!mMappedIndexData)  		{ -			GLint buff; -			glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); -			if ((GLuint)buff != mGLIndices) +			log_glerror(); + +			if(!sDisableVBOMapping)  			{ -				llerrs << "Invalid GL index buffer bound: " << buff << llendl; -			} +				GLint buff; +				glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); +				if ((GLuint)buff != mGLIndices) +				{ +					llerrs << "Invalid GL index buffer bound: " << buff << llendl; +				} -			llerrs << "glMapBuffer returned NULL (no index data)" << llendl; +				llerrs << "glMapBuffer returned NULL (no index data)" << llendl; +			} +			else +			{ +				llerrs << "memory allocation for Index data failed. " << llendl ; +			}  		}  		sMappedCount++;  	} -	 -	return mMappedData; + +	return mMappedIndexData ;  } -void LLVertexBuffer::unmapBuffer() +void LLVertexBuffer::unmapBuffer(S32 type)  {  	LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER); -	if (mMappedData || mMappedIndexData) +	if (!useVBOs()) +	{ +		return ; //nothing to unmap +	} + +	bool updated_all = false ; +	if (mMappedData && mVertexLocked && type != TYPE_INDEX)  	{ -		if (useVBOs() && mLocked) +		updated_all = (mIndexLocked && type < 0) ; //both vertex and index buffers done updating + +		if(sDisableVBOMapping) +		{ +			stop_glerror(); +			glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), mMappedData); +			stop_glerror(); +		} +		else  		{  			stop_glerror();  			glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);  			stop_glerror(); + +			mMappedData = NULL; +		} + +		mVertexLocked = FALSE ; +		sMappedCount--; +	} + +	if(mMappedIndexData && mIndexLocked && (type < 0 || type == TYPE_INDEX)) +	{ +		if(sDisableVBOMapping) +		{ +			stop_glerror(); +			glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), mMappedIndexData); +			stop_glerror(); +		} +		else +		{ +			stop_glerror();  			glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);  			stop_glerror(); -			/*if (!sMapped) -			{ -				llerrs << "Redundantly unmapped VBO!" << llendl; -			} -			sMapped = FALSE;*/ -			sMappedCount--; - -			if (mUsage == GL_STATIC_DRAW_ARB) -			{ //static draw buffers can only be mapped a single time -				//throw out client data (we won't be using it again) -				mEmpty = TRUE; -				mFinal = TRUE; -			} -			else +			mMappedIndexData = NULL ; +		} + +		mIndexLocked = FALSE ; +		sMappedCount--; +	} + +	if(updated_all) +	{ +		if(mUsage == GL_STATIC_DRAW_ARB) +		{ +			//static draw buffers can only be mapped a single time +			//throw out client data (we won't be using it again) +			mEmpty = TRUE; +			mFinal = TRUE; + +			if(sDisableVBOMapping)  			{ -				mEmpty = FALSE; +				freeClientBuffer() ;  			} - -			mMappedIndexData = NULL; -			mMappedData = NULL; -			 -			mLocked = FALSE; +		} +		else +		{ +			mEmpty = FALSE;  		}  	}  } @@ -939,15 +1088,16 @@ template <class T,S32 type> struct VertexBufferStrider  					strider_t& strider,   					S32 index)  	{ -		if (vbo.mapBuffer() == NULL) -		{ -			llwarns << "mapBuffer failed!" << llendl; -			return FALSE; -		} -  		if (type == LLVertexBuffer::TYPE_INDEX)  		{  			S32 stride = sizeof(T); + +			if (vbo.mapIndexBuffer() == NULL) +			{ +				llwarns << "mapIndexBuffer failed!" << llendl; +				return FALSE; +			} +  			strider = (T*)(vbo.getMappedIndices() + index*stride);  			strider.setStride(0);  			return TRUE; @@ -955,6 +1105,13 @@ template <class T,S32 type> struct VertexBufferStrider  		else if (vbo.hasDataType(type))  		{  			S32 stride = vbo.getStride(); + +			if (vbo.mapVertexBuffer(type) == NULL) +			{ +				llwarns << "mapVertexBuffer failed!" << llendl; +				return FALSE; +			} +  			strider = (T*)(vbo.getMappedData() + vbo.getOffset(type) + index*stride);  			strider.setStride(stride);  			return TRUE; @@ -1035,7 +1192,7 @@ void LLVertexBuffer::setStride(S32 type, S32 new_stride)  //----------------------------------------------------------------------------  // Set for rendering -void LLVertexBuffer::setBuffer(U32 data_mask) +void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)  {  	LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER);  	//set up pointers if the data mask is different ... @@ -1176,7 +1333,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)  		{  			ll_fail("LLVertexBuffer::mapBuffer failed");  		} -		unmapBuffer(); +		unmapBuffer(type);  	}  	else  	{		 diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 94fa790957..c51ce7ac4e 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -80,7 +80,7 @@ public:  	static BOOL	sUseStreamDraw; -	static void initClass(bool use_vbo); +	static void initClass(bool use_vbo, bool no_vbo_mapping);  	static void cleanupClass();  	static void setupClientArrays(U32 data_mask);   	static void clientCopy(F64 max_time = 0.005); //copy data from client to GL @@ -139,19 +139,24 @@ protected:  	void	updateNumVerts(S32 nverts);  	void	updateNumIndices(S32 nindices);   	virtual BOOL	useVBOs() const; -	void	unmapBuffer(); -		 +	void	unmapBuffer(S32 type); +	void freeClientBuffer() ; +	void allocateClientVertexBuffer() ; +	void allocateClientIndexBuffer() ; +  public:  	LLVertexBuffer(U32 typemask, S32 usage);  	// map for data access -	U8*		mapBuffer(S32 access = -1); +	U8*		mapVertexBuffer(S32 type = -1, S32 access = -1); +	U8*		mapIndexBuffer(S32 access = -1); +  	// set for rendering -	virtual void	setBuffer(U32 data_mask); 	// calls  setupVertexBuffer() if data_mask is not 0 +	virtual void	setBuffer(U32 data_mask, S32 type = -1); 	// calls  setupVertexBuffer() if data_mask is not 0  	// allocate buffer  	void	allocateBuffer(S32 nverts, S32 nindices, bool create);  	virtual void resizeBuffer(S32 newnverts, S32 newnindices); -		 +			  	// Only call each getVertexPointer, etc, once before calling unmapBuffer()  	// call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer()  	// example: @@ -170,7 +175,7 @@ public:  	bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0);  	BOOL isEmpty() const					{ return mEmpty; } -	BOOL isLocked() const					{ return mLocked; } +	BOOL isLocked() const					{ return mVertexLocked || mIndexLocked; }  	S32 getNumVerts() const					{ return mNumVerts; }  	S32 getNumIndices() const				{ return mNumIndices; }  	S32 getRequestedVerts() const			{ return mRequestedNumVerts; } @@ -209,13 +214,14 @@ protected:  	U32		mGLIndices;		// GL IBO handle  	U8*		mMappedData;	// pointer to currently mapped data (NULL if unmapped)  	U8*		mMappedIndexData;	// pointer to currently mapped indices (NULL if unmapped) -	BOOL	mLocked;			// if TRUE, buffer is being or has been written to in client memory +	BOOL	mVertexLocked;			// if TRUE, vertex buffer is being or has been written to in client memory +	BOOL	mIndexLocked;			// if TRUE, index buffer is being or has been written to in client memory  	BOOL	mFinal;			// if TRUE, buffer can not be mapped again  	BOOL	mFilthy;		// if TRUE, entire buffer must be copied (used to prevent redundant dirty flags) -	BOOL	mEmpty;			// if TRUE, client buffer is empty (or NULL). Old values have been discarded. -	S32		mOffsets[TYPE_MAX]; +	BOOL	mEmpty;			// if TRUE, client buffer is empty (or NULL). Old values have been discarded.	  	BOOL	mResized;		// if TRUE, client buffer has been resized and GL buffer has not  	BOOL	mDynamicSize;	// if TRUE, buffer has been resized at least once (and should be padded) +	S32		mOffsets[TYPE_MAX];  	class DirtyRegion  	{ @@ -240,13 +246,14 @@ public:  	static std::vector<U32> sDeleteList;  	typedef std::list<LLVertexBuffer*> buffer_list_t; +	static BOOL sDisableVBOMapping; //disable glMapBufferARB  	static BOOL sEnableVBOs; +	static BOOL sVBOActive; +	static BOOL sIBOActive;  	static S32 sTypeOffsets[TYPE_MAX];  	static U32 sGLMode[LLRender::NUM_MODES];  	static U32 sGLRenderBuffer; -	static U32 sGLRenderIndices; -	static BOOL sVBOActive; -	static BOOL sIBOActive; +	static U32 sGLRenderIndices;	  	static U32 sLastMask;  	static U32 sAllocatedBytes;  	static U32 sBindCount;  | 
