From 58edba51290f18e0868397fa6ba2a885f8fc9667 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 24 Feb 2011 18:08:17 -0600 Subject: [PATCH] V2 llrender merge, sans freetype and LLTexture --- indra/llcommon/llpreprocessor.h | 17 ++ indra/llrender/llcubemap.cpp | 15 +- indra/llrender/llfontbitmapcache.cpp | 18 +- indra/llrender/llfontbitmapcache.h | 1 - indra/llrender/llfontgl.cpp | 5 +- indra/llrender/llfontgl.h | 3 +- indra/llrender/llfontregistry.cpp | 31 +- indra/llrender/llfontregistry.h | 8 +- indra/llrender/llgl.cpp | 70 ++++- indra/llrender/llgl.h | 2 + indra/llrender/llglheaders.h | 12 + indra/llrender/llimagegl.cpp | 412 +++++++++++++++++++++------ indra/llrender/llimagegl.h | 19 +- indra/llrender/llrender.cpp | 177 ++++++++++-- indra/llrender/llrender.h | 16 +- indra/llrender/llrendertarget.cpp | 53 +++- indra/llrender/llrendertarget.h | 4 + indra/llrender/llvertexbuffer.cpp | 35 ++- indra/newview/llviewerdisplay.cpp | 3 + indra/newview/llviewerimage.cpp | 27 +- 20 files changed, 717 insertions(+), 211 deletions(-) diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 474f53d81..3af4ae89d 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -55,13 +55,28 @@ #define LL_BIG_ENDIAN 1 #endif + // Per-compiler switches + #ifdef __GNUC__ #define LL_FORCE_INLINE inline __attribute__((always_inline)) #else #define LL_FORCE_INLINE __forceinline #endif +// Mark-up expressions with branch prediction hints. Do NOT use +// this with reckless abandon - it's an obfuscating micro-optimization +// outside of inner loops or other places where you are OVERWHELMINGLY +// sure which way an expression almost-always evaluates. +#if __GNUC__ >= 3 +# define LL_LIKELY(EXPR) __builtin_expect (!!(EXPR), true) +# define LL_UNLIKELY(EXPR) __builtin_expect (!!(EXPR), false) +#else +# define LL_LIKELY(EXPR) (EXPR) +# define LL_UNLIKELY(EXPR) (EXPR) +#endif + + // Figure out differences between compilers #if defined(__GNUC__) #define GCC_VERSION (__GNUC__ * 10000 \ @@ -106,7 +121,9 @@ #if defined(LL_WINDOWS) #define BOOST_REGEX_NO_LIB 1 #define CURL_STATICLIB 1 +#ifndef XML_STATIC #define XML_STATIC +#endif #endif // LL_WINDOWS // Deal with VC6 problems diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index a5c677dd4..036714e5c 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -63,6 +63,12 @@ LLCubeMap::LLCubeMap() mTextureCoordStage(0), mMatrixStage(0) { + mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB; + mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; + mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB; + mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB; + mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB; + mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB; } LLCubeMap::~LLCubeMap() @@ -75,13 +81,6 @@ void LLCubeMap::initGL() if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) { - mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB; - mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; - mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB; - mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB; - mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB; - mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB; - // Not initialized, do stuff. if (mImages[0].isNull()) { @@ -94,7 +93,7 @@ void LLCubeMap::initGL() mImages[i] = new LLImageGL(64, 64, 4, (use_cube_mipmaps? TRUE : FALSE)); mImages[i]->setTarget(mTargets[i], LLTexUnit::TT_CUBE_MAP); mRawImages[i] = new LLImageRaw(64, 64, 4); - mImages[i]->createGLTexture(0, mRawImages[i], texname, TRUE); + mImages[i]->createGLTexture(0, mRawImages[i], texname); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname); mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP); diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp index 052510e6e..f01878642 100644 --- a/indra/llrender/llfontbitmapcache.cpp +++ b/indra/llrender/llfontbitmapcache.cpp @@ -37,13 +37,13 @@ LLFontBitmapCache::LLFontBitmapCache(): mNumComponents(0), - mMaxCharWidth(0), - mMaxCharHeight(0), mBitmapWidth(0), mBitmapHeight(0), + mBitmapNum(-1), + mMaxCharWidth(0), + mMaxCharHeight(0), mCurrentOffsetX(1), - mCurrentOffsetY(1), - mCurrentBitmapNum(-1) + mCurrentOffsetY(1) { } @@ -160,10 +160,10 @@ void LLFontBitmapCache::reset() mImageRawVec.clear(); mImageGLVec.clear(); - mBitmapWidth = 0, - mBitmapHeight = 0, - mCurrentOffsetX = 0, - mCurrentOffsetY = 0, - mCurrentBitmapNum = -1; + mBitmapWidth = 0; + mBitmapHeight = 0; + mBitmapNum = -1; + mCurrentOffsetX = 1; + mCurrentOffsetY = 1; } diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h index 4beea0d02..f5ed224eb 100644 --- a/indra/llrender/llfontbitmapcache.h +++ b/indra/llrender/llfontbitmapcache.h @@ -71,7 +71,6 @@ private: S32 mMaxCharHeight; S32 mCurrentOffsetX; S32 mCurrentOffsetY; - S32 mCurrentBitmapNum; std::vector > mImageRawVec; std::vector > mImageGLVec; }; diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 7b3ea4552..507a8b926 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -218,7 +218,8 @@ bool findOrCreateFont(LLFontGL*& fontp, const LLFontDescriptor& desc) // static BOOL LLFontGL::initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, - const std::vector& xui_paths) + const std::vector& xui_paths, + bool create_gl_textures) { bool succ = true; sVertDPI = (F32)llfloor(screen_dpi * y_scale); @@ -230,7 +231,7 @@ BOOL LLFontGL::initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale, // Font registry init if (!sFontRegistry) { - sFontRegistry = new LLFontRegistry(xui_paths); + sFontRegistry = new LLFontRegistry(xui_paths,create_gl_textures); sFontRegistry->parseFontInfo("fonts.xml"); } else diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 6cb1727ff..efeb420da 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -95,7 +95,8 @@ public: static BOOL initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, - const std::vector& xui_paths); + const std::vector& xui_paths, + bool create_gl_textures = true); static void destroyDefaultFonts(); static void destroyAllGL(); diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index 619228eb6..0e92afeb4 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -33,8 +33,8 @@ #include "linden_common.h" #include "llgl.h" -#include "llfontregistry.h" #include "llfontgl.h" +#include "llfontregistry.h" #include #include "llcontrol.h" #include "lldir.h" @@ -104,7 +104,7 @@ bool removeSubString(std::string& str, const std::string& substr) size_t pos = str.find(substr); if (pos != string::npos) { - str.replace(pos,substr.length(),(const char *)NULL, 0); + str.erase(pos, substr.size()); return true; } return false; @@ -168,7 +168,9 @@ LLFontDescriptor LLFontDescriptor::normalize() const return LLFontDescriptor(new_name,new_size,new_style,getFileNames()); } -LLFontRegistry::LLFontRegistry(const string_vec_t& xui_paths) +LLFontRegistry::LLFontRegistry(const string_vec_t& xui_paths, + bool create_gl_textures) +: mCreateGLTextures(create_gl_textures) { // Propagate this down from LLUICtrlFactory so LLRender doesn't // need an upstream dependency on LLUI. @@ -377,10 +379,22 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) LLFontDescriptor nearest_exact_desc = *match_desc; nearest_exact_desc.setSize(norm_desc.getSize()); font_reg_map_t::iterator it = mFontMap.find(nearest_exact_desc); - if (it != mFontMap.end()) + // If we fail to find a font in the fonts directory, it->second might be NULL. + // We shouldn't construcnt a font with a NULL mFontFreetype. + // This may not be the best solution, but it at least prevents a crash. + if (it != mFontMap.end() && it->second != NULL) { llinfos << "-- matching font exists: " << nearest_exact_desc.getName() << " size " << nearest_exact_desc.getSize() << " style " << ((S32) nearest_exact_desc.getStyle()) << llendl; + return it->second; + //Haven't plugged free-type in yet. + // copying underlying Freetype font, and storing in LLFontGL with requested font descriptor + /*LLFontGL *font = new LLFontGL; + font->mFontDescriptor = desc; + font->mFontFreetype = it->second->mFontFreetype; + mFontMap[desc] = font; + + return font;*/ } // Build list of font names to look for. @@ -427,7 +441,9 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) { LLFontGL *fontp = new LLFontGL; std::string font_path = local_path + *file_name_it; - BOOL is_fallback = !is_first_found; + // *HACK: Fallback fonts don't render, so we can use that to suppress + // creation of OpenGL textures for test apps. JC + BOOL is_fallback = !is_first_found || !mCreateGLTextures; F32 extra_scale = (is_fallback)?fallback_scale:1.0; if (!fontp->loadFace(font_path, extra_scale * point_size, LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback)) @@ -649,3 +665,8 @@ void LLFontRegistry::dump() } } } + +const string_vec_t& LLFontRegistry::getUltimateFallbackList() const +{ + return mUltimateFallbackList; +} diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h index 523e18426..4da4ca48b 100644 --- a/indra/llrender/llfontregistry.h +++ b/indra/llrender/llfontregistry.h @@ -71,7 +71,10 @@ private: class LLFontRegistry { public: - LLFontRegistry(const string_vec_t& xui_paths); + // create_gl_textures - set to false for test apps with no OpenGL window, + // such as llui_libtest + LLFontRegistry(const string_vec_t& xui_paths, + bool create_gl_textures); ~LLFontRegistry(); // Load standard font info from XML file(s). @@ -95,7 +98,7 @@ public: void dump(); - const string_vec_t& getUltimateFallbackList() const { return mUltimateFallbackList; } + const string_vec_t& getUltimateFallbackList() const; private: LLFontGL *createFont(const LLFontDescriptor& desc); @@ -109,6 +112,7 @@ private: string_vec_t mUltimateFallbackList; string_vec_t mXUIPaths; + bool mCreateGLTextures; }; #endif // LL_LLFONTREGISTRY_H diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 47d3d2d3b..1263ac83c 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -139,6 +139,9 @@ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = // GL_EXT_framebuffer_blit PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL; +// GL_EXT_blend_func_separate +PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL; + // GL_ARB_draw_buffers PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL; @@ -278,6 +281,7 @@ LLGLManager::LLGLManager() : mHasCompressedTextures(FALSE), mHasFramebufferObject(FALSE), mHasFramebufferMultisample(FALSE), + mHasBlendFuncSeparate(FALSE), mHasVertexBufferObject(FALSE), mHasPBuffer(FALSE), @@ -286,6 +290,8 @@ LLGLManager::LLGLManager() : mHasFragmentShader(FALSE), mHasOcclusionQuery(FALSE), mHasPointParameters(FALSE), + mHasDrawBuffers(FALSE), + mHasTextureRectangle(FALSE), mHasAnisotropic(FALSE), mHasARBEnvCombine(FALSE), @@ -590,6 +596,11 @@ void LLGLManager::initExtensions() #else mHasDepthClamp = FALSE; #endif +# if GL_EXT_blend_func_separate + mHasBlendFuncSeparate = TRUE; +#else + mHasBlendFuncSeparate = FALSE; +# endif mHasMipMapGeneration = FALSE; mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; @@ -599,6 +610,7 @@ void LLGLManager::initExtensions() mHasShaderObjects = FALSE; mHasVertexShader = FALSE; mHasFragmentShader = FALSE; + mHasTextureRectangle = FALSE; #else // LL_MESA_HEADLESS mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap"); @@ -610,12 +622,14 @@ 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); mHasFramebufferMultisample = mHasFramebufferObject && ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts); mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); - mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts); + mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); + mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts); mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts) @@ -630,13 +644,14 @@ void LLGLManager::initExtensions() if (getenv("LL_GL_NOEXT")) /* Flawfinder: ignore */ { //mHasMultitexture = FALSE; // NEEDED! + mHasDepthClamp = FALSE; mHasARBEnvCombine = FALSE; mHasCompressedTextures = FALSE; mHasVertexBufferObject = FALSE; mHasFramebufferObject = FALSE; mHasFramebufferMultisample = FALSE; mHasDrawBuffers = FALSE; - mHasDepthClamp = FALSE; + mHasBlendFuncSeparate = FALSE; mHasMipMapGeneration = FALSE; mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; @@ -661,6 +676,7 @@ void LLGLManager::initExtensions() mHasShaderObjects = FALSE; mHasVertexShader = FALSE; mHasFragmentShader = FALSE; + mHasBlendFuncSeparate = FALSE; LL_WARNS("RenderInit") << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << LL_ENDL; } if (getenv("LL_GL_BLACKLIST")) /* Flawfinder: ignore */ @@ -688,7 +704,9 @@ void LLGLManager::initExtensions() if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE; - if (strchr(blacklist,'t')) mHasDepthClamp = 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 @@ -737,6 +755,14 @@ void LLGLManager::initExtensions() { LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_fragment_shader" << LL_ENDL; } + if (!mHasBlendFuncSeparate) + { + LL_INFOS("RenderInit") << "Couldn't initialize GL_EXT_blend_func_separate" << LL_ENDL; + } + if (!mHasDrawBuffers) + { + LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_draw_buffers" << LL_ENDL; + } // Disable certain things due to known bugs if (mIsIntel && mHasMipMapGeneration) @@ -809,6 +835,10 @@ void LLGLManager::initExtensions() { glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDrawBuffersARB"); } + if (mHasBlendFuncSeparate) + { + glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT"); + } #if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS // This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements"); @@ -977,7 +1007,7 @@ void assert_glerror() { return; } - if (!gGLManager.mInited) + if (LL_UNLIKELY(!gGLManager.mInited)) { LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL; } @@ -985,7 +1015,7 @@ void assert_glerror() GLenum error; error = glGetError(); BOOL quit = FALSE; - while (error) + while (LL_UNLIKELY(error)) { quit = TRUE; #ifndef LL_LINUX // *FIX: ! This should be an error for linux as well. @@ -1138,7 +1168,7 @@ void LLGLState::checkTextureChannels(const std::string& msg) } } - GLint maxTextureUnits; + GLint maxTextureUnits = 0; glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits); static const char* label[] = @@ -1168,8 +1198,11 @@ void LLGLState::checkTextureChannels(const std::string& msg) }; GLint stackDepth = 0; - LLMatrix4 identity; - LLMatrix4 matrix; + glh::matrix4f mat; + glh::matrix4f identity; + identity.identity(); +// LLMatrix4 identity; +// LLMatrix4 matrix; for (GLint i = 1; i < maxTextureUnits; i++) { @@ -1184,15 +1217,18 @@ void LLGLState::checkTextureChannels(const std::string& msg) LL_WARNS("RenderState") << "Texture matrix stack corrupted." << LL_ENDL; } - glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) matrix.mMatrix); + //glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) matrix.mMatrix); + glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) mat.m); - if (matrix != identity) + //if (matrix != identity) + if (mat != identity) { error = TRUE; LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL; } - for (S32 j = (i == 0 ? 1 : 0); j < 9; j++) + for (S32 j = (i == 0 ? 1 : 0); + j < (gGLManager.mHasTextureRectangle ? 9 : 8); j++) { if (glIsEnabled(value[j])) { @@ -1201,10 +1237,6 @@ void LLGLState::checkTextureChannels(const std::string& msg) } } - glh::matrix4f mat; - glh::matrix4f identity; - identity.identity(); - glGetFloatv(GL_TEXTURE_MATRIX, mat.m); if (mat != identity) @@ -1735,6 +1767,14 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled) { stop_glerror(); + + if (!depth_enabled) + { // always disable depth writes if depth testing is disabled + // GL spec defines this as a requirement, but some implementations allow depth writes with testing disabled + // The proper way to write to depth buffer with testing disabled is to enable testing and use a depth_func of GL_ALWAYS + write_enabled = FALSE; + } + if (depth_enabled != sDepthEnabled) { gGL.flush(); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index cc7ebffd2..27116e088 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -78,6 +78,7 @@ public: BOOL mHasCompressedTextures; BOOL mHasFramebufferObject; BOOL mHasFramebufferMultisample; + BOOL mHasBlendFuncSeparate; // ARB Extensions BOOL mHasVertexBufferObject; @@ -89,6 +90,7 @@ public: BOOL mHasPointParameters; BOOL mHasDrawBuffers; BOOL mHasDepthClamp; + BOOL mHasTextureRectangle; // Other extensions. BOOL mHasAnisotropic; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 9e3ae9d57..81ae3d40e 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -218,6 +218,9 @@ extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; extern PFNGLCOLORTABLEEXTPROC glColorTableEXT; +//GL_EXT_blend_func_separate +extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; + //GL_EXT_framebuffer_object extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; @@ -449,6 +452,9 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; +//GL_EXT_blend_func_separate +extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; + //GL_EXT_framebuffer_object extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; @@ -645,6 +651,9 @@ extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB; extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB; extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; +//GL_EXT_blend_func_separate +extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; + //GL_EXT_framebuffer_object extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; @@ -689,6 +698,9 @@ extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; // Note that they also must not be called on 10.3.9. This should be taken care of by a runtime check for the existence of the GL extension. #include +//GL_EXT_blend_func_separate +extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + // GL_EXT_framebuffer_object extern GLboolean glIsRenderbufferEXT(GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; extern void glBindRenderbufferEXT(GLenum target, GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index c981b97de..a8ef4ee9d 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -56,6 +56,7 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes = 0; S32 LLImageGL::sBoundTextureMemoryInBytes = 0; S32 LLImageGL::sCurBoundTextureMemory = 0; S32 LLImageGL::sCount = 0; +std::list LLImageGL::sDeadTextureList; BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; F32 LLImageGL::sLastFrameTime = 0.f; @@ -75,7 +76,7 @@ std::vector LLImageGL::sTextureBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ; std::vector LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ; S32 LLImageGL::sCurTexSizeBar = -1 ; S32 LLImageGL::sCurTexPickSize = -1 ; -LLPointer LLImageGL::sDefaultTexturep = NULL; +LLPointer LLImageGL::sHighlightTexturep = NULL; S32 LLImageGL::sMaxCatagories = 1 ; std::vector LLImageGL::sTextureMemByCategory; @@ -133,6 +134,13 @@ void LLImageGL::checkTexSize() const //************************************************************************************** //---------------------------------------------------------------------------- +BOOL is_little_endian() +{ + S32 a = 0x12345678; + U8 *c = (U8*)(&a); + + return (*c == 0x78) ; +} //static void LLImageGL::initClass(S32 num_catagories) { @@ -146,6 +154,40 @@ void LLImageGL::initClass(S32 num_catagories) //static void LLImageGL::cleanupClass() { + sTextureMemByCategory.clear() ; + sTextureMemByCategoryBound.clear() ; + sTextureCurMemByCategoryBound.clear() ; +} + +//static +void LLImageGL::setHighlightTexture(S32 category) +{ + const S32 dim = 128; + sHighlightTexturep = new LLImageGL() ; + LLPointer image_raw = new LLImageRaw(dim,dim,3); + U8* data = image_raw->getData(); + for (S32 i = 0; 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); + sHighlightTexturep->dontDiscard(); + image_raw = NULL; } //static @@ -369,7 +411,6 @@ LLImageGL::~LLImageGL() sImageList.erase(this); delete [] mPickMask; mPickMask = NULL; - mPickMaskSize = 0; sCount--; } @@ -380,10 +421,13 @@ void LLImageGL::init(BOOL usemipmaps) #endif mPickMask = NULL; - mPickMaskSize = 0; mTextureState = NO_DELETE ; mTextureMemory = 0; mLastBindTime = 0.f; + mPickMaskWidth = 0; + mPickMaskHeight = 0; + mAlphaStride = 0 ; + mAlphaOffset = 0 ; mTarget = GL_TEXTURE_2D; mBindTarget = LLTexUnit::TT_TEXTURE; @@ -455,7 +499,7 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents) // Check if dimensions are a power of two! if (!checkSize(width,height)) { - llerrs << llformat("Texture has non power of two dimention: %dx%d",width,height) << llendl; + llerrs << llformat("Texture has non power of two dimension: %dx%d",width,height) << llendl; } if (mTexName) @@ -463,7 +507,12 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents) // llwarns << "Setting Size of LLImageGL with existing mTexName = " << mTexName << llendl; destroyGLTexture(); } - + + // pickmask validity depends on old image size, delete it + delete [] mPickMask; + mPickMask = NULL; + mPickMaskWidth = mPickMaskHeight = 0; + mWidth = width; mHeight = height; mComponents = ncomponents; @@ -518,7 +567,7 @@ void LLImageGL::forceUpdateBindStats(void) const mLastBindTime = sLastFrameTime; } -void LLImageGL::updateBindStats(void) const +BOOL LLImageGL::updateBindStats() const { if (mTexName != 0) { @@ -533,8 +582,11 @@ void LLImageGL::updateBindStats(void) const updateBoundTexMem(); mLastBindTime = sLastFrameTime; + + return TRUE ; } } + return FALSE; } //virtual @@ -567,6 +619,8 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for else mFormatType = type_format; mFormatSwapBytes = swap_bytes; + + calcAlphaChannelOffsetAndStride() ; } //---------------------------------------------------------------------------- @@ -922,7 +976,10 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures) // static void LLImageGL::deleteTextures(S32 numTextures, U32 *textures) { - glDeleteTextures(numTextures, (GLuint*)textures); + for (S32 i = 0; i < numTextures; i++) + { + sDeadTextureList.push_back(textures[i]); + } } // static @@ -1020,6 +1077,8 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S to_create = false; break; } + + calcAlphaChannelOffsetAndStride() ; } if(!to_create) //not create a gl texture @@ -1030,7 +1089,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S return TRUE ; } - mCategory = category ; + setCategory(category) ; const U8* rawdata = imageraw->getData(); return createGLTexture(discard_level, rawdata, FALSE, usename); } @@ -1286,21 +1345,30 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre return TRUE ; } -void LLImageGL::destroyGLTexture() +void LLImageGL::deleteDeadTextures() { - if (mTexName != 0) + while (!sDeadTextureList.empty()) { - stop_glerror(); - + GLuint tex = sDeadTextureList.front(); + sDeadTextureList.pop_front(); for (int i = 0; i < gGLManager.mNumTextureUnits; i++) { - if (sCurrentBoundTextures[i] == mTexName) + if (sCurrentBoundTextures[i] == tex) { gGL.getTexUnit(i)->unbind(LLTexUnit::TT_TEXTURE); stop_glerror(); } } + glDeleteTextures(1, &tex); + stop_glerror(); + } +} + +void LLImageGL::destroyGLTexture() +{ + if (mTexName != 0) + { if(mTextureMemory) { if(gAuditTexture) @@ -1316,7 +1384,6 @@ void LLImageGL::destroyGLTexture() mTexName = 0; mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. mGLTextureCreated = FALSE ; - stop_glerror(); } } @@ -1345,12 +1412,12 @@ void LLImageGL::setFilteringOption(LLTexUnit::eTextureFilterOptions option) mFilterOption = option; } - if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) + if (mTexName != 0 && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) { gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureFilteringOption(option); mTexOptionsDirty = false; + stop_glerror(); } - stop_glerror(); } BOOL LLImageGL::getIsResident(BOOL test_now) @@ -1442,59 +1509,189 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b mBindTarget = bind_target; } -void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h) +//Used by media in V2 +const S8 INVALID_OFFSET = -99 ; +void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask) { - if (mFormatType != GL_UNSIGNED_BYTE) + if(mNeedsAlphaAndPickMask != need_mask) { - llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl; + mNeedsAlphaAndPickMask = need_mask; + + if(mNeedsAlphaAndPickMask) + { + mAlphaOffset = 0 ; + } + else //do not need alpha mask + { + mAlphaOffset = INVALID_OFFSET ; + mIsMask = FALSE; + } + } +} + +void LLImageGL::calcAlphaChannelOffsetAndStride() +{ + if(mAlphaOffset == INVALID_OFFSET)//do not need alpha mask + { + return ; } - U32 stride = 0; + mAlphaStride = -1 ; switch (mFormatPrimary) { case GL_LUMINANCE: case GL_ALPHA: - stride = 1; + mAlphaStride = 1; break; case GL_LUMINANCE_ALPHA: - stride = 2; + mAlphaStride = 2; break; case GL_RGB: - //no alpha + mNeedsAlphaAndPickMask = FALSE ; mIsMask = FALSE; - return; + return ; //no alpha channel. case GL_RGBA: - stride = 4; + mAlphaStride = 4; break; case GL_BGRA_EXT: - stride = 4; + mAlphaStride = 4; break; default: - llwarns << "Cannot analyze alpha of image with primary format " << std::hex << mFormatPrimary << std::dec << llendl; - return; + break; + } + + mAlphaOffset = -1 ; + if (mFormatType == GL_UNSIGNED_BYTE) + { + mAlphaOffset = mAlphaStride - 1 ; + } + else if(is_little_endian()) + { + if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) + { + mAlphaOffset = 0 ; + } + else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) + { + mAlphaOffset = 3 ; + } + } + else //big endian + { + if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) + { + mAlphaOffset = 3 ; + } + else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) + { + mAlphaOffset = 0 ; + } + } + + if( mAlphaStride < 1 || //unsupported format + mAlphaOffset < 0 || //unsupported type + (mFormatPrimary == GL_BGRA_EXT && mFormatType != GL_UNSIGNED_BYTE)) //unknown situation + { + llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl; + + mNeedsAlphaAndPickMask = FALSE ; + mIsMask = FALSE; + } +} + +void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) +{ + if(!mNeedsAlphaAndPickMask) + { + return ; } U32 length = w * h; - const GLubyte* current = ((const GLubyte*) data_in)+stride-1; + U32 alphatotal = 0; - S32 sample[16]; - memset(sample, 0, sizeof(S32)*16); + U32 sample[16]; + memset(sample, 0, sizeof(U32)*16); - for (U32 i = 0; i < length; i++) + // generate histogram of quantized alpha. + // also add-in the histogram of a 2x2 box-sampled version. The idea is + // this will mid-skew the data (and thus increase the chances of not + // being used as a mask) from high-frequency alpha maps which + // suffer the worst from aliasing when used as alpha masks. + if (w >= 2 && h >= 2) { - ++sample[*current/16]; - current += stride; - } + llassert(w%2 == 0); + llassert(h%2 == 0); + const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset; + for (U32 y = 0; y < h; y+=2) + { + const GLubyte* current = rowstart; + for (U32 x = 0; x < w; x+=2) + { + const U32 s1 = current[0]; + alphatotal += s1; + const U32 s2 = current[w * mAlphaStride]; + alphatotal += s2; + current += mAlphaStride; + const U32 s3 = current[0]; + alphatotal += s3; + const U32 s4 = current[w * mAlphaStride]; + alphatotal += s4; + current += mAlphaStride; - U32 total = 0; + ++sample[s1/16]; + ++sample[s2/16]; + ++sample[s3/16]; + ++sample[s4/16]; + + const U32 asum = (s1+s2+s3+s4); + alphatotal += asum; + sample[asum/(16*4)] += 4; + } + + rowstart += 2 * w * mAlphaStride; + } + length *= 2; // we sampled everything twice, essentially + } + else + { + const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset; + for (U32 i = 0; i < length; i++) + { + const U32 s1 = *current; + alphatotal += s1; + ++sample[s1/16]; + current += mAlphaStride; + } + } + + // if more than 1/16th of alpha samples are mid-range, this + // shouldn't be treated as a 1-bit mask + + // also, if all of the alpha samples are clumped on one half + // of the range (but not at an absolute extreme), then consider + // this to be an intentional effect and don't treat as a mask. + + U32 midrangetotal = 0; for (U32 i = 4; i < 11; i++) { - total += sample[i]; + midrangetotal += sample[i]; + } + U32 lowerhalftotal = 0; + for (U32 i = 0; i < 8; i++) + { + lowerhalftotal += sample[i]; + } + U32 upperhalftotal = 0; + for (U32 i = 8; i < 16; i++) + { + upperhalftotal += sample[i]; } - if (total > length/16) + if (midrangetotal > length/16 || // lots of midrange, or + (lowerhalftotal == length && alphatotal != 0) || // all close to transparent but not all totally transparent, or + (upperhalftotal == length && alphatotal != 255*length)) // all close to opaque but not all totally opaque { - mIsMask = FALSE; + mIsMask = FALSE; // not suitable for masking } else { @@ -1516,6 +1713,8 @@ BOOL LLImageGL::isDeletionCandidate() { return mTextureState == DELETION_CANDIDATE ; } +//---------------------------------------------------------------------------- + void LLImageGL::setDeletionCandidate() { @@ -1556,46 +1755,51 @@ void LLImageGL::setNoDelete() //---------------------------------------------------------------------------- void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { - delete [] mPickMask; //Always happens regardless. - - mPickMask = NULL; - mPickMaskSize = 0; - - if (!(mFormatType != GL_UNSIGNED_BYTE || - mFormatPrimary != GL_RGBA)) //can only generate a pick mask for this sort of texture + if(!mNeedsAlphaAndPickMask) { - U32 pick_width = width/2; - U32 pick_height = height/2; + return ; + } - mPickMaskSize = llmax(pick_width, (U32) 1) * llmax(pick_height, (U32) 1); + delete [] mPickMask; + mPickMask = NULL; + mPickMaskWidth = mPickMaskHeight = 0; - mPickMaskSize = mPickMaskSize/8 + 1; + if (mFormatType != GL_UNSIGNED_BYTE || + mFormatPrimary != GL_RGBA) + { + //cannot generate a pick mask for this texture + return; + } - mPickMask = new U8[mPickMaskSize]; + U32 pick_width = width/2 + 1; + U32 pick_height = height/2 + 1; - memset(mPickMask, 0, sizeof(U8) * mPickMaskSize); + U32 size = pick_width * pick_height; + size = (size + 7) / 8; // pixelcount-to-bits + mPickMask = new U8[size]; + mPickMaskWidth = pick_width - 1; + mPickMaskHeight = pick_height - 1; - U32 pick_bit = 0; - for (S32 y = 0; y < height; y += 2) + memset(mPickMask, 0, sizeof(U8) * size); + + U32 pick_bit = 0; + + for (S32 y = 0; y < height; y += 2) + { + for (S32 x = 0; x < width; x += 2) { - for (S32 x = 0; x < width; x += 2) + U8 alpha = data_in[(y*width+x)*4+3]; + + if (alpha > 32) { - U8 alpha = data_in[(y*width+x)*4+3]; + U32 pick_idx = pick_bit/8; + U32 pick_offset = pick_bit%8; + llassert(pick_idx < size); - if (alpha > 32) - { - U32 pick_idx = pick_bit/8; - U32 pick_offset = pick_bit%8; - if (pick_idx >= mPickMaskSize) - { - llerrs << "WTF?" << llendl; - } - - mPickMask[pick_idx] |= 1 << pick_offset; - } - - ++pick_bit; + mPickMask[pick_idx] |= 1 << pick_offset; } + + ++pick_bit; } } } @@ -1606,33 +1810,47 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) if (mPickMask) { - S32 width = getWidth()/2; - S32 height = getHeight()/2; - - F32 u = tc.mV[0] - floorf(tc.mV[0]); - F32 v = tc.mV[1] - floorf(tc.mV[1]); - - if (u < 0.f || u > 1.f || - v < 0.f || v > 1.f) + F32 u,v; + if (LL_LIKELY(tc.isFinite())) { - llerrs << "WTF?" << llendl; - } - - S32 x = (S32)(u * width); - S32 y = (S32)(v * height); - - S32 idx = y*width+x; - S32 offset = idx%8; - - if (idx / 8 < (S32)mPickMaskSize) - { - res = mPickMask[idx/8] & (1 << offset) ? TRUE : FALSE; + u = tc.mV[0] - floorf(tc.mV[0]); + v = tc.mV[1] - floorf(tc.mV[1]); } else { - llwarns << "Index out of range for mPickMask !" << llendl; - return FALSE; + LL_WARNS_ONCE("render") << "Ugh, non-finite u/v in mask pick" << LL_ENDL; + u = v = 0.f; + // removing assert per EXT-4388 + // llassert(false); } + + if (LL_UNLIKELY(u < 0.f || u > 1.f || + v < 0.f || v > 1.f)) + { + LL_WARNS_ONCE("render") << "Ugh, u/v out of range in image mask pick" << LL_ENDL; + u = v = 0.f; + // removing assert per EXT-4388 + // llassert(false); + } + + S32 x = llfloor(u * mPickMaskWidth); + S32 y = llfloor(v * mPickMaskHeight); + + if (LL_UNLIKELY(x > mPickMaskWidth)) + { + LL_WARNS_ONCE("render") << "Ooh, width overrun on pick mask read, that coulda been bad." << LL_ENDL; + x = llmax((U16)0, mPickMaskWidth); + } + if (LL_UNLIKELY(y > mPickMaskHeight)) + { + LL_WARNS_ONCE("render") << "Ooh, height overrun on pick mask read, that woulda been bad." << LL_ENDL; + y = llmax((U16)0, mPickMaskHeight); + } + + S32 idx = y*mPickMaskWidth+x; + S32 offset = idx%8; + + res = mPickMask[idx/8] & (1 << offset) ? TRUE : FALSE; } return res; @@ -1650,9 +1868,15 @@ void LLImageGL::setCategory(S32 category) { sTextureMemByCategory[mCategory] -= mTextureMemory ; } - sTextureMemByCategory[category] += mTextureMemory ; - - mCategory = category; + if(category > -1 && category < sMaxCatagories) + { + sTextureMemByCategory[category] += mTextureMemory ; + mCategory = category; + } + else + { + mCategory = -1 ; + } } } diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index c7114c36a..478d74cb1 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -50,12 +50,16 @@ class LLImageGL : public LLRefCount { friend class LLTexUnit; public: + static std::list sDeadTextureList; + + static void deleteDeadTextures(); + // Size calculation static S32 dataFormatBits(S32 dataformat); static S32 dataFormatBytes(S32 dataformat, S32 width, S32 height); static S32 dataFormatComponents(S32 dataformat); - void updateBindStats(void) const; + BOOL updateBindStats(void) const; void forceUpdateBindStats(void) const; // needs to be called every frame @@ -85,7 +89,8 @@ public: protected: virtual ~LLImageGL(); - void analyzeAlpha(const void* data_in, S32 w, S32 h); + void analyzeAlpha(const void* data_in, U32 w, U32 h); + void calcAlphaChannelOffsetAndStride(); public: virtual void dump(); // debugging info to llinfos @@ -182,6 +187,7 @@ protected: void init(BOOL usemipmaps); virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors + void setNeedsAlphaAndPickMask(BOOL need_mask); public: // Various GL/Rendering options S32 mTextureMemory; @@ -190,12 +196,16 @@ public: private: LLPointer mSaveData; // used for destroyGL/restoreGL U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel - U32 mPickMaskSize; + U16 mPickMaskWidth; + U16 mPickMaskHeight; S8 mUseMipMaps; S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents) S8 mAutoGenMips; BOOL mIsMask; + BOOL mNeedsAlphaAndPickMask; + S8 mAlphaStride ; + S8 mAlphaOffset ; bool mGLTextureCreated ; LLGLuint mTexName; @@ -279,13 +289,14 @@ public: //for debug use: show texture size distribution //---------------------------------------- - static LLPointer sDefaultTexturep; //default texture to replace normal textures + static LLPointer sHighlightTexturep; //default texture to replace normal textures static std::vector sTextureLoadedCounter ; static std::vector sTextureBoundCounter ; static std::vector sTextureCurBoundCounter ; static S32 sCurTexSizeBar ; static S32 sCurTexPickSize ; + static void setHighlightTexture(S32 category) ; static S32 getTextureCounterIndex(U32 val) ; static void incTextureCounterStatic(U32 val, S32 ncomponents, S32 category) ; static void decTextureCounterStatic(U32 val, S32 ncomponents, S32 category) ; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 6a670f2e5..8a62e557f 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -88,7 +88,9 @@ static GLenum sGLBlendFactor[] = GL_DST_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, - GL_ONE_MINUS_SRC_ALPHA + GL_ONE_MINUS_SRC_ALPHA, + + GL_ZERO // 'BF_UNDEF' }; LLTexUnit::LLTexUnit(S32 index) @@ -99,7 +101,7 @@ mCurrAlphaSrc1(TBS_TEX_ALPHA), mCurrAlphaSrc2(TBS_PREV_ALPHA), mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), mHasMipMaps(false) { - llassert_always(index < LL_NUM_TEXTURE_LAYERS); + llassert_always(index < (S32)LL_NUM_TEXTURE_LAYERS); mIndex = index; } @@ -207,7 +209,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize) { texture->updateBindStats(); - return bind(LLImageGL::sDefaultTexturep.get()); + return bind(LLImageGL::sHighlightTexturep.get()); } } @@ -217,8 +219,10 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) enable(texture->getTarget()); mCurrTexture = texture->getTexName(); glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture); - texture->updateBindStats(); - texture->setActive() ; + if(texture->updateBindStats()) + { + texture->setActive() ; + } mHasMipMaps = texture->mHasMipMaps; if (texture->mTexOptionsDirty) { @@ -227,7 +231,6 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) setTextureFilteringOption(texture->mFilterOption); } } - return true; } @@ -280,6 +283,11 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) if (bindDepth) { + if (renderTarget->hasStencil()) + { + llerrs << "Cannot bind a render buffer for sampling. Allocate render target without a stencil buffer if sampling of depth buffer is required." << llendl; + } + bindManual(renderTarget->getUsage(), renderTarget->getDepth()); } else @@ -293,8 +301,11 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) { - if (mIndex < 0) return false; - + if (mIndex < 0) + { + return false; + } + if(mCurrTexture != texture) { gGL.flush(); @@ -372,6 +383,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); } @@ -680,8 +694,11 @@ void LLTexUnit::debugTextureUnit(void) LLRender::LLRender() -: mDirty(false), mCount(0), mMode(LLRender::TRIANGLES), - mMaxAnisotropy(0.f) + : mDirty(false), + mCount(0), + mMode(LLRender::TRIANGLES), + mCurrTextureUnitIndex(0), + mMaxAnisotropy(0.f) { mBuffer = new LLVertexBuffer(immediate_mask, 0); mBuffer->allocateBuffer(4096, 0, TRUE); @@ -703,6 +720,10 @@ LLRender::LLRender() mCurrAlphaFunc = CF_DEFAULT; mCurrAlphaFuncVal = 0.01f; + mCurrBlendColorSFactor = BF_UNDEF; + mCurrBlendAlphaSFactor = BF_UNDEF; + mCurrBlendColorDFactor = BF_UNDEF; + mCurrBlendAlphaDFactor = BF_UNDEF; } LLRender::~LLRender() @@ -787,29 +808,28 @@ void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB void LLRender::setSceneBlendType(eBlendType type) { - flush(); switch (type) { case BT_ALPHA: - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + blendFunc(BF_SOURCE_ALPHA, BF_ONE_MINUS_SOURCE_ALPHA); break; case BT_ADD: - glBlendFunc(GL_ONE, GL_ONE); + blendFunc(BF_ONE, BF_ONE); break; case BT_ADD_WITH_ALPHA: - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + blendFunc(BF_SOURCE_ALPHA, BF_ONE); break; case BT_MULT: - glBlendFunc(GL_DST_COLOR, GL_ZERO); + blendFunc(BF_DEST_COLOR, BF_ZERO); break; case BT_MULT_ALPHA: - glBlendFunc(GL_DST_ALPHA, GL_ZERO); + blendFunc(BF_DEST_ALPHA, BF_ZERO); break; case BT_MULT_X2: - glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + blendFunc(BF_DEST_COLOR, BF_SOURCE_COLOR); break; case BT_REPLACE: - glBlendFunc(GL_ONE, GL_ZERO); + blendFunc(BF_ONE, BF_ZERO); break; default: llerrs << "Unknown Scene Blend Type: " << type << llendl; @@ -835,10 +855,45 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor) { - flush(); - glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]); + llassert(sfactor < BF_UNDEF); + llassert(dfactor < BF_UNDEF); + if (mCurrBlendColorSFactor != sfactor || mCurrBlendColorDFactor != dfactor || + mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor) + { + mCurrBlendColorSFactor = sfactor; + mCurrBlendAlphaSFactor = sfactor; + mCurrBlendColorDFactor = dfactor; + mCurrBlendAlphaDFactor = dfactor; + flush(); + glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]); + } } +void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, + eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor) +{ + llassert(color_sfactor < BF_UNDEF); + llassert(color_dfactor < BF_UNDEF); + llassert(alpha_sfactor < BF_UNDEF); + llassert(alpha_dfactor < BF_UNDEF); + if (!gGLManager.mHasBlendFuncSeparate) + { + LL_WARNS_ONCE("render") << "no glBlendFuncSeparateEXT(), using color-only blend func" << llendl; + blendFunc(color_sfactor, color_dfactor); + return; + } + if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor || + mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor) + { + mCurrBlendColorSFactor = color_sfactor; + mCurrBlendAlphaSFactor = alpha_sfactor; + mCurrBlendColorDFactor = color_dfactor; + mCurrBlendAlphaDFactor = alpha_dfactor; + flush(); + glBlendFuncSeparateEXT(sGLBlendFactor[color_sfactor], sGLBlendFactor[color_dfactor], + sGLBlendFactor[alpha_sfactor], sGLBlendFactor[alpha_dfactor]); + } +} LLTexUnit* LLRender::getTexUnit(U32 index) { if ((index >= 0) && (index < mTexUnits.size())) @@ -975,15 +1030,85 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) return; } - mVerticesp[mCount] = LLVector3(x,y,z); - mCount++; - if (mCount < 4096) + //if (mUIOffset.empty()) { - mVerticesp[mCount] = mVerticesp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mVerticesp[mCount] = LLVector3(x,y,z); } + /*else + { + LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back()); + mVerticesp[mCount] = vert; + }*/ + + mCount++; + mVerticesp[mCount] = mVerticesp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; } + +void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count) +{ + if (mCount + vert_count > 4094) + { + // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; + return; + } + + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + + mCount++; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + } + + mVerticesp[mCount] = mVerticesp[mCount-1]; +} + +void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count) +{ + if (mCount + vert_count > 4094) + { + // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; + return; + } + + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + + mCount++; + mColorsp[mCount] = mColorsp[mCount-1]; + } + + mVerticesp[mCount] = mVerticesp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; +} + +void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count) +{ + if (mCount + vert_count > 4094) + { + // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; + return; + } + + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount] = colors[i]; + + mCount++; + } + + mVerticesp[mCount] = mVerticesp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; +} + void LLRender::vertex2i(const GLint& x, const GLint& y) { vertex3f((GLfloat) x, (GLfloat) y, 0); diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index da69de8cf..0faaac441 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -268,7 +268,9 @@ public: BF_DEST_ALPHA, BF_SOURCE_ALPHA, BF_ONE_MINUS_DEST_ALPHA, - BF_ONE_MINUS_SOURCE_ALPHA + BF_ONE_MINUS_SOURCE_ALPHA, + + BF_UNDEF } eBlendFactor; LLRender(); @@ -305,13 +307,20 @@ public: void color3fv(const GLfloat* c); void color4ubv(const GLubyte* c); + void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count); + void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count); + void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count); void setColorMask(bool writeColor, bool writeAlpha); void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha); void setSceneBlendType(eBlendType type); void setAlphaRejectSettings(eCompareFunc func, F32 value = 0.01f); + // applies blend func to both color and alpha void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor); + // applies separate blend functions to color and alpha + void blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, + eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor); LLTexUnit* getTexUnit(U32 index); @@ -348,6 +357,11 @@ private: std::vector mTexUnits; LLTexUnit* mDummyTexUnit; + eBlendFactor mCurrBlendColorSFactor; + eBlendFactor mCurrBlendColorDFactor; + eBlendFactor mCurrBlendAlphaSFactor; + eBlendFactor mCurrBlendAlphaDFactor; + F32 mMaxAnisotropy; }; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 08ced38c9..d9f4f3430 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -203,7 +203,7 @@ void LLRenderTarget::allocateDepth() gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8_EXT, mResX, mResY, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32_ARB, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); } } @@ -378,7 +378,7 @@ void LLRenderTarget::flush(BOOL fetch_depth) allocateDepth(); } - gGL.getTexUnit(0)->bind(this, true); + gGL.getTexUnit(0)->bind(this); glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8_EXT, 0, 0, mResX, mResY, 0); } @@ -427,13 +427,13 @@ void LLRenderTarget::flush(BOOL fetch_depth) } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glFlush(); } } void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter) { + gGL.flush(); if (!source.mFBO || !mFBO) { llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl; @@ -444,13 +444,54 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, mSampleBuffer->copyContents(source, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } else + { + if (mask == GL_DEPTH_BUFFER_BIT && source.mStencil != mStencil) + { + stop_glerror(); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, source.mFBO); + gGL.getTexUnit(0)->bind(this, true); + stop_glerror(); + glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, srcX0, srcY0, dstX0, dstY0, dstX1, dstY1); + stop_glerror(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + stop_glerror(); + } + else + { + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO); + stop_glerror(); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO); + stop_glerror(); + check_framebuffer_status(); + stop_glerror(); + glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + stop_glerror(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + stop_glerror(); + } + } +} + +//static +void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, + S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter) +{ + if (!source.mFBO) + { + llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl; + } { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO); - + stop_glerror(); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); + stop_glerror(); + check_framebuffer_status(); + stop_glerror(); glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); - + stop_glerror(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + stop_glerror(); } } diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index d5d809b79..9ad4ec3a4 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -121,6 +121,7 @@ public: U32 getTexture(U32 attachment = 0) const; U32 getDepth(void) const { return mDepth; } + BOOL hasStencil() const { return mStencil; } void bindTexture(U32 index, S32 channel); @@ -135,6 +136,9 @@ public: void copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter); + static void copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, + S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter); + //Returns TRUE if target is ready to be rendered into. //That is, if the target has been allocated with at least //one renderable attachment (i.e. color buffer, depth buffer). diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index df067bd30..756603a32 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -337,7 +337,14 @@ void LLVertexBuffer::clientCopy(F64 max_time) LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : LLRefCount(), - mNumVerts(0), mNumIndices(0), mUsage(usage), mGLBuffer(0), mGLIndices(0), + + mNumVerts(0), + mNumIndices(0), + mRequestedNumVerts(-1), + mRequestedNumIndices(-1), + mUsage(usage), + mGLBuffer(0), + mGLIndices(0), mMappedData(NULL), mMappedIndexData(NULL), mLocked(FALSE), mFinal(FALSE), @@ -811,7 +818,7 @@ volatile U8* LLVertexBuffer::mapBuffer(S32 access) GLint buff; glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); - if (buff != mGLBuffer) + if ((GLuint)buff != mGLBuffer) { llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; } @@ -824,7 +831,7 @@ volatile U8* LLVertexBuffer::mapBuffer(S32 access) { GLint buff; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if (buff != mGLIndices) + if ((GLuint)buff != mGLIndices) { llerrs << "Invalid GL index buffer bound: " << buff << llendl; } @@ -1020,15 +1027,18 @@ void LLVertexBuffer::setBuffer(U32 data_mask) { GLint buff; glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); - if (buff != mGLBuffer) + if ((GLuint)buff != mGLBuffer) { llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; } - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if (buff != mGLIndices) + if (mGLIndices) { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); + if ((GLuint)buff != mGLIndices) + { + llerrs << "Invalid GL index buffer bound: " << buff << llendl; + } } } @@ -1038,15 +1048,18 @@ void LLVertexBuffer::setBuffer(U32 data_mask) { GLint buff; glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); - if (buff != mGLBuffer) + if ((GLuint)buff != mGLBuffer) { llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; } - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if (buff != mGLIndices) + if (mGLIndices != 0) { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); + if ((GLuint)buff != mGLIndices) + { + llerrs << "Invalid GL index buffer bound: " << buff << llendl; + } } } diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 82fe8afd3..0f8efb23b 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -765,6 +765,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time max_image_decode_time = llclamp(max_image_decode_time, 0.001f, 0.005f ); // min 1ms/frame, max 5ms/frame) gImageList.updateImages(max_image_decode_time); + + //remove dead textures from GL + LLImageGL::deleteDeadTextures(); stop_glerror(); } llpushcallstacks ; diff --git a/indra/newview/llviewerimage.cpp b/indra/newview/llviewerimage.cpp index 7978a9355..ca2ffc8eb 100644 --- a/indra/newview/llviewerimage.cpp +++ b/indra/newview/llviewerimage.cpp @@ -149,31 +149,7 @@ void LLViewerImage::initClass() if(gAuditTexture) { - sDefaultTexturep = new LLImageGL() ; - image_raw = new LLImageRaw(dim,dim,3); - data = image_raw->getData(); - for (S32 i = 0; i=(dim-border) || j>=(dim-border)) - { - *data++ = 0xff; - *data++ = 0xff; - *data++ = 0xff; - } - else - { - *data++ = 0xff; - *data++ = 0xff; - *data++ = 0x00; - } - } - } - sDefaultTexturep->createGLTexture(0, image_raw, 0, TRUE, LLViewerImageBoostLevel::OTHER); - image_raw = NULL; - sDefaultTexturep->dontDiscard(); + LLImageGL::setHighlightTexture(LLViewerImageBoostLevel::OTHER) ; } } @@ -188,7 +164,6 @@ void LLViewerImage::cleanupClass() sSmokeImagep = NULL; sMissingAssetImagep = NULL; sWhiteImagep = NULL; - sDefaultTexturep = NULL ; } // tuning params