diff options
Diffstat (limited to 'indra/llrender')
-rw-r--r-- | indra/llrender/llcubemap.cpp | 2 | ||||
-rw-r--r-- | indra/llrender/llfontgl.cpp | 10 | ||||
-rw-r--r-- | indra/llrender/llfontgl.h | 2 | ||||
-rw-r--r-- | indra/llrender/llgl.cpp | 117 | ||||
-rw-r--r-- | indra/llrender/llgl.h | 29 | ||||
-rw-r--r-- | indra/llrender/llglheaders.h | 13 | ||||
-rw-r--r-- | indra/llrender/llglslshader.cpp | 11 | ||||
-rw-r--r-- | indra/llrender/llglslshader.h | 4 | ||||
-rw-r--r-- | indra/llrender/llimagegl.cpp | 330 | ||||
-rw-r--r-- | indra/llrender/llimagegl.h | 61 | ||||
-rw-r--r-- | indra/llrender/llrender.cpp | 34 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.cpp | 15 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.h | 1 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.cpp | 45 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.h | 3 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 321 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.h | 43 |
17 files changed, 673 insertions, 368 deletions
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 45a3b18179..362452d837 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -81,7 +81,7 @@ void LLCubeMap::initGL() { U32 texname = 0; - LLImageGL::generateTextures(1, &texname); + LLImageGL::generateTextures(LLTexUnit::TT_CUBE_MAP, GL_RGB8, 1, &texname); for (int i = 0; i < 6; i++) { diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index fccbf37a8d..4dc2fcd714 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -422,6 +422,16 @@ S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y } // font metrics - override for LLFontFreetype that returns units of virtual pixels +F32 LLFontGL::getAscenderHeight() const +{ + return mFontFreetype->getAscenderHeight() / sScaleY; +} + +F32 LLFontGL::getDescenderHeight() const +{ + return mFontFreetype->getDescenderHeight() / sScaleY; +} + S32 LLFontGL::getLineHeight() const { return llceil(mFontFreetype->getAscenderHeight() / sScaleY) + llceil(mFontFreetype->getDescenderHeight() / sScaleY); diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 74bdbb43e7..5ed5d2c4eb 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -115,6 +115,8 @@ public: S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const; // font metrics - override for LLFontFreetype that returns units of virtual pixels + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; S32 getLineHeight() const; S32 getWidth(const std::string& utf8text) const; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 197bc2b422..0b56b3889c 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -94,6 +94,10 @@ void APIENTRY gl_debug_callback(GLenum source, llwarns << "Severity: " << std::hex << severity << llendl; llwarns << "Message: " << message << llendl; llwarns << "-----------------------" << llendl; + if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) + { + llerrs << "Halting on GL Error" << llendl; + } } #endif @@ -245,6 +249,12 @@ PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL; PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL; PFNGLSAMPLEMASKIPROC glSampleMaski = NULL; +//transform feedback (4.0 core) +PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = NULL; +PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = NULL; +PFNGLBINDBUFFERRANGEPROC glBindBufferRange = NULL; + //GL_ARB_debug_output PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL; PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL; @@ -417,6 +427,7 @@ LLGLManager::LLGLManager() : mHasDrawBuffers(FALSE), mHasTextureRectangle(FALSE), mHasTextureMultisample(FALSE), + mHasTransformFeedback(FALSE), mMaxSampleMaskWords(0), mMaxColorTextureSamples(0), mMaxDepthTextureSamples(0), @@ -554,7 +565,8 @@ bool LLGLManager::initGL() parse_gl_version( &mDriverVersionMajor, &mDriverVersionMinor, &mDriverVersionRelease, - &mDriverVersionVendorString ); + &mDriverVersionVendorString, + &mGLVersionString); mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f; @@ -572,6 +584,15 @@ bool LLGLManager::initGL() #endif } + if (mGLVersion >= 2.1f && LLImageGL::sCompressTextures) + { //use texture compression + glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST); + } + else + { //GL version is < 3.0, always disable texture compression + LLImageGL::sCompressTextures = false; + } + // Trailing space necessary to keep "nVidia Corpor_ati_on" cards // from being recognized as ATI. if (mGLVendor.substr(0,4) == "ATI ") @@ -592,11 +613,8 @@ bool LLGLManager::initGL() #endif // LL_WINDOWS #if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS - // release 7277 is a point at which we verify that ATI OpenGL - // drivers get pretty stable with SL, ~Catalyst 8.2, - // for both Win32 and Linux. - if (mDriverVersionRelease < 7277 && - mDriverVersionRelease != 0) // 0 == Undetectable driver version - these get to pretend to be new ATI drivers, though that decision may be revisited. + // count any pre OpenGL 3.0 implementation as an old driver + if (mGLVersion < 3.f) { mATIOldDriver = TRUE; } @@ -735,6 +753,11 @@ bool LLGLManager::initGL() } #endif + if (mIsIntel && mGLVersion <= 3.f) + { //never try to use framebuffer objects on older intel drivers (crashy) + mHasFramebufferObject = FALSE; + } + if (mHasFramebufferObject) { glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples); @@ -923,7 +946,6 @@ void LLGLManager::initExtensions() mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); - mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap"); mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color"); mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic"); glh_init_extensions("GL_ARB_texture_cube_map"); @@ -948,11 +970,14 @@ void LLGLManager::initExtensions() ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); #endif + mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f; + mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts); mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts); + mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE; #if !LL_DARWIN mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); #endif @@ -1192,7 +1217,14 @@ void LLGLManager::initExtensions() glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample"); glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv"); glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski"); - } + } + if (mHasTransformFeedback) + { + glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glBeginTransformFeedback"); + glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback"); + glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings"); + glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange"); + } if (mHasDebugOutput) { glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB"); @@ -1897,7 +1929,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) glClientActiveTextureARB(GL_TEXTURE0_ARB); gGL.getTexUnit(0)->activate(); - if (gGLManager.mHasVertexShader) + if (gGLManager.mHasVertexShader && LLGLSLShader::sNoFixedFunction) { //make sure vertex attribs are all disabled GLint count; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &count); @@ -1949,6 +1981,7 @@ LLGLState::LLGLState(LLGLenum state, S32 enabled) : case GL_COLOR_MATERIAL: case GL_FOG: case GL_LINE_STIPPLE: + case GL_POLYGON_STIPPLE: mState = 0; break; } @@ -2037,7 +2070,7 @@ void LLGLManager::initGLStates() //////////////////////////////////////////////////////////////////////////////// -void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ) +void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string ) { // GL_VERSION returns a null-terminated string with the format: // <major>.<minor>[.<release>] [<vendor specific>] @@ -2053,6 +2086,8 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor return; } + version_string->assign(version); + std::string ver_copy( version ); S32 len = (S32)strlen( version ); /* Flawfinder: ignore */ S32 i = 0; @@ -2414,3 +2449,65 @@ LLGLSquashToFarClip::~LLGLSquashToFarClip() gGL.matrixMode(LLRender::MM_MODELVIEW); } + + +LLGLSyncFence::LLGLSyncFence() +{ +#ifdef GL_ARB_sync + mSync = 0; +#endif +} + +LLGLSyncFence::~LLGLSyncFence() +{ +#ifdef GL_ARB_sync + if (mSync) + { + glDeleteSync(mSync); + } +#endif +} + +void LLGLSyncFence::placeFence() +{ +#ifdef GL_ARB_sync + if (mSync) + { + glDeleteSync(mSync); + } + mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +#endif +} + +bool LLGLSyncFence::isCompleted() +{ + bool ret = true; +#ifdef GL_ARB_sync + if (mSync) + { + GLenum status = glClientWaitSync(mSync, 0, 1); + if (status == GL_TIMEOUT_EXPIRED) + { + ret = false; + } + } +#endif + return ret; +} + +void LLGLSyncFence::wait() +{ +#ifdef GL_ARB_sync + if (mSync) + { + while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) + { //track the number of times we've waited here + static S32 waits = 0; + waits++; + } + } +#endif +} + + + diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 5a33c98708..964495a3ab 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -104,6 +104,7 @@ public: BOOL mHasDepthClamp; BOOL mHasTextureRectangle; BOOL mHasTextureMultisample; + BOOL mHasTransformFeedback; S32 mMaxSampleMaskWords; S32 mMaxColorTextureSamples; S32 mMaxDepthTextureSamples; @@ -141,6 +142,7 @@ public: S32 mGLSLVersionMajor; S32 mGLSLVersionMinor; std::string mDriverVersionVendorString; + std::string mGLVersionString; S32 mVRAM; // VRAM in MB S32 mGLMaxVertexRange; @@ -417,13 +419,38 @@ public: virtual void updateGL() = 0; }; +const U32 FENCE_WAIT_TIME_NANOSECONDS = 1000; //1 ms + +class LLGLFence +{ +public: + virtual void placeFence() = 0; + virtual bool isCompleted() = 0; + virtual void wait() = 0; +}; + +class LLGLSyncFence : public LLGLFence +{ +public: +#ifdef GL_ARB_sync + GLsync mSync; +#endif + + LLGLSyncFence(); + virtual ~LLGLSyncFence(); + + void placeFence(); + bool isCompleted(); + void wait(); +}; + extern LLMatrix4 gGLObliqueProjectionInverse; #include "llglstates.h" void init_glstates(); -void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ); +void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string ); extern BOOL gClothRipple; extern BOOL gHeadlessClient; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index d61ec707f0..a0727b8686 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -528,6 +528,13 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; extern PFNGLSAMPLEMASKIPROC glSampleMaski; +//transform feedback (4.0 core) +extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; +extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; +extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; +extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; + + #elif LL_WINDOWS //---------------------------------------------------------------------------- // LL_WINDOWS @@ -759,6 +766,12 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; extern PFNGLSAMPLEMASKIPROC glSampleMaski; +//transform feedback (4.0 core) +extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; +extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; +extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; +extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; + //GL_ARB_debug_output extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB; extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 4b7e639aed..7cbf39096e 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -129,7 +129,9 @@ void LLGLSLShader::unload() } BOOL LLGLSLShader::createShader(vector<string> * attributes, - vector<string> * uniforms) + vector<string> * uniforms, + U32 varying_count, + const char** varyings) { //reloading, reset matrix hash values for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i) @@ -172,6 +174,13 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes, mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1); } +#ifdef GL_INTERLEAVED_ATTRIBS + if (varying_count > 0 && varyings) + { + glTransformFeedbackVaryings(mProgramObject, varying_count, varyings, GL_INTERLEAVED_ATTRIBS); + } +#endif + // Map attributes and uniforms if (success) { diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 7873fe3c4e..5c68cb46eb 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -76,7 +76,9 @@ public: void unload(); BOOL createShader(std::vector<std::string> * attributes, - std::vector<std::string> * uniforms); + std::vector<std::string> * uniforms, + U32 varying_count = 0, + const char** varyings = NULL); BOOL attachObject(std::string object); void attachObject(GLhandleARB object); void attachObjects(GLhandleARB* objects = NULL, S32 count = 0); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 78591ddd38..659d3ca409 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -42,8 +42,11 @@ //---------------------------------------------------------------------------- const F32 MIN_TEXTURE_LIFETIME = 10.f; +//which power of 2 is i? +//assumes i is a power of 2 > 0 +U32 wpo2(U32 i); + //statics -LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 }; U32 LLImageGL::sUniqueCount = 0; U32 LLImageGL::sBindCount = 0; @@ -51,12 +54,14 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes = 0; S32 LLImageGL::sBoundTextureMemoryInBytes = 0; S32 LLImageGL::sCurBoundTextureMemory = 0; S32 LLImageGL::sCount = 0; -std::list<U32> LLImageGL::sDeadTextureList; +LLImageGL::dead_texturelist_t LLImageGL::sDeadTextureList[LLTexUnit::TT_NONE]; +U32 LLImageGL::sCurTexName = 1; BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; F32 LLImageGL::sLastFrameTime = 0.f; BOOL LLImageGL::sAllowReadBackRaw = FALSE ; LLImageGL* LLImageGL::sDefaultGLTexture = NULL ; +bool LLImageGL::sCompressTextures = false; std::set<LLImageGL*> LLImageGL::sImageList; @@ -65,19 +70,10 @@ std::set<LLImageGL*> LLImageGL::sImageList; //**************************************************************************************************** //----------------------- //debug use -BOOL gAuditTexture = FALSE ; -#define MAX_TEXTURE_LOG_SIZE 22 //2048 * 2048 -std::vector<S32> LLImageGL::sTextureLoadedCounter(MAX_TEXTURE_LOG_SIZE + 1) ; -std::vector<S32> LLImageGL::sTextureBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ; -std::vector<S32> LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ; S32 LLImageGL::sCurTexSizeBar = -1 ; S32 LLImageGL::sCurTexPickSize = -1 ; -LLPointer<LLImageGL> LLImageGL::sHighlightTexturep = NULL; -S32 LLImageGL::sMaxCatagories = 1 ; +S32 LLImageGL::sMaxCategories = 1 ; -std::vector<S32> LLImageGL::sTextureMemByCategory; -std::vector<S32> LLImageGL::sTextureMemByCategoryBound ; -std::vector<S32> LLImageGL::sTextureCurMemByCategoryBound ; //------------------------ //**************************************************************************************************** //End for texture auditing use only @@ -175,49 +171,11 @@ BOOL is_little_endian() //static void LLImageGL::initClass(S32 num_catagories) { - sMaxCatagories = num_catagories ; - - sTextureMemByCategory.resize(sMaxCatagories); - sTextureMemByCategoryBound.resize(sMaxCatagories) ; - sTextureCurMemByCategoryBound.resize(sMaxCatagories) ; } //static void LLImageGL::cleanupClass() { - sTextureMemByCategory.clear() ; - sTextureMemByCategoryBound.clear() ; - sTextureCurMemByCategoryBound.clear() ; -} - -//static -void LLImageGL::setHighlightTexture(S32 category) -{ - const S32 dim = 128; - sHighlightTexturep = new LLImageGL() ; - LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3); - U8* data = image_raw->getData(); - for (S32 i = 0; i<dim; i++) - { - for (S32 j = 0; j<dim; j++) - { - const S32 border = 2; - if (i<border || j<border || i>=(dim-border) || j>=(dim-border)) - { - *data++ = 0xff; - *data++ = 0xff; - *data++ = 0xff; - } - else - { - *data++ = 0xff; - *data++ = 0xff; - *data++ = 0x00; - } - } - } - sHighlightTexturep->createGLTexture(0, image_raw, 0, TRUE, category); - image_raw = NULL; } //static @@ -285,31 +243,11 @@ void LLImageGL::updateStats(F32 current_time) sLastFrameTime = current_time; sBoundTextureMemoryInBytes = sCurBoundTextureMemory; sCurBoundTextureMemory = 0; - - if(gAuditTexture) - { - for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++) - { - sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ; - sTextureCurBoundCounter[i] = 0 ; - } - for(U32 i = 0 ; i < sTextureCurMemByCategoryBound.size() ; i++) - { - sTextureMemByCategoryBound[i] = sTextureCurMemByCategoryBound[i] ; - sTextureCurMemByCategoryBound[i] = 0 ; - } - } } //static S32 LLImageGL::updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) { - if(gAuditTexture && ncomponents > 0 && category > -1) - { - sTextureCurBoundCounter[getTextureCounterIndex(mem / ncomponents)]++ ; - sTextureCurMemByCategoryBound[category] += mem ; - } - LLImageGL::sCurBoundTextureMemory += mem ; return LLImageGL::sCurBoundTextureMemory; } @@ -477,10 +415,13 @@ void LLImageGL::init(BOOL usemipmaps) mDiscardLevelInAtlas = -1 ; mTexelsInAtlas = 0 ; mTexelsInGLTexture = 0 ; + + mAllowCompression = true; mTarget = GL_TEXTURE_2D; mBindTarget = LLTexUnit::TT_TEXTURE; mHasMipMaps = false; + mMipLevels = -1; mIsResident = 0; @@ -671,8 +612,24 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) is_compressed = true; } + + + if (mUseMipMaps) + { + //set has mip maps to true before binding image so tex parameters get set properly + gGL.getTexUnit(0)->unbind(mBindTarget); + mHasMipMaps = true; + mTexOptionsDirty = true; + setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); + } + else + { + mHasMipMaps = false; + } + llverify(gGL.getTexUnit(0)->bind(this)); + if (mUseMipMaps) { if (data_hasmips) @@ -685,6 +642,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) S32 w = getWidth(d); S32 h = getHeight(d); S32 gl_level = d-mCurrentDiscardLevel; + + mMipLevels = llmax(mMipLevels, gl_level); + if (d > mCurrentDiscardLevel) { data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment @@ -705,7 +665,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } - LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in); + LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in, mAllowCompression); if (gl_level == 0) { analyzeAlpha(data_in, w, h); @@ -727,10 +687,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { if (mAutoGenMips) { - if (!gGLManager.mHasFramebufferObject) - { - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE); - } stop_glerror(); { // LLFastTimer t2(FTM_TEMP4); @@ -744,10 +700,15 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) S32 w = getWidth(mCurrentDiscardLevel); S32 h = getHeight(mCurrentDiscardLevel); + mMipLevels = wpo2(llmax(w, h)); + + //use legacy mipmap generation mode + glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE); + LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, mFormatPrimary, mFormatType, - data_in); + data_in, mAllowCompression); analyzeAlpha(data_in, w, h); stop_glerror(); @@ -759,16 +720,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } } - - if (gGLManager.mHasFramebufferObject) - { - glGenerateMipmap(LLTexUnit::getInternalType(mBindTarget)); - } } else { // Create mips by hand - // about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800 // ~4x faster than gluBuild2DMipmaps S32 width = getWidth(mCurrentDiscardLevel); S32 height = getHeight(mCurrentDiscardLevel); @@ -778,6 +733,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) const U8* cur_mip_data = 0; S32 prev_mip_size = 0; S32 cur_mip_size = 0; + + mMipLevels = nummips; + for (int m=0; m<nummips; m++) { if (m==0) @@ -805,7 +763,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } - LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data); + LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression); if (m == 0) { analyzeAlpha(data_in, w, h); @@ -842,10 +800,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl; } - mHasMipMaps = true; } else { + mMipLevels = 0; S32 w = getWidth(); S32 h = getHeight(); if (is_compressed) @@ -863,7 +821,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, - mFormatPrimary, mFormatType, (GLvoid *)data_in); + mFormatPrimary, mFormatType, (GLvoid *)data_in, mAllowCompression); analyzeAlpha(data_in, w, h); updatePickMask(w, h, data_in); @@ -877,7 +835,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } } - mHasMipMaps = false; } stop_glerror(); mGLTextureCreated = true; @@ -1090,27 +1047,69 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_ } // static -void LLImageGL::generateTextures(S32 numTextures, U32 *textures) +void LLImageGL::generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures) { - glGenTextures(numTextures, (GLuint*)textures); + bool empty = true; + + dead_texturelist_t::iterator iter = sDeadTextureList[type].find(format); + + if (iter != sDeadTextureList[type].end()) + { + empty = iter->second.empty(); + } + + for (S32 i = 0; i < numTextures; ++i) + { + if (!empty) + { + textures[i] = iter->second.front(); + iter->second.pop_front(); + empty = iter->second.empty(); + } + else + { + textures[i] = sCurTexName++; + } + } } // static -void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate) +void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate) { - for (S32 i = 0; i < numTextures; i++) + if (gGLManager.mInited) { - sDeadTextureList.push_back(textures[i]); - } + if (format == 0 || type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1) + { //unknown internal format or unknown number of mip levels, not safe to reuse + glDeleteTextures(numTextures, textures); + } + else + { + for (S32 i = 0; i < numTextures; ++i) + { //remove texture from VRAM by setting its size to zero + for (S32 j = 0; j <= mip_levels; j++) + { + gGL.getTexUnit(0)->bindManual(type, textures[i]); - if (immediate) + glTexImage2D(LLTexUnit::getInternalType(type), j, format, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + + llassert(std::find(sDeadTextureList[type][format].begin(), + sDeadTextureList[type][format].end(), textures[i]) == + sDeadTextureList[type][format].end()); + + sDeadTextureList[type][format].push_back(textures[i]); + } + } + } + + /*if (immediate) { LLImageGL::deleteDeadTextures(); - } + }*/ } // static -void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels) +void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression) { bool use_scratch = false; U32* scratch = NULL; @@ -1173,6 +1172,36 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt } } + if (LLImageGL::sCompressTextures && allow_compression) + { + switch (intformat) + { + case GL_RGB: + case GL_RGB8: + intformat = GL_COMPRESSED_RGB; + break; + case GL_RGBA: + case GL_RGBA8: + intformat = GL_COMPRESSED_RGBA; + break; + case GL_LUMINANCE: + case GL_LUMINANCE8: + intformat = GL_COMPRESSED_LUMINANCE; + break; + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE8_ALPHA8: + intformat = GL_COMPRESSED_LUMINANCE_ALPHA; + break; + case GL_ALPHA: + case GL_ALPHA8: + intformat = GL_COMPRESSED_ALPHA; + break; + default: + llwarns << "Could not compress format: " << std::hex << intformat << llendl; + break; + } + } + stop_glerror(); glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); stop_glerror(); @@ -1201,10 +1230,11 @@ BOOL LLImageGL::createGLTexture() if(mTexName) { - glDeleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ; + LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, (reinterpret_cast<GLuint*>(&mTexName))) ; } - glGenTextures(1, (GLuint*)&mTexName); + + LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName); stop_glerror(); if (!mTexName) { @@ -1284,7 +1314,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S return TRUE ; } - setCategory(category) ; + setCategory(category); const U8* rawdata = imageraw->getData(); return createGLTexture(discard_level, rawdata, FALSE, usename); } @@ -1317,7 +1347,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ } else { - LLImageGL::generateTextures(1, &mTexName); + LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName); stop_glerror(); { llverify(gGL.getTexUnit(0)->bind(this)); @@ -1362,12 +1392,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ { sGlobalTextureMemoryInBytes -= mTextureMemory; - if(gAuditTexture) - { - decTextureCounter(mTextureMemory, mComponents, mCategory) ; - } - - LLImageGL::deleteTextures(1, &old_name); + LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &old_name); stop_glerror(); } @@ -1376,10 +1401,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ sGlobalTextureMemoryInBytes += mTextureMemory; mTexelsInGLTexture = getWidth() * getHeight() ; - if(gAuditTexture) - { - incTextureCounter(mTextureMemory, mComponents, mCategory) ; - } // mark this as bound at this point, so we don't throw it out immediately mLastBindTime = sLastFrameTime; return TRUE; @@ -1500,7 +1521,7 @@ void LLImageGL::deleteDeadTextures() { bool reset = false; - while (!sDeadTextureList.empty()) + /*while (!sDeadTextureList.empty()) { GLuint tex = sDeadTextureList.front(); sDeadTextureList.pop_front(); @@ -1522,7 +1543,7 @@ void LLImageGL::deleteDeadTextures() glDeleteTextures(1, &tex); stop_glerror(); - } + }*/ if (reset) { @@ -1536,22 +1557,29 @@ void LLImageGL::destroyGLTexture() { if(mTextureMemory) { - if(gAuditTexture) - { - decTextureCounter(mTextureMemory, mComponents, mCategory) ; - } sGlobalTextureMemoryInBytes -= mTextureMemory; mTextureMemory = 0; } - LLImageGL::deleteTextures(1, &mTexName); - mTexName = 0; + LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &mTexName); mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. + mTexName = 0; mGLTextureCreated = FALSE ; - } + } } - +//force to invalidate the gl texture, most likely a sculpty texture +void LLImageGL::forceToInvalidateGLTexture() +{ + if (mTexName != 0) + { + destroyGLTexture(); + } + else + { + mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. + } +} //---------------------------------------------------------------------------- @@ -1969,70 +1997,6 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) return res; } -void LLImageGL::setCategory(S32 category) -{ -#if 0 //turn this off temporarily because it is not in use now. - if(!gAuditTexture) - { - return ; - } - if(mCategory != category) - { - if(mCategory > -1) - { - sTextureMemByCategory[mCategory] -= mTextureMemory ; - } - if(category > -1 && category < sMaxCatagories) - { - sTextureMemByCategory[category] += mTextureMemory ; - mCategory = category; - } - else - { - mCategory = -1 ; - } - } -#endif -} - -//for debug use -//val is a "power of two" number -S32 LLImageGL::getTextureCounterIndex(U32 val) -{ - //index range is [0, MAX_TEXTURE_LOG_SIZE]. - if(val < 2) - { - return 0 ; - } - else if(val >= (1 << MAX_TEXTURE_LOG_SIZE)) - { - return MAX_TEXTURE_LOG_SIZE ; - } - else - { - S32 ret = 0 ; - while(val >>= 1) - { - ++ret; - } - return ret ; - } -} - -//static -void LLImageGL::incTextureCounter(U32 val, S32 ncomponents, S32 category) -{ - sTextureLoadedCounter[getTextureCounterIndex(val)]++ ; - sTextureMemByCategory[category] += (S32)val * ncomponents ; -} - -//static -void LLImageGL::decTextureCounter(U32 val, S32 ncomponents, S32 category) -{ - sTextureLoadedCounter[getTextureCounterIndex(val)]-- ; - sTextureMemByCategory[category] += (S32)val * ncomponents ; -} - void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size) { sCurTexSizeBar = index ; diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 2cfb15b0d9..e118c28c1b 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -45,8 +45,16 @@ class LLImageGL : public LLRefCount { friend class LLTexUnit; public: - static std::list<U32> sDeadTextureList; + static U32 sCurTexName; + //previously used but now available texture names + // sDeadTextureList[<usage>][<internal format>] + typedef std::map<U32, std::list<U32> > dead_texturelist_t; + static dead_texturelist_t sDeadTextureList[LLTexUnit::TT_NONE]; + + // These 2 functions replace glGenTextures() and glDeleteTextures() + static void generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures); + static void deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate = false); static void deleteDeadTextures(); // Size calculation @@ -94,16 +102,13 @@ public: void setSize(S32 width, S32 height, S32 ncomponents); void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;} + void setAllowCompression(bool allow) { mAllowCompression = allow; } - // These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D() - // for tracking purposes and will be deprecated in the future - static void generateTextures(S32 numTextures, U32 *textures); - static void deleteTextures(S32 numTextures, U32 *textures, bool immediate = false); - static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels); + static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true); BOOL createGLTexture() ; - BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, - S32 category = sMaxCatagories - 1); + 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); void setImage(const LLImageRaw* imageraw); void setImage(const U8* data_in, BOOL data_hasmips = FALSE); @@ -114,6 +119,7 @@ public: // 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(); + void forceToInvalidateGLTexture(); void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); void setComponents(S8 ncomponents) { mComponents = ncomponents; } @@ -209,11 +215,14 @@ private: U32 mTexelsInAtlas ; U32 mTexelsInGLTexture; + bool mAllowCompression; + protected: LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps) LLTexUnit::eTextureType mBindTarget; // Normally TT_TEXTURE, sometimes something else (ex. cube maps) bool mHasMipMaps; - + S32 mMipLevels; + LLGLboolean mIsResident; S8 mComponents; @@ -234,8 +243,6 @@ public: static S32 sCount; static F32 sLastFrameTime; - - static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID // Global memory statistics static S32 sGlobalTextureMemoryInBytes; // Tracks main memory texmem @@ -246,7 +253,7 @@ public: static BOOL sGlobalUseAnisotropic; static LLImageGL* sDefaultGLTexture ; static BOOL sAutomatedTest; - + static bool sCompressTextures; //use GL texture compression #if DEBUG_MISS BOOL mMissed; // Missed on last bind? BOOL getMissed() const { return mMissed; }; @@ -257,9 +264,10 @@ public: public: static void initClass(S32 num_catagories) ; static void cleanupClass() ; -private: - static S32 sMaxCatagories ; +private: + static S32 sMaxCategories; + //the flag to allow to call readBackRaw(...). //can be removed if we do not use that function at all. static BOOL sAllowReadBackRaw ; @@ -269,39 +277,22 @@ private: //**************************************************************************************************** private: S32 mCategory ; -public: - void setCategory(S32 category) ; - S32 getCategory()const {return mCategory ;} - +public: + void setCategory(S32 category) {mCategory = category;} + S32 getCategory()const {return mCategory;} + //for debug use: show texture size distribution //---------------------------------------- - static LLPointer<LLImageGL> sHighlightTexturep; //default texture to replace normal textures - static std::vector<S32> sTextureLoadedCounter ; - static std::vector<S32> sTextureBoundCounter ; - static std::vector<S32> sTextureCurBoundCounter ; static S32 sCurTexSizeBar ; static S32 sCurTexPickSize ; - static void setHighlightTexture(S32 category) ; - static S32 getTextureCounterIndex(U32 val) ; - static void incTextureCounter(U32 val, S32 ncomponents, S32 category) ; - static void decTextureCounter(U32 val, S32 ncomponents, S32 category) ; static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ; static void resetCurTexSizebar(); - //---------------------------------------- - //for debug use: show texture category distribution - //---------------------------------------- - - static std::vector<S32> sTextureMemByCategory; - static std::vector<S32> sTextureMemByCategoryBound ; - static std::vector<S32> sTextureCurMemByCategoryBound ; - //---------------------------------------- //**************************************************************************************************** //End of definitions for texture auditing use only //**************************************************************************************************** }; -extern BOOL gAuditTexture; #endif // LL_LLIMAGEGL_H diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index b0ddacbb05..348c1eb1b7 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -246,14 +246,6 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) } //in audit, replace the selected texture by the default one. - if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0) - { - if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize) - { - gl_tex->updateBindStats(gl_tex->mTextureMemory); - return bind(LLImageGL::sHighlightTexturep.get()); - } - } if ((mCurrTexture != gl_tex->getTexName()) || forceBind) { activate(); @@ -416,12 +408,14 @@ void LLTexUnit::unbind(eTextureType type) if (mIndex < 0) return; + //always flush and activate for consistency + // some code paths assume unbind always flushes and sets the active texture + gGL.flush(); + activate(); + // Disabled caching of binding state. if (mCurrTexType == type) { - gGL.flush(); - - activate(); mCurrTexture = 0; if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE) { @@ -472,11 +466,25 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio } else if (option >= TFO_BILINEAR) { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (mHasMipMaps) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } } else { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (mHasMipMaps) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } } if (gGLManager.mHasAnisotropic) diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index ef2a7395da..99f0da330c 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -55,7 +55,6 @@ bool LLRenderTarget::sUseFBO = false; LLRenderTarget::LLRenderTarget() : mResX(0), mResY(0), - mTex(0), mFBO(0), mDepth(0), mStencil(0), @@ -135,7 +134,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) } U32 tex; - LLImageGL::generateTextures(1, &tex); + LLImageGL::generateTextures(mUsage, color_fmt, 1, &tex); gGL.getTexUnit(0)->bindManual(mUsage, tex); stop_glerror(); @@ -143,7 +142,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) { clear_glerror(); - LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false); if (glGetError() != GL_NO_ERROR) { llwarns << "Could not allocate color buffer for render target." << llendl; @@ -193,6 +192,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) } mTex.push_back(tex); + mInternalFormat.push_back(color_fmt); if (gDebugGL) { //bind and unbind to validate target @@ -217,13 +217,13 @@ bool LLRenderTarget::allocateDepth() } else { - LLImageGL::generateTextures(1, &mDepth); + LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth); gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); stop_glerror(); clear_glerror(); - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } @@ -294,7 +294,7 @@ void LLRenderTarget::release() } else { - LLImageGL::deleteTextures(1, &mDepth, true); + LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true); stop_glerror(); } mDepth = 0; @@ -326,8 +326,9 @@ void LLRenderTarget::release() if (mTex.size() > 0) { sBytesAllocated -= mResX*mResY*4*mTex.size(); - LLImageGL::deleteTextures(mTex.size(), &mTex[0], true); + LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true); mTex.clear(); + mInternalFormat.clear(); } mResX = mResY = 0; diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 2735ab21c5..8360458840 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -142,6 +142,7 @@ protected: U32 mResX; U32 mResY; std::vector<U32> mTex; + std::vector<U32> mInternalFormat; U32 mFBO; U32 mDepth; bool mStencil; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 7d384450e6..a9248d4d73 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -702,7 +702,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (texture_index_channels > 1) { - text[count++] = strdup("VARYING_FLAT ivec4 vary_texture_index;\n"); + text[count++] = strdup("VARYING_FLAT int vary_texture_index;\n"); } text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n"); @@ -716,20 +716,33 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade } else if (major_version > 1 || minor_version >= 30) { //switches are supported in GLSL 1.30 and later - text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n"); - text[count++] = strdup("\tswitch (vary_texture_index.r)\n"); - text[count++] = strdup("\t{\n"); - - //switch body - for (S32 i = 0; i < texture_index_channels; ++i) - { - std::string case_str = llformat("\t\tcase %d: ret = texture2D(tex%d, texcoord); break;\n", i, i); - text[count++] = strdup(case_str.c_str()); + if (gGLManager.mIsNVIDIA) + { //switches are unreliable on some NVIDIA drivers + for (U32 i = 0; i < texture_index_channels; ++i) + { + std::string if_string = llformat("\t%sif (vary_texture_index == %d) { return texture2D(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i); + text[count++] = strdup(if_string.c_str()); + } + text[count++] = strdup("\treturn vec4(1,0,1,1);\n"); + text[count++] = strdup("}\n"); } + else + { + text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n"); + text[count++] = strdup("\tswitch (vary_texture_index)\n"); + text[count++] = strdup("\t{\n"); + + //switch body + for (S32 i = 0; i < texture_index_channels; ++i) + { + std::string case_str = llformat("\t\tcase %d: return texture2D(tex%d, texcoord);\n", i, i); + text[count++] = strdup(case_str.c_str()); + } - text[count++] = strdup("\t}\n"); - text[count++] = strdup("\treturn ret;\n"); - text[count++] = strdup("}\n"); + text[count++] = strdup("\t}\n"); + text[count++] = strdup("\treturn ret;\n"); + text[count++] = strdup("}\n"); + } } else { //should never get here. Indexed texture rendering requires GLSL 1.30 or later @@ -1026,6 +1039,9 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("size"); mReservedUniforms.push_back("falloff"); + mReservedUniforms.push_back("box_center"); + mReservedUniforms.push_back("box_size"); + mReservedUniforms.push_back("minLuminance"); mReservedUniforms.push_back("maxExtractAlpha"); @@ -1062,8 +1078,9 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("proj_shadow_res"); mReservedUniforms.push_back("depth_cutoff"); mReservedUniforms.push_back("norm_cutoff"); + mReservedUniforms.push_back("shadow_target_width"); - llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_NORM_CUTOFF+1); + llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH+1); mReservedUniforms.push_back("tc_scale"); mReservedUniforms.push_back("rcp_screen_res"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index e28bda6de2..7a16b7c20f 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -97,6 +97,8 @@ public: LIGHT_CENTER, LIGHT_SIZE, LIGHT_FALLOFF, + BOX_CENTER, + BOX_SIZE, GLOW_MIN_LUMINANCE, GLOW_MAX_EXTRACT_ALPHA, @@ -130,6 +132,7 @@ public: DEFERRED_PROJ_SHADOW_RES, DEFERRED_DEPTH_CUTOFF, DEFERRED_NORM_CUTOFF, + DEFERRED_SHADOW_TARGET_WIDTH, FXAA_TC_SCALE, FXAA_RCP_SCREEN_RES, diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 8b5503229f..80752231d7 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -38,6 +38,10 @@ #include "llglslshader.h" #include "llmemory.h" +#if LL_DARWIN +#define LL_VBO_POOLING 1 +#else +#endif //Next Highest Power Of Two //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2 U32 nhpo2(U32 v) @@ -49,6 +53,37 @@ U32 nhpo2(U32 v) return r; } +//which power of 2 is i? +//assumes i is a power of 2 > 0 +U32 wpo2(U32 i) +{ + llassert(i > 0); + llassert(nhpo2(i) == i); + + U32 r = 0; + + while (i >>= 1) ++r; + + return r; +} + + +const U32 LL_VBO_BLOCK_SIZE = 2048; +const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024; + +U32 vbo_block_size(U32 size) +{ //what block size will fit size? + U32 mod = size % LL_VBO_BLOCK_SIZE; + return mod == 0 ? size : size + (LL_VBO_BLOCK_SIZE-mod); +} + +U32 vbo_block_index(U32 size) +{ + return vbo_block_size(size)/LL_VBO_BLOCK_SIZE; +} + +const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE); + //============================================================================ @@ -57,7 +92,16 @@ LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB); LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB); LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB); + U32 LLVBOPool::sBytesPooled = 0; +U32 LLVBOPool::sIndexBytesPooled = 0; +U32 LLVBOPool::sCurGLName = 1; + +std::list<U32> LLVertexBuffer::sAvailableVAOName; +U32 LLVertexBuffer::sCurVAOName = 1; + +U32 LLVertexBuffer::sAllocatedIndexBytes = 0; +U32 LLVertexBuffer::sIndexCount = 0; LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL; U32 LLVertexBuffer::sBindCount = 0; @@ -74,99 +118,88 @@ U32 LLVertexBuffer::sLastMask = 0; bool LLVertexBuffer::sVBOActive = false; bool LLVertexBuffer::sIBOActive = false; U32 LLVertexBuffer::sAllocatedBytes = 0; +U32 LLVertexBuffer::sVertexCount = 0; bool LLVertexBuffer::sMapped = false; bool LLVertexBuffer::sUseStreamDraw = true; bool LLVertexBuffer::sUseVAO = false; bool LLVertexBuffer::sPreferStreamDraw = false; -const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms -class LLGLSyncFence : public LLGLFence +U32 LLVBOPool::genBuffer() { -public: -#ifdef GL_ARB_sync - GLsync mSync; -#endif - - LLGLSyncFence() - { -#ifdef GL_ARB_sync - mSync = 0; -#endif - } + U32 ret = 0; - virtual ~LLGLSyncFence() + if (mGLNamePool.empty()) { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } -#endif + ret = sCurGLName++; } - - void placeFence() + else { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } - mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -#endif + ret = mGLNamePool.front(); + mGLNamePool.pop_front(); } - void wait() - { -#ifdef GL_ARB_sync - if (mSync) - { - while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) - { //track the number of times we've waited here - static S32 waits = 0; - waits++; - } - } -#endif - } + return ret; +} +void LLVBOPool::deleteBuffer(U32 name) +{ + if (gGLManager.mInited) + { + LLVertexBuffer::unbind(); -}; + glBindBufferARB(mType, name); + glBufferDataARB(mType, 0, NULL, mUsage); + llassert(std::find(mGLNamePool.begin(), mGLNamePool.end(), name) == mGLNamePool.end()); -//which power of 2 is i? -//assumes i is a power of 2 > 0 -U32 wpo2(U32 i) -{ - llassert(i > 0); - llassert(nhpo2(i) == i); + mGLNamePool.push_back(name); - U32 r = 0; + glBindBufferARB(mType, 0); + } +} - while (i >>= 1) ++r; - return r; +LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType) +: mUsage(vboUsage), mType(vboType) +{ + mMissCount.resize(LL_VBO_POOL_SEED_COUNT); + std::fill(mMissCount.begin(), mMissCount.end(), 0); } -volatile U8* LLVBOPool::allocate(U32& name, U32 size) +volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) { - llassert(nhpo2(size) == size); + llassert(vbo_block_size(size) == size); + + volatile U8* ret = NULL; - U32 i = wpo2(size); + U32 i = vbo_block_index(size); if (mFreeList.size() <= i) { mFreeList.resize(i+1); } - volatile U8* ret = NULL; - - if (mFreeList[i].empty()) + if (mFreeList[i].empty() || for_seed) { //make a new buffer - glGenBuffersARB(1, &name); + name = genBuffer(); + glBindBufferARB(mType, name); - LLVertexBuffer::sAllocatedBytes += size; + + if (!for_seed && i < LL_VBO_POOL_SEED_COUNT) + { //record this miss + mMissCount[i]++; + } + + if (mType == GL_ARRAY_BUFFER_ARB) + { + LLVertexBuffer::sAllocatedBytes += size; + } + else + { + LLVertexBuffer::sAllocatedIndexBytes += size; + } if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) { @@ -179,13 +212,39 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size) } glBindBufferARB(mType, 0); + + if (for_seed) + { //put into pool for future use + llassert(mFreeList.size() > i); + + Record rec; + rec.mGLName = name; + rec.mClientData = ret; + + if (mType == GL_ARRAY_BUFFER_ARB) + { + sBytesPooled += size; + } + else + { + sIndexBytesPooled += size; + } + mFreeList[i].push_back(rec); + } } else { name = mFreeList[i].front().mGLName; ret = mFreeList[i].front().mClientData; - sBytesPooled -= size; + if (mType == GL_ARRAY_BUFFER_ARB) + { + sBytesPooled -= size; + } + else + { + sIndexBytesPooled -= size; + } mFreeList[i].pop_front(); } @@ -195,30 +254,49 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size) void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) { - llassert(nhpo2(size) == size); - - U32 i = wpo2(size); + llassert(vbo_block_size(size) == size); - llassert(mFreeList.size() > i); + deleteBuffer(name); + ll_aligned_free_16((U8*) buffer); - Record rec; - rec.mGLName = name; - rec.mClientData = buffer; - - if (buffer == NULL) + if (mType == GL_ARRAY_BUFFER_ARB) { - glDeleteBuffersARB(1, &rec.mGLName); + LLVertexBuffer::sAllocatedBytes -= size; } else { - sBytesPooled += size; - mFreeList[i].push_back(rec); + LLVertexBuffer::sAllocatedIndexBytes -= size; + } +} + +void LLVBOPool::seedPool() +{ + U32 dummy_name = 0; + + if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT) + { + mFreeList.resize(LL_VBO_POOL_SEED_COUNT); + } + + for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++) + { + if (mMissCount[i] > mFreeList[i].size()) + { + U32 size = i*LL_VBO_BLOCK_SIZE; + + S32 count = mMissCount[i] - mFreeList[i].size(); + for (U32 j = 0; j < count; ++j) + { + allocate(dummy_name, size, true); + } + } } } + void LLVBOPool::cleanup() { - U32 size = 1; + U32 size = LL_VBO_BLOCK_SIZE; for (U32 i = 0; i < mFreeList.size(); ++i) { @@ -228,8 +306,8 @@ void LLVBOPool::cleanup() { Record& r = l.front(); - glDeleteBuffersARB(1, &r.mGLName); - + deleteBuffer(r.mGLName); + if (r.mClientData) { ll_aligned_free_16((void*) r.mClientData); @@ -237,12 +315,23 @@ void LLVBOPool::cleanup() l.pop_front(); - LLVertexBuffer::sAllocatedBytes -= size; - sBytesPooled -= size; + if (mType == GL_ARRAY_BUFFER_ARB) + { + sBytesPooled -= size; + LLVertexBuffer::sAllocatedBytes -= size; + } + else + { + sIndexBytesPooled -= size; + LLVertexBuffer::sAllocatedIndexBytes -= size; + } } - size *= 2; + size += LL_VBO_BLOCK_SIZE; } + + //reset miss counts + std::fill(mMissCount.begin(), mMissCount.end(), 0); } @@ -276,6 +365,41 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = GL_LINE_LOOP, }; +//static +U32 LLVertexBuffer::getVAOName() +{ + U32 ret = 0; + + if (!sAvailableVAOName.empty()) + { + ret = sAvailableVAOName.front(); + sAvailableVAOName.pop_front(); + } + else + { +#ifdef GL_ARB_vertex_array_object + glGenVertexArrays(1, &ret); +#endif + } + + return ret; +} + +//static +void LLVertexBuffer::releaseVAOName(U32 name) +{ + sAvailableVAOName.push_back(name); +} + + +//static +void LLVertexBuffer::seedPools() +{ + sStreamVBOPool.seedPool(); + sDynamicVBOPool.seedPool(); + sStreamIBOPool.seedPool(); + sDynamicIBOPool.seedPool(); +} //static void LLVertexBuffer::setupClientArrays(U32 data_mask) @@ -885,7 +1009,7 @@ LLVertexBuffer::~LLVertexBuffer() if (mGLArray) { #if GL_ARB_vertex_array_object - glDeleteVertexArrays(1, &mGLArray); + releaseVAOName(mGLArray); #endif } @@ -898,6 +1022,9 @@ LLVertexBuffer::~LLVertexBuffer() mFence = NULL; + sVertexCount -= mNumVerts; + sIndexCount -= mNumIndices; + llassert_always(!mMappedData && !mMappedIndexData); }; @@ -929,7 +1056,7 @@ void LLVertexBuffer::waitFence() const void LLVertexBuffer::genBuffer(U32 size) { - mSize = nhpo2(size); + mSize = vbo_block_size(size); if (mUsage == GL_STREAM_DRAW_ARB) { @@ -945,7 +1072,7 @@ void LLVertexBuffer::genBuffer(U32 size) void LLVertexBuffer::genIndices(U32 size) { - mIndicesSize = nhpo2(size); + mIndicesSize = vbo_block_size(size); if (mUsage == GL_STREAM_DRAW_ARB) { @@ -1108,10 +1235,10 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) llassert(nverts >= 0); - if (nverts >= 65535) + if (nverts > 65536) { llwarns << "Vertex buffer overflow!" << llendl; - nverts = 65535; + nverts = 65536; } U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts); @@ -1121,7 +1248,9 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) createGLBuffer(needed_size); } + sVertexCount -= mNumVerts; mNumVerts = nverts; + sVertexCount += mNumVerts; } void LLVertexBuffer::updateNumIndices(S32 nindices) @@ -1137,7 +1266,9 @@ void LLVertexBuffer::updateNumIndices(S32 nindices) createGLIndices(needed_size); } + sIndexCount -= mNumIndices; mNumIndices = nindices; + sIndexCount += mNumIndices; } void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) @@ -1163,7 +1294,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) { #if GL_ARB_vertex_array_object - glGenVertexArrays(1, &mGLArray); + mGLArray = getVAOName(); #endif setupVertexArray(); } @@ -1199,7 +1330,7 @@ void LLVertexBuffer::setupVertexArray() 1, //TYPE_WEIGHT, 4, //TYPE_WEIGHT4, 4, //TYPE_CLOTHWEIGHT, - 4, //TYPE_TEXTURE_INDEX + 1, //TYPE_TEXTURE_INDEX }; U32 attrib_type[] = @@ -1216,7 +1347,7 @@ void LLVertexBuffer::setupVertexArray() GL_FLOAT, //TYPE_WEIGHT, GL_FLOAT, //TYPE_WEIGHT4, GL_FLOAT, //TYPE_CLOTHWEIGHT, - GL_UNSIGNED_BYTE, //TYPE_TEXTURE_INDEX + GL_UNSIGNED_INT, //TYPE_TEXTURE_INDEX }; bool attrib_integer[] = @@ -2033,6 +2164,16 @@ void LLVertexBuffer::flush() } } +// bind for transform feedback (quick 'n dirty) +void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count) +{ +#ifdef GL_TRANSFORM_FEEDBACK_BUFFER + U32 offset = mOffsets[type] + sTypeSize[type]*index; + U32 size= (sTypeSize[type]*count); + glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size); +#endif +} + // Set for rendering void LLVertexBuffer::setBuffer(U32 data_mask) { @@ -2184,10 +2325,10 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) stop_glerror(); volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; - /*if ((data_mask & mTypeMask) != data_mask) + if (gDebugGL && ((data_mask & mTypeMask) != data_mask)) { llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; - }*/ + } if (LLGLSLShader::sNoFixedFunction) { @@ -2263,7 +2404,7 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) #if !LL_DARWIN S32 loc = TYPE_TEXTURE_INDEX; void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12); - glVertexAttribIPointer(loc, 4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); + glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); #endif } if (data_mask & MAP_VERTEX) diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index d859199663..11fa4ab6a0 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -55,24 +55,30 @@ class LLVBOPool { public: static U32 sBytesPooled; + static U32 sIndexBytesPooled; - LLVBOPool(U32 vboUsage, U32 vboType) - : mUsage(vboUsage) - , mType(vboType) - {} + static U32 sCurGLName; + LLVBOPool(U32 vboUsage, U32 vboType); + const U32 mUsage; const U32 mType; //size MUST be a power of 2 - volatile U8* allocate(U32& name, U32 size); + volatile U8* allocate(U32& name, U32 size, bool for_seed = false); //size MUST be the size provided to allocate that returned the given name void release(U32 name, volatile U8* buffer, U32 size); + //batch allocate buffers to be provided to the application on demand + void seedPool(); + //destroy all records in mFreeList void cleanup(); + U32 genBuffer(); + void deleteBuffer(U32 name); + class Record { public: @@ -80,17 +86,15 @@ public: volatile U8* mClientData; }; + std::list<U32> mGLNamePool; + typedef std::list<Record> record_list_t; std::vector<record_list_t> mFreeList; -}; + std::vector<U32> mMissCount; -class LLGLFence -{ -public: - virtual void placeFence() = 0; - virtual void wait() = 0; }; + //============================================================================ // base class class LLPrivateMemoryPool; @@ -124,13 +128,22 @@ public: static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; + static std::list<U32> sAvailableVAOName; + static U32 sCurVAOName; + static bool sUseStreamDraw; static bool sUseVAO; static bool sPreferStreamDraw; + static void seedPools(); + + static U32 getVAOName(); + static void releaseVAOName(U32 name); + static void initClass(bool use_vbo, bool no_vbo_mapping); static void cleanupClass(); static void setupClientArrays(U32 data_mask); + static void pushPositions(U32 mode, const LLVector4a* pos, U32 count); static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm); static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp); @@ -207,7 +220,6 @@ protected: void destroyGLIndices(); void updateNumVerts(S32 nverts); void updateNumIndices(S32 nindices); - bool useVBOs() const; void unmapBuffer(); public: @@ -217,6 +229,8 @@ public: volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range); volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range); + void bindForFeedback(U32 channel, U32 type, U32 index, U32 count); + // set for rendering virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0 void flush(); //flush pending data to GL memory @@ -239,12 +253,14 @@ public: bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getTextureIndexStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool useVBOs() const; bool isEmpty() const { return mEmpty; } bool isLocked() const { return mVertexLocked || mIndexLocked; } S32 getNumVerts() const { return mNumVerts; } @@ -332,6 +348,9 @@ public: static bool sIBOActive; static U32 sLastMask; static U32 sAllocatedBytes; + static U32 sAllocatedIndexBytes; + static U32 sVertexCount; + static U32 sIndexCount; static U32 sBindCount; static U32 sSetCount; }; |