diff options
author | Brad Kittenbrink <brad@lindenlab.com> | 2009-02-18 21:10:16 +0000 |
---|---|---|
committer | Brad Kittenbrink <brad@lindenlab.com> | 2009-02-18 21:10:16 +0000 |
commit | abdc99f21b542c4fea67030ddbd7166c9d1c6c63 (patch) | |
tree | 3e984e405adfdec189ca8a047daca5250737ffbf /indra/llrender | |
parent | 34412f0530cf6a411b4de906a8e9da59cbcb3a85 (diff) |
Merge of QAR-1267 to trunk. This was a combo merge of QAR-1175 (maint-render-9) and QAR-1236 (dll-msvcrt-2)
svn merge -r 109838:112264 svn+ssh://svn.lindenlab.com/svn/linden/branches/maint-render/maint-render-9-merge-r109833
Diffstat (limited to 'indra/llrender')
-rw-r--r-- | indra/llrender/CMakeLists.txt | 6 | ||||
-rw-r--r-- | indra/llrender/llcubemap.cpp | 11 | ||||
-rw-r--r-- | indra/llrender/llfontgl.cpp | 69 | ||||
-rw-r--r-- | indra/llrender/llfontgl.h | 2 | ||||
-rw-r--r-- | indra/llrender/llgl.cpp | 101 | ||||
-rw-r--r-- | indra/llrender/llgl.h | 4 | ||||
-rw-r--r-- | indra/llrender/llglheaders.h | 32 | ||||
-rw-r--r-- | indra/llrender/llglslshader.cpp | 86 | ||||
-rw-r--r-- | indra/llrender/llglslshader.h | 4 | ||||
-rw-r--r-- | indra/llrender/llimagegl.cpp | 305 | ||||
-rw-r--r-- | indra/llrender/llimagegl.h | 75 | ||||
-rw-r--r-- | indra/llrender/llpostprocess.cpp | 22 | ||||
-rw-r--r-- | indra/llrender/llpostprocess.h | 2 | ||||
-rw-r--r-- | indra/llrender/llrender.cpp | 134 | ||||
-rw-r--r-- | indra/llrender/llrender.h | 44 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.cpp | 533 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.h | 58 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 106 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.h | 15 |
19 files changed, 1270 insertions, 339 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 76858d9839..72aa3715c0 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -27,9 +27,7 @@ set(llrender_SOURCE_FILES llglslshader.cpp llimagegl.cpp llpostprocess.cpp - llrender.cpp llrendersphere.cpp - llrendertarget.cpp llshadermgr.cpp llvertexbuffer.cpp ) @@ -50,7 +48,6 @@ set(llrender_HEADER_FILES llpostprocess.h llrender.h llrendersphere.h - llrendertarget.h llshadermgr.h llvertexbuffer.h ) @@ -63,6 +60,7 @@ list(APPEND llrender_SOURCE_FILES ${llrender_HEADER_FILES}) if (SERVER AND NOT WINDOWS AND NOT DARWIN) copy_server_sources( llgl + llrender ) @@ -78,6 +76,8 @@ if (SERVER AND NOT WINDOWS AND NOT DARWIN) else (SERVER AND NOT WINDOWS AND NOT DARWIN) list(APPEND llrender_SOURCE_FILES llgl.cpp + llrender.cpp + llrendertarget.cpp ) endif (SERVER AND NOT WINDOWS AND NOT DARWIN) add_library (llrender ${llrender_SOURCE_FILES}) diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 14b95c25e7..754d90c854 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -85,9 +85,9 @@ void LLCubeMap::initGL() // Not initialized, do stuff. if (mImages[0].isNull()) { - GLuint texname = 0; + U32 texname = 0; - glGenTextures(1, &texname); + LLImageGL::generateTextures(1, &texname); for (int i = 0; i < 6; i++) { @@ -97,9 +97,10 @@ void LLCubeMap::initGL() mImages[i]->createGLTexture(0, mRawImages[i], texname); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname); - mImages[i]->setClampCubemap (TRUE, TRUE, TRUE); + mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP); stop_glerror(); } + gGL.getTexUnit(0)->disable(); } disable(); } @@ -311,8 +312,8 @@ void LLCubeMap::restoreMatrix() void LLCubeMap::setReflection (void) { gGL.getTexUnit(mTextureStage)->bindManual(LLTexUnit::TT_CUBE_MAP, getGLName()); - mImages[0]->setMipFilterNearest (FALSE, FALSE); - mImages[0]->setClampCubemap (TRUE, TRUE); + mImages[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); + mImages[0]->setAddressMode(LLTexUnit::TAM_CLAMP); } LLVector3 LLCubeMap::map(U8 side, U16 v_val, U16 h_val) const diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 846f18f4a9..3829306e25 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -535,7 +535,7 @@ BOOL LLFontGL::loadFace(const std::string& filename, } mImageGLp->createGLTexture(0, mRawImageGLp); gGL.getTexUnit(0)->bind(mImageGLp); - mImageGLp->setMipFilterNearest(TRUE, TRUE); + mImageGLp->setFilteringOption(LLTexUnit::TFO_POINT); return TRUE; } @@ -549,7 +549,7 @@ BOOL LLFontGL::addChar(const llwchar wch) stop_glerror(); mImageGLp->setSubImage(mRawImageGLp, 0, 0, mImageGLp->getWidth(), mImageGLp->getHeight()); gGL.getTexUnit(0)->bind(mImageGLp); - mImageGLp->setMipFilterNearest(TRUE, TRUE); + mImageGLp->setFilteringOption(LLTexUnit::TFO_POINT); stop_glerror(); return TRUE; } @@ -565,7 +565,7 @@ S32 LLFontGL::renderUTF8(const std::string &text, const S32 offset, BOOL use_ellipses) const { LLWString wstr = utf8str_to_wstring(text); - return render(wstr, offset, x, y, color, halign, valign, style, max_chars, max_pixels, right_x, use_ellipses); + return render(wstr, offset, x, y, color, halign, valign, style, max_chars, max_pixels, right_x, FALSE, use_ellipses); } S32 LLFontGL::render(const LLWString &wstr, @@ -1104,59 +1104,32 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ llwchar wch = wchars[i]; const embedded_data_t* ext_data = getEmbeddedCharData(wch); - if (ext_data) - { - F32 char_width = getEmbeddedCharAdvance(ext_data); - - if( scaled_max_pixels < (total_width + char_width) ) - { - break; - } - - total_width += char_width; - - drawable_chars++; - if( max_chars >= 0 && drawable_chars >= max_chars ) - { - break; - } - - if ( i > 0 ) - { - total_width += EXT_KERNING * sScaleX; - } + F32 char_width = ext_data ? getEmbeddedCharAdvance(ext_data) : getXAdvance(wch); - // Round after kerning. - total_width = (F32)llfloor(total_width + 0.5f); - } - else + if( scaled_max_pixels < (total_width + char_width) ) { - F32 char_width = getXAdvance(wch); - if( scaled_max_pixels < (total_width + char_width) ) - { - break; - } - - total_width += char_width; + break; + } - drawable_chars++; - if( max_chars >= 0 && drawable_chars >= max_chars ) - { - break; - } + total_width += char_width; + drawable_chars++; - if ( i > 0 ) - { - // Kerning - total_width += getXKerning(wchars[i-1], wch); - } + if( max_chars >= 0 && drawable_chars >= max_chars ) + { + break; + } - // Round after kerning. - total_width = (F32)llfloor(total_width + 0.5f); + if ( i > 0 ) + { + // kerning + total_width += ext_data ? (EXT_KERNING * sScaleX) : getXKerning(wchars[i-1], wch); } + + // Round after kerning. + total_width = llround(total_width); } - return text_len - drawable_chars; + return start_pos - drawable_chars; } diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index b369e42ce1..f8da460de2 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -181,7 +181,7 @@ public: F32* drawn_pixels = NULL) const; // Returns the index of the first complete characters from text that can be drawn in max_pixels - // starting on the right side (at character start_pos). + // given that the character at start_pos should be the last character (or as close to last as possible). virtual S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const; // Returns the index of the character closest to pixel position x (ignoring text to the right of max_pixels and max_chars) diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 74313974c9..61194c4ecf 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -133,6 +133,15 @@ PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL; PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL; PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL; +// GL_EXT_framebuffer_multisample +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = NULL; + +// GL_EXT_framebuffer_blit +PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL; + +// GL_ARB_draw_buffers +PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL; + //shader object prototypes PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = NULL; PFNGLGETHANDLEARBPROC glGetHandleARB = NULL; @@ -249,6 +258,12 @@ PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL; PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #endif +#if LL_LINUX_NV_GL_HEADERS +// linux nvidia headers. these define these differently to mesa's. ugh. +PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL; +PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = NULL; +PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = NULL; +#endif // LL_LINUX_NV_GL_HEADERS #endif LLGLManager gGLManager; @@ -262,6 +277,7 @@ LLGLManager::LLGLManager() : mHasMipMapGeneration(FALSE), mHasCompressedTextures(FALSE), mHasFramebufferObject(FALSE), + mHasFramebufferMultisample(FALSE), mHasVertexBufferObject(FALSE), mHasPBuffer(FALSE), @@ -561,6 +577,16 @@ void LLGLManager::initExtensions() # else mHasFramebufferObject = FALSE; # endif +# if GL_EXT_framebuffer_multisample + mHasFramebufferMultisample = TRUE; +# else + mHasFramebufferMultisample = FALSE; +# endif +# if GL_ARB_draw_buffers + mHasDrawBuffers = TRUE; +#else + mHasDrawBuffers = FALSE; +# endif mHasMipMapGeneration = FALSE; mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; @@ -584,6 +610,8 @@ void LLGLManager::initExtensions() // 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); #if !LL_DARWIN mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); #endif @@ -604,6 +632,8 @@ void LLGLManager::initExtensions() mHasCompressedTextures = FALSE; mHasVertexBufferObject = FALSE; mHasFramebufferObject = FALSE; + mHasFramebufferMultisample = FALSE; + mHasDrawBuffers = FALSE; mHasMipMapGeneration = FALSE; mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; @@ -653,6 +683,9 @@ void LLGLManager::initExtensions() if (strchr(blacklist,'o')) mHasFragmentShader = FALSE;//S if (strchr(blacklist,'p')) mHasPointParameters = FALSE;//S if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S + if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S + if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE; + } #endif // LL_LINUX || LL_SOLARIS @@ -761,15 +794,29 @@ void LLGLManager::initExtensions() glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameterivEXT"); glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmapEXT"); } -#if !LL_LINUX && !LL_SOLARIS - // This is expected to be a static symbol on Linux GL implementations + if (mHasFramebufferMultisample) + { + glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisampleEXT"); + glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebufferEXT"); + } + if (mHasDrawBuffers) + { + glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDrawBuffersARB"); + } +#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"); if (!glDrawRangeElements) { mGLMaxVertexRange = 0; mGLMaxIndexRange = 0; } -#endif // !LL_LINUX +#endif // !LL_LINUX || LL_LINUX_NV_GL_HEADERS +#if LL_LINUX_NV_GL_HEADERS + // nvidia headers are critically different from mesa-esque + glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glActiveTextureARB"); + glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glClientActiveTextureARB"); +#endif // LL_LINUX_NV_GL_HEADERS if (mHasOcclusionQuery) { @@ -946,7 +993,7 @@ void assert_glerror() { // gluErrorString returns NULL for some extensions' error codes. // you'll probably have to grep for the number in glext.h. - LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << LL_ENDL; + LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << LL_ENDL; } error = glGetError(); #endif @@ -986,6 +1033,11 @@ void LLGLState::initClass() //make sure multisample defaults to disabled sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE; glDisable(GL_MULTISAMPLE_ARB); + + sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE; + glDisable(GL_MULTISAMPLE_ARB); + + glEnableClientState(GL_VERTEX_ARRAY); } //static @@ -1037,7 +1089,7 @@ void LLGLState::checkStates(const std::string& msg) if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA) { - LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << " " << msg << LL_ENDL; + LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << " " << msg << std::dec << LL_ENDL; } for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); @@ -1076,7 +1128,7 @@ void LLGLState::checkTextureChannels(const std::string& msg) if (tex_env_mode != GL_MODULATE) { error = TRUE; - LL_WARNS("RenderState") << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << LL_ENDL; + LL_WARNS("RenderState") << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << std::dec << LL_ENDL; } } @@ -1092,7 +1144,8 @@ void LLGLState::checkTextureChannels(const std::string& msg) "GL_TEXTURE_GEN_S", "GL_TEXTURE_GEN_T", "GL_TEXTURE_GEN_Q", - "GL_TEXTURE_GEN_R" + "GL_TEXTURE_GEN_R", + "GL_TEXTURE_RECTANGLE_ARB" }; static GLint value[] = @@ -1104,7 +1157,8 @@ void LLGLState::checkTextureChannels(const std::string& msg) GL_TEXTURE_GEN_S, GL_TEXTURE_GEN_T, GL_TEXTURE_GEN_Q, - GL_TEXTURE_GEN_R + GL_TEXTURE_GEN_R, + GL_TEXTURE_RECTANGLE_ARB }; GLint stackDepth = 0; @@ -1132,7 +1186,7 @@ void LLGLState::checkTextureChannels(const std::string& msg) LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL; } - for (S32 j = (i == 0 ? 1 : 0); j < 8; j++) + for (S32 j = (i == 0 ? 1 : 0); j < 9; j++) { if (glIsEnabled(value[j])) { @@ -1140,6 +1194,18 @@ void LLGLState::checkTextureChannels(const std::string& msg) LL_WARNS("RenderState") << "Texture channel " << i << " still has " << label[j] << " enabled." << LL_ENDL; } } + + glh::matrix4f mat; + glh::matrix4f identity; + identity.identity(); + + glGetFloatv(GL_TEXTURE_MATRIX, mat.m); + + if (mat != identity) + { + error = TRUE; + LL_WARNS("RenderState") << "Texture matrix " << i << " is not identity." << LL_ENDL; + } } gGL.getTexUnit(0)->activate(); @@ -1261,6 +1327,22 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) glClientActiveTextureARB(GL_TEXTURE0_ARB); gGL.getTexUnit(0)->activate(); + if (gGLManager.mHasVertexShader) + { //make sure vertex attribs are all disabled + GLint count; + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &count); + for (GLint i = 0; i < count; i++) + { + GLint enabled; + glGetVertexAttribivARB((GLuint) i, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &enabled); + if (enabled) + { + error = TRUE; + LL_WARNS("RenderState") << "GL still has vertex attrib array " << i << " enabled." << LL_ENDL; + } + } + } + if (error) { LL_GL_ERRS << "GL client array corruption detected. " << msg << LL_ENDL; @@ -1646,6 +1728,7 @@ void LLGLNamePool::cleanupPools() LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, GLenum depth_func) : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled) { + stop_glerror(); if (depth_enabled != sDepthEnabled) { gGL.flush(); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 8caef2016e..00ff1e2f53 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -77,7 +77,8 @@ public: BOOL mHasMipMapGeneration; BOOL mHasCompressedTextures; BOOL mHasFramebufferObject; - + BOOL mHasFramebufferMultisample; + // ARB Extensions BOOL mHasVertexBufferObject; BOOL mHasPBuffer; @@ -86,6 +87,7 @@ public: BOOL mHasFragmentShader; BOOL mHasOcclusionQuery; BOOL mHasPointParameters; + BOOL mHasDrawBuffers; // Other extensions. BOOL mHasAnisotropic; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index e9a9ad1a77..91a01a9266 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -281,6 +281,18 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; #undef Status #endif // LL_LINUX && !LL_MESA_HEADLESS +#if LL_LINUX && defined(WINGDIAPI) +// WINGDIAPI gets set if we are using the linux nvidia gl.h header which needs +// the functions below setting up. +# define LL_LINUX_NV_GL_HEADERS +#endif // LL_LINUX && defined(WINGDIAPI) + +#ifdef LL_LINUX_NV_GL_HEADERS +// Missing functions when using nvidia headers: +extern PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; +extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB; +extern PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements; +#endif // LL_LINUX_NV_GL_HEADERS // GL_ARB_vertex_buffer_object extern PFNGLBINDBUFFERARBPROC glBindBufferARB; @@ -435,8 +447,6 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; -extern PFNGLCOLORTABLEEXTPROC glColorTableEXT; - //GL_EXT_framebuffer_object extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; @@ -456,6 +466,14 @@ extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; +// GL_EXT_framebuffer_multisample +extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT; + +// GL_EXT_framebuffer_blit +extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT; + +//GL_ARB_draw_buffers +extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; #elif LL_WINDOWS @@ -644,6 +662,14 @@ extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; +// GL_EXT_framebuffer_multisample +extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT; + +// GL_EXT_framebuffer_blit +extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT; + +//GL_ARB_draw_buffers +extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; #elif LL_DARWIN //---------------------------------------------------------------------------- @@ -680,6 +706,8 @@ extern void glFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenu extern void glGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, GLenum pname, GLint *params) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; extern void glGenerateMipmapEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +// GL_ARB_draw_buffers +extern void glDrawBuffersARB(GLsizei n, const GLenum* bufs) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; #ifdef __cplusplus extern "C" { diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 6464846c63..08d654805e 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -256,6 +256,14 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms) S32 location = glGetUniformLocationARB(mProgramObject, name); if (location != -1) { + //chop off "[0]" so we can always access the first element + //of an array by the array name + char* is_array = strstr(name, "[0]"); + if (is_array) + { + is_array[0] = 0; + } + mUniformMap[name] = location; LL_DEBUGS("ShaderLoading") << "Uniform " << name << " is at location " << location << LL_ENDL; @@ -353,11 +361,17 @@ void LLGLSLShader::unbind() { if (gGLManager.mHasShaderObjects) { - for (U32 i = 0; i < mAttribute.size(); ++i) + stop_glerror(); + if (gGLManager.mIsNVIDIA) { - vertexAttrib4f(i, 0,0,0,1); + for (U32 i = 0; i < mAttribute.size(); ++i) + { + vertexAttrib4f(i, 0,0,0,1); + stop_glerror(); + } } glUseProgramObjectARB(0); + stop_glerror(); } } @@ -390,14 +404,39 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode) return -1; } S32 index = mTexture[uniform]; - if (index != -1) + if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE) { - gGL.getTexUnit(index)->activate(); + if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode) + { + llerrs << "Texture channel " << index << " texture type corrupted." << llendl; + } gGL.getTexUnit(index)->disable(); } return index; } +void LLGLSLShader::uniform1i(U32 index, GLint x) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + if (iter == mValue.end() || iter->second.mV[0] != x) + { + glUniform1iARB(mUniform[index], x); + mValue[mUniform[index]] = LLVector4(x,0.f,0.f,0.f); + } + } + } +} + void LLGLSLShader::uniform1f(U32 index, GLfloat x) { if (mProgramObject > 0) @@ -489,6 +528,29 @@ void LLGLSLShader::uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat } } +void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0],0.f,0.f,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) + { + glUniform1ivARB(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v) { if (mProgramObject > 0) @@ -647,6 +709,22 @@ GLint LLGLSLShader::getUniformLocation(const string& uniform) return -1; } +void LLGLSLShader::uniform1i(const string& uniform, GLint v) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + LLVector4 vec(v,0.f,0.f,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec)) + { + glUniform1iARB(location, v); + mValue[location] = vec; + } + } +} + void LLGLSLShader::uniform1f(const string& uniform, GLfloat v) { GLint location = getUniformLocation(uniform); diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index c495a08726..166d4af04c 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -78,18 +78,22 @@ public: BOOL mapAttributes(const std::vector<std::string> * attributes); BOOL mapUniforms(const std::vector<std::string> * uniforms); void mapUniform(GLint index, const std::vector<std::string> * uniforms); + void uniform1i(U32 index, GLint i); void uniform1f(U32 index, GLfloat v); void uniform2f(U32 index, GLfloat x, GLfloat y); void uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z); void uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void uniform1iv(U32 index, U32 count, const GLint* i); void uniform1fv(U32 index, U32 count, const GLfloat* v); void uniform2fv(U32 index, U32 count, const GLfloat* v); void uniform3fv(U32 index, U32 count, const GLfloat* v); void uniform4fv(U32 index, U32 count, const GLfloat* v); + void uniform1i(const std::string& uniform, GLint i); void uniform1f(const std::string& uniform, GLfloat v); void uniform2f(const std::string& uniform, GLfloat x, GLfloat y); void uniform3f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z); void uniform4f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void uniform1iv(const std::string& uniform, U32 count, const GLint* i); void uniform1fv(const std::string& uniform, U32 count, const GLfloat* v); void uniform2fv(const std::string& uniform, U32 count, const GLfloat* v); void uniform3fv(const std::string& uniform, U32 count, const GLfloat* v); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index f5b596b963..307147798e 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -63,7 +63,6 @@ BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; F32 LLImageGL::sLastFrameTime = 0.f; std::set<LLImageGL*> LLImageGL::sImageList; - //************************************************************************************** //below are functions for debug use //do not delete them even though they are not currently being used. @@ -309,21 +308,21 @@ void LLImageGL::init(BOOL usemipmaps) #endif mPickMask = NULL; + mTextureState = NO_DELETE ; mTextureMemory = 0; mLastBindTime = 0.f; mTarget = GL_TEXTURE_2D; mBindTarget = LLTexUnit::TT_TEXTURE; mUseMipMaps = usemipmaps; - mHasMipMaps = FALSE; + mHasMipMaps = false; mAutoGenMips = FALSE; mTexName = 0; mIsResident = 0; - mClampS = FALSE; - mClampT = FALSE; - mClampR = FALSE; - mMagFilterNearest = FALSE; - mMinFilterNearest = FALSE; + + mTexOptionsDirty = true; + mAddressMode = LLTexUnit::TAM_WRAP; + mFilterOption = LLTexUnit::TFO_ANISOTROPIC; mWidth = 0; mHeight = 0; mComponents = 0; @@ -339,6 +338,7 @@ void LLImageGL::init(BOOL usemipmaps) mHasExplicitFormat = FALSE; mGLTextureCreated = FALSE ; + mIsMask = FALSE; } void LLImageGL::cleanup() @@ -469,6 +469,11 @@ bool LLImageGL::bindDefaultImage(const S32 stage) const return false; } +//virtual +void LLImageGL::forceImmediateUpdate() +{ + return ; +} void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes ) { @@ -498,7 +503,7 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { // LLFastTimer t1(LLFastTimer::FTM_TEMP1); - + llpushcallstacks ; bool is_compressed = false; if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) { @@ -519,6 +524,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) // are stored BEFORE the largest image for (S32 d=mCurrentDiscardLevel; d<=mMaxDiscardLevel; d++) { + S32 w = getWidth(d); S32 h = getHeight(d); S32 gl_level = d-mCurrentDiscardLevel; @@ -529,7 +535,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) if (is_compressed) { // LLFastTimer t2(LLFastTimer::FTM_TEMP4); - S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); + S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); stop_glerror(); } @@ -543,7 +549,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } - glTexImage2D(mTarget, gl_level, mFormatInternal, w, h, 0, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in); + LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in); + if (gl_level == 0) + { + analyzeAlpha(data_in, w, h); + } updatePickMask(w, h, data_in); if(mFormatSwapBytes) @@ -575,10 +585,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) S32 w = getWidth(mCurrentDiscardLevel); S32 h = getHeight(mCurrentDiscardLevel); - glTexImage2D(mTarget, 0, mFormatInternal, - w, h, 0, + LLImageGL::setManualImage(mTarget, 0, mFormatInternal, + w, h, mFormatPrimary, mFormatType, data_in); + analyzeAlpha(data_in, w, h); stop_glerror(); updatePickMask(w, h, data_in); @@ -630,7 +641,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } - glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data); + LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data); + if (m == 0) + { + analyzeAlpha(data_in, w, h); + } stop_glerror(); if (m == 0) { @@ -663,7 +678,7 @@ 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; + mHasMipMaps = true; } else { @@ -684,8 +699,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } - glTexImage2D(mTarget, 0, mFormatInternal, w, h, 0, + LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, mFormatPrimary, mFormatType, (GLvoid *)data_in); + analyzeAlpha(data_in, w, h); + updatePickMask(w, h, data_in); stop_glerror(); @@ -697,14 +714,16 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } } - mHasMipMaps = FALSE; + mHasMipMaps = false; } stop_glerror(); mGLTextureCreated = true; + llpushcallstacks ; } BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) { + llpushcallstacks ; if (!width || !height) { return TRUE; @@ -780,6 +799,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); + gGL.getTexUnit(0)->disable(); stop_glerror(); if(mFormatSwapBytes) @@ -792,6 +812,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 stop_glerror(); mGLTextureCreated = true; } + llpushcallstacks ; return TRUE; } @@ -816,6 +837,24 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_ } } +// static +void LLImageGL::generateTextures(S32 numTextures, U32 *textures) +{ + glGenTextures(numTextures, (GLuint*)textures); +} + +// static +void LLImageGL::deleteTextures(S32 numTextures, U32 *textures) +{ + glDeleteTextures(numTextures, (GLuint*)textures); +} + +// static +void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels) +{ + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels); +} + //create an empty GL texture: just create a texture name //the texture is assiciate with some image by calling glTexImage outside LLImageGL BOOL LLImageGL::createGLTexture() @@ -848,6 +887,7 @@ BOOL LLImageGL::createGLTexture() BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/) { + llpushcallstacks ; if (gGLManager.mIsDisabled) { llwarns << "Trying to create a texture while GL is disabled!" << llendl; @@ -908,6 +948,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) { + llpushcallstacks ; llassert(data_in); if (discard_level < 0) @@ -924,7 +965,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ return TRUE; } - GLuint old_name = mTexName; + U32 old_name = mTexName; // S32 old_discard = mCurrentDiscardLevel; if (usename != 0) @@ -933,7 +974,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ } else { - glGenTextures(1, (GLuint*)&mTexName); + LLImageGL::generateTextures(1, &mTexName); stop_glerror(); { // LLFastTimer t1(LLFastTimer::FTM_TEMP6); @@ -963,9 +1004,11 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ setImage(data_in, data_hasmips); - setClamp(mClampS, mClampT); - setMipFilterNearest(mMagFilterNearest); - + // Set texture options to our defaults. + gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps); + gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode); + gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption); + // things will break if we don't unbind after creation gGL.getTexUnit(0)->unbind(mBindTarget); stop_glerror(); @@ -973,16 +1016,18 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ if (old_name != 0) { sGlobalTextureMemory -= mTextureMemory; - glDeleteTextures(1, &old_name); + LLImageGL::deleteTextures(1, &old_name); stop_glerror(); } mTextureMemory = getMipBytes(discard_level); sGlobalTextureMemory += mTextureMemory; - + setActive() ; + // mark this as bound at this point, so we don't throw it out immediately mLastBindTime = sLastFrameTime; + llpushcallstacks ; return TRUE; } @@ -1055,6 +1100,7 @@ BOOL LLImageGL::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_h BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) { + llpushcallstacks ; if (discard_level < 0) { discard_level = mCurrentDiscardLevel; @@ -1069,7 +1115,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre //explicitly unbind texture gGL.getTexUnit(0)->unbind(mBindTarget); - llverify(gGL.getTexUnit(0)->bind(this)); + llverify(gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName)); //debug code, leave it there commented. //checkTexSize() ; @@ -1157,7 +1203,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre return FALSE ; } //----------------------------------------------------------------------------------------------- - + llpushcallstacks ; return TRUE ; } @@ -1179,8 +1225,10 @@ void LLImageGL::destroyGLTexture() sGlobalTextureMemory -= mTextureMemory; mTextureMemory = 0; - glDeleteTextures(1, (GLuint*)&mTexName); + LLImageGL::deleteTextures(1, &mTexName); + mTextureState = DELETED ; mTexName = 0; + mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. mGLTextureCreated = FALSE ; stop_glerror(); } @@ -1188,89 +1236,35 @@ void LLImageGL::destroyGLTexture() //---------------------------------------------------------------------------- -void LLImageGL::glClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr) -{ - glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT); - glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT); - glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT); -} - -void LLImageGL::glClamp (BOOL clamps, BOOL clampt) +void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) { - if (mTexName != 0) + if (mAddressMode != mode) { - glTexParameteri (LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT); - glTexParameteri (LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_WRAP_T, clampt ? GL_CLAMP_TO_EDGE : GL_REPEAT); + mTexOptionsDirty = true; + mAddressMode = mode; } -} -void LLImageGL::setClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr) -{ - mClampS = clamps; - mClampT = clampt; - mClampR = clampr; - glClampCubemap (clamps, clampt, clampr); -} - -void LLImageGL::setClamp(BOOL clamps, BOOL clampt) -{ - mClampS = clamps; - mClampT = clampt; - glClamp (clamps, clampt); -} - -void LLImageGL::overrideClamp (BOOL clamps, BOOL clampt) -{ - glClamp (clamps, clampt); -} - -void LLImageGL::restoreClamp (void) -{ - glClamp (mClampS, mClampT); + if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) + { + gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureAddressMode(mode); + mTexOptionsDirty = false; + } } -void LLImageGL::setMipFilterNearest(BOOL mag_nearest, BOOL min_nearest) +void LLImageGL::setFilteringOption(LLTexUnit::eTextureFilterOptions option) { - mMagFilterNearest = mag_nearest; - mMinFilterNearest = min_nearest; + if (mFilterOption != option) + { + mTexOptionsDirty = true; + mFilterOption = option; + } - if (mTexName != 0) + if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) { - if (mMinFilterNearest) - { - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - else if (mHasMipMaps) - { - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - else - { - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - if (mMagFilterNearest) - { - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - else - { - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - if (gGLManager.mHasAnisotropic) - { - if (sGlobalUseAnisotropic && !mMagFilterNearest) - { - F32 largest_anisotropy; - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_anisotropy); - glTexParameterf(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_anisotropy); - } - else - { - glTexParameterf(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f); - } - } - stop_glerror(); - } + gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureFilteringOption(option); + mTexOptionsDirty = false; + } + stop_glerror(); } BOOL LLImageGL::getIsResident(BOOL test_now) @@ -1357,6 +1351,115 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b mBindTarget = bind_target; } +void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h) +{ + if (mFormatType != GL_UNSIGNED_BYTE) + { + llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl; + } + + U32 stride = 0; + switch (mFormatPrimary) + { + case GL_LUMINANCE: + case GL_ALPHA: + stride = 1; + break; + case GL_LUMINANCE_ALPHA: + stride = 2; + break; + case GL_RGB: + //no alpha + mIsMask = FALSE; + return; + case GL_RGBA: + stride = 4; + break; + default: + llwarns << "Cannot analyze alpha of image with primary format " << std::hex << mFormatPrimary << std::dec << llendl; + return; + } + + U32 length = w * h; + const GLubyte* current = ((const GLubyte*) data_in)+stride-1; + + S32 sample[16]; + memset(sample, 0, sizeof(S32)*16); + + for (U32 i = 0; i < length; i++) + { + ++sample[*current/16]; + current += stride; + } + + U32 total = 0; + for (U32 i = 4; i < 11; i++) + { + total += sample[i]; + } + + if (total > length/16) + { + mIsMask = FALSE; + } + else + { + mIsMask = TRUE; + } +} + +BOOL LLImageGL::isDeleted() +{ + return mTextureState == DELETED ; +} + +BOOL LLImageGL::isInactive() +{ + return mTextureState == INACTIVE ; +} + +BOOL LLImageGL::isDeletionCandidate() +{ + return mTextureState == DELETION_CANDIDATE ; +} + +void LLImageGL::setDeletionCandidate() +{ + if(mTexName && (mTextureState == INACTIVE)) + { + mTextureState = DELETION_CANDIDATE ; + } +} + +void LLImageGL::forceActive() +{ + mTextureState = ACTIVE ; +} + +void LLImageGL::setActive() +{ + if(mTextureState != NO_DELETE) + { + mTextureState = ACTIVE ; + } +} + +//set the texture inactive +void LLImageGL::setInactive() +{ + if(mTexName && (mTextureState == ACTIVE) && !getBoundRecently()) + { + mTextureState = INACTIVE ; + } +} + +//set the texture to stay in memory +void LLImageGL::setNoDelete() +{ + mTextureState = NO_DELETE ; +} + +//---------------------------------------------------------------------------- void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { if (mFormatType != GL_UNSIGNED_BYTE || @@ -1469,7 +1572,7 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) llassert(w > 0 && h > 0 && cur_mip_data); U8 test = cur_mip_data[w*h*mComponents-1]; { - glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data); + LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data); stop_glerror(); } if (prev_mip_data && prev_mip_data != rawdata) diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index cb565939d9..4f737bcaae 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -46,6 +46,7 @@ class LLImageGL : public LLRefCount { + friend class LLTexUnit; public: // Size calculation static S32 dataFormatBits(S32 dataformat); @@ -80,17 +81,22 @@ public: protected: virtual ~LLImageGL(); -private: - void glClamp (BOOL clamps, BOOL clampt); - void glClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr = FALSE); + void analyzeAlpha(const void* data_in, S32 w, S32 h); public: virtual void dump(); // debugging info to llinfos virtual bool bindError(const S32 stage = 0) const; virtual bool bindDefaultImage(const S32 stage = 0) const; + virtual void forceImmediateUpdate() ; void setSize(S32 width, S32 height, S32 ncomponents); + // 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); + static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels); + BOOL createGLTexture() ; BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0); BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); @@ -103,14 +109,9 @@ public: // Read back a raw image for this discard level, if it exists BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok); void destroyGLTexture(); - - void setClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr = FALSE); - void setClamp(BOOL clamps, BOOL clampt); - void overrideClamp (BOOL clamps, BOOL clampt); - void restoreClamp (void); - void setMipFilterNearest(BOOL mag_nearest, BOOL min_nearest = FALSE); + void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); - void dontDiscard() { mDontDiscard = 1; } + void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; } S32 getDiscardLevel() const { return mCurrentDiscardLevel; } S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; } @@ -124,15 +125,12 @@ public: S32 getMipBytes(S32 discard_level = -1) const; BOOL getBoundRecently() const; LLGLenum getPrimaryFormat() const { return mFormatPrimary; } - - BOOL getClampS() const { return mClampS; } - BOOL getClampT() const { return mClampT; } - BOOL getClampR() const { return mClampR; } - BOOL getMipFilterNearest() const { return mMagFilterNearest; } - + BOOL getHasGLTexture() const { return mTexName != 0; } LLGLuint getTexName() const { return mTexName; } + BOOL getIsAlphaMask() const { return mIsMask; } + BOOL getIsResident(BOOL test_now = FALSE); // not const void setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target); @@ -152,6 +150,27 @@ public: BOOL getMask(const LLVector2 &tc); void checkTexSize() const ; + + // Sets the addressing mode used to sample the texture + // (such as wrapping, mirrored wrapping, and clamp) + // Note: this actually gets set the next time the texture is bound. + void setAddressMode(LLTexUnit::eTextureAddressMode mode); + LLTexUnit::eTextureAddressMode getAddressMode(void) const { return mAddressMode; } + + // Sets the filtering options used to sample the texture + // (such as point sampling, bilinear interpolation, mipmapping, and anisotropic filtering) + // Note: this actually gets set the next time the texture is bound. + void setFilteringOption(LLTexUnit::eTextureFilterOptions option); + LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; } + + BOOL isDeleted() ; + BOOL isInactive() ; + BOOL isDeletionCandidate(); + void setDeletionCandidate() ; + void setInactive() ; + void setActive() ; + void forceActive() ; + void setNoDelete() ; protected: void init(BOOL usemipmaps); @@ -166,9 +185,10 @@ private: LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel S8 mUseMipMaps; - S8 mHasMipMaps; S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents) S8 mAutoGenMips; + + BOOL mIsMask; bool mGLTextureCreated ; LLGLuint mTexName; @@ -179,6 +199,7 @@ private: 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; LLGLboolean mIsResident; @@ -186,17 +207,27 @@ protected: S8 mMaxDiscardLevel; S8 mDontDiscard; // Keep full res version of this image (for UI, etc) - S8 mClampS; // Need to save clamp state - S8 mClampT; - S8 mClampR; - S8 mMagFilterNearest; // if TRUE, set magfilter to GL_NEAREST - S8 mMinFilterNearest; // if TRUE, set minfilter to GL_NEAREST + bool mTexOptionsDirty; + LLTexUnit::eTextureAddressMode mAddressMode; // Defaults to TAM_WRAP + LLTexUnit::eTextureFilterOptions mFilterOption; // Defaults to TFO_TRILINEAR + LLGLint mFormatInternal; // = GL internalformat LLGLenum mFormatPrimary; // = GL format (pixel data format) LLGLenum mFormatType; BOOL mFormatSwapBytes;// if true, use glPixelStorei(GL_UNPACK_SWAP_BYTES, 1) +protected: + typedef enum + { + DELETED = 0, //removed from memory + DELETION_CANDIDATE, //ready to be removed from memory + INACTIVE, //not be used for the last certain period (i.e., 30 seconds). + ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds). + NO_DELETE = 99 //stay in memory, can not be removed. + } LLGLTexureState; + LLGLTexureState mTextureState ; + // STATICS public: static std::set<LLImageGL*> sImageList; diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index 940abb54d4..7f4be6a866 100644 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -208,7 +208,7 @@ void LLPostProcess::applyShaders(void) /// If any of the above shaders have been called update the frame buffer; if (tweaks.useColorFilter()) { - GLuint tex = mSceneRenderTexture->getTexName() ; + U32 tex = mSceneRenderTexture->getTexName() ; copyFrameBuffer(tex, screenW, screenH); } applyNightVisionShader(); @@ -218,7 +218,7 @@ void LLPostProcess::applyShaders(void) /// If any of the above shaders have been called update the frame buffer; if (tweaks.useColorFilter().asBoolean() || tweaks.useNightVisionShader().asBoolean()) { - GLuint tex = mSceneRenderTexture->getTexName() ; + U32 tex = mSceneRenderTexture->getTexName() ; copyFrameBuffer(tex, screenW, screenH); } applyBloomShader(); @@ -360,7 +360,7 @@ void LLPostProcess::doEffects(void) /// Copy the screen buffer to the render texture { - GLuint tex = mSceneRenderTexture->getTexName() ; + U32 tex = mSceneRenderTexture->getTexName() ; copyFrameBuffer(tex, screenW, screenH); } @@ -386,7 +386,7 @@ void LLPostProcess::doEffects(void) checkError(); } -void LLPostProcess::copyFrameBuffer(GLuint & texture, unsigned int width, unsigned int height) +void LLPostProcess::copyFrameBuffer(U32 & texture, unsigned int width, unsigned int height) { gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, texture); glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, width, height, 0); @@ -503,10 +503,8 @@ void LLPostProcess::createTexture(LLPointer<LLImageGL>& texture, unsigned int wi gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, texture->getTexName()); glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); } } @@ -523,11 +521,9 @@ void LLPostProcess::createNoiseTexture(LLPointer<LLImageGL>& texture) if(texture->createGLTexture()) { gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture->getTexName()); - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); } } diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h index e5e34d920c..009e4bd415 100644 --- a/indra/llrender/llpostprocess.h +++ b/indra/llrender/llpostprocess.h @@ -256,7 +256,7 @@ private: /// OpenGL Helper Functions void getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog); void createTexture(LLPointer<LLImageGL>& texture, unsigned int width, unsigned int height); - void copyFrameBuffer(GLuint & texture, unsigned int width, unsigned int height); + void copyFrameBuffer(U32 & texture, unsigned int width, unsigned int height); void createNoiseTexture(LLPointer<LLImageGL>& texture); bool checkError(void); void checkShaderError(GLhandleARB shader); diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index c7068133d2..bee41f556e 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -75,7 +75,7 @@ static GLenum sGLCompareFunc[] = GL_GREATER }; -const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD; +const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD0; static GLenum sGLBlendFactor[] = { @@ -96,7 +96,8 @@ LLTexUnit::LLTexUnit(S32 index) mCurrColorOp(TBO_MULT), mCurrAlphaOp(TBO_MULT), mCurrColorSrc1(TBS_TEX_COLOR), mCurrColorSrc2(TBS_PREV_COLOR), mCurrAlphaSrc1(TBS_TEX_ALPHA), mCurrAlphaSrc2(TBS_PREV_ALPHA), -mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0) +mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), +mHasMipMaps(false) { llassert_always(index < LL_NUM_TEXTURE_LAYERS); mIndex = index; @@ -176,8 +177,9 @@ void LLTexUnit::disable(void) } } -bool LLTexUnit::bind(const LLImageGL* texture, bool forceBind) +bool LLTexUnit::bind(LLImageGL* texture, bool forceBind) { + stop_glerror(); if (mIndex < 0) return false; gGL.flush(); @@ -190,15 +192,30 @@ bool LLTexUnit::bind(const LLImageGL* texture, bool forceBind) if (!texture->getTexName()) //if texture does not exist { + //if deleted, will re-generate it immediately + texture->forceImmediateUpdate() ; + return texture->bindDefaultImage(mIndex); } - // Disabled caching of binding state. - activate(); - enable(texture->getTarget()); - mCurrTexture = texture->getTexName(); - glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture); - texture->updateBindStats(); - return true; + + if (texture != NULL && ((mCurrTexture != texture->getTexName()) || forceBind)) + { + activate(); + enable(texture->getTarget()); + mCurrTexture = texture->getTexName(); + glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture); + texture->updateBindStats(); + texture->setActive() ; + mHasMipMaps = texture->mHasMipMaps; + if (texture->mTexOptionsDirty) + { + texture->mTexOptionsDirty = false; + setTextureAddressMode(texture->mAddressMode); + setTextureFilteringOption(texture->mFilterOption); + } + return true; + } + return false; } bool LLTexUnit::bind(LLCubeMap* cubeMap) @@ -207,8 +224,7 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) gGL.flush(); - // Disabled caching of binding state. - if (cubeMap != NULL) + if (cubeMap != NULL && mCurrTexture != cubeMap->mImages[0]->getTexName()) { if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) { @@ -216,8 +232,14 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) enable(LLTexUnit::TT_CUBE_MAP); mCurrTexture = cubeMap->mImages[0]->getTexName(); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mCurrTexture); + mHasMipMaps = cubeMap->mImages[0]->mHasMipMaps; cubeMap->mImages[0]->updateBindStats(); - cubeMap->mImages[0]->setMipFilterNearest (FALSE, FALSE); + if (cubeMap->mImages[0]->mTexOptionsDirty) + { + cubeMap->mImages[0]->mTexOptionsDirty = false; + setTextureAddressMode(cubeMap->mImages[0]->mAddressMode); + setTextureFilteringOption(cubeMap->mImages[0]->mFilterOption); + } return true; } else @@ -228,6 +250,8 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) return false; } +// LLRenderTarget is unavailible on the mapserver since it uses FBOs. +#if !LL_MESA_HEADLESS bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) { if (mIndex < 0) return false; @@ -245,23 +269,26 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) return true; } +#endif // LL_MESA_HEADLESS -bool LLTexUnit::bindManual(eTextureType type, U32 texture) +bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) { - if (mIndex < 0) return false; + if (mIndex < 0 || mCurrTexture == texture) return false; - // Disabled caching of binding state. gGL.flush(); activate(); enable(type); mCurrTexture = texture; glBindTexture(sGLTextureType[type], texture); + mHasMipMaps = hasMips; return true; } void LLTexUnit::unbind(eTextureType type) { + stop_glerror(); + if (mIndex < 0) return; // Disabled caching of binding state. @@ -277,17 +304,57 @@ void LLTexUnit::unbind(eTextureType type) void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode) { - if (mIndex < 0) return; + if (mIndex < 0 || mCurrTexture == 0) return; + + activate(); - if (true) + glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]); + glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]); + if (mCurrTexType == TT_CUBE_MAP) { - activate(); + glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]); + } +} + +void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option) +{ + if (mIndex < 0 || mCurrTexture == 0) return; + + if (option == TFO_POINT) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + if (option >= TFO_TRILINEAR && mHasMipMaps) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } + else if (option >= TFO_BILINEAR) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } - glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]); - glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]); - if (mCurrTexType == TT_CUBE_MAP) + if (gGLManager.mHasAnisotropic) + { + if (LLImageGL::sGlobalUseAnisotropic && option == TFO_ANISOTROPIC) { - glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]); + if (gGL.mMaxAnisotropy < 1.f) + { + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGL.mMaxAnisotropy); + } + glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, gGL.mMaxAnisotropy); + } + else + { + glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f); } } } @@ -590,12 +657,13 @@ void LLTexUnit::debugTextureUnit(void) LLRender::LLRender() -: mDirty(false), mCount(0), mMode(LLRender::TRIANGLES) +: mDirty(false), mCount(0), mMode(LLRender::TRIANGLES), + mMaxAnisotropy(0.f) { mBuffer = new LLVertexBuffer(immediate_mask, 0); mBuffer->allocateBuffer(4096, 0, TRUE); mBuffer->getVertexStrider(mVerticesp); - mBuffer->getTexCoordStrider(mTexcoordsp); + mBuffer->getTexCoord0Strider(mTexcoordsp); mBuffer->getColorStrider(mColorsp); mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS); @@ -688,7 +756,10 @@ void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB mCurrColorMask[2] = writeColorB; mCurrColorMask[3] = writeAlpha; - glColorMask(writeColorR, writeColorG, writeColorB, writeAlpha); + glColorMask(writeColorR ? GL_TRUE : GL_FALSE, + writeColorG ? GL_TRUE : GL_FALSE, + writeColorB ? GL_TRUE : GL_FALSE, + writeAlpha ? GL_TRUE : GL_FALSE); } void LLRender::setSceneBlendType(eBlendType type) @@ -768,6 +839,14 @@ bool LLRender::verifyTexUnitActive(U32 unitToVerify) } } +void LLRender::clearErrors() +{ + while (glGetError()) + { + //loop until no more error flags left + } +} + void LLRender::begin(const GLuint& mode) { if (mode != mMode) @@ -853,13 +932,14 @@ void LLRender::flush() mBuffer->setBuffer(immediate_mask); mBuffer->drawArrays(mMode, 0, mCount); - + mVerticesp[0] = mVerticesp[mCount]; mTexcoordsp[0] = mTexcoordsp[mCount]; mColorsp[0] = mColorsp[mCount]; mCount = 0; } } + void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) { //the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095] diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 752a4e0b37..437c715c2f 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -71,6 +71,14 @@ public: TAM_CLAMP // No texture type is currently enabled } eTextureAddressMode; + typedef enum + { // Note: If mipmapping or anisotropic are not enabled or supported it should fall back gracefully + TFO_POINT = 0, // Equal to: min=point, mag=point, mip=none. + TFO_BILINEAR, // Equal to: min=linear, mag=linear, mip=point. + TFO_TRILINEAR, // Equal to: min=linear, mag=linear, mip=linear. + TFO_ANISOTROPIC // Equal to: min=anisotropic, max=anisotropic, mip=linear. + } eTextureFilterOptions; + typedef enum { TB_REPLACE = 0, @@ -131,30 +139,43 @@ public: // Sets this tex unit to be the currently active one void activate(void); - // Enables this texture unit for the given texture type (automatically disables any previously enabled texture type) + // Enables this texture unit for the given texture type + // (automatically disables any previously enabled texture type) void enable(eTextureType type); + // Disables the current texture unit void disable(void); // Binds the LLImageGL to this texture unit // (automatically enables the unit for the LLImageGL's texture type) - bool bind(const LLImageGL* texture, bool forceBind = false); + bool bind(LLImageGL* texture, bool forceBind = false); // Binds a cubemap to this texture unit // (automatically enables the texture unit for cubemaps) bool bind(LLCubeMap* cubeMap); - // Binds a render target to this texture unit (automatically enables the texture unit for the RT's texture type) + // Binds a render target to this texture unit + // (automatically enables the texture unit for the RT's texture type) bool bind(LLRenderTarget * renderTarget, bool bindDepth = false); - // Manually binds a texture to the texture unit (automatically enables the tex unit for the given texture type) - bool bindManual(eTextureType type, U32 texture); + // Manually binds a texture to the texture unit + // (automatically enables the tex unit for the given texture type) + bool bindManual(eTextureType type, U32 texture, bool hasMips = false); - // Unbinds the currently bound texture of the given type (only if there's a texture of the given type currently bound) + // Unbinds the currently bound texture of the given type + // (only if there's a texture of the given type currently bound) void unbind(eTextureType type); + // Sets the addressing mode used to sample the texture + // Warning: this stays set for the bound texture forever, + // make sure you want to permanently change the address mode for the bound texture. void setTextureAddressMode(eTextureAddressMode mode); + // Sets the filtering options used to sample the texture + // Warning: this stays set for the bound texture forever, + // make sure you want to permanently change the filtering for the bound texture. + void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option); + void setTextureBlendType(eTextureBlendType type); inline void setTextureColorBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_COLOR) @@ -166,6 +187,12 @@ public: static U32 getInternalType(eTextureType type); + U32 getCurrTexture(void) { return mCurrTexture; } + + eTextureType getCurrType(void) { return mCurrTexType; } + + void setHasMipMaps(bool hasMips) { mHasMipMaps = hasMips; } + protected: S32 mIndex; U32 mCurrTexture; @@ -179,6 +206,7 @@ protected: eTextureBlendSrc mCurrAlphaSrc2; S32 mCurrColorScale; S32 mCurrAlphaScale; + bool mHasMipMaps; void debugTextureUnit(void); void setColorScale(S32 scale); @@ -292,6 +320,8 @@ public: void debugTexUnits(void); + void clearErrors(); + struct Vertex { GLfloat v[3]; @@ -316,6 +346,8 @@ private: LLStrider<LLColor4U> mColorsp; std::vector<LLTexUnit*> mTexUnits; LLTexUnit* mDummyTexUnit; + + F32 mMaxAnisotropy; }; extern F64 gGLModelView[16]; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 623c1df4db..b7f31779ca 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -37,6 +37,24 @@ #include "llgl.h" +void check_framebuffer_status() +{ + if (gDebugGL) + { + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + switch (status) + { + case GL_FRAMEBUFFER_COMPLETE_EXT: + break; + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + llerrs << "WTF?" << llendl; + break; + default: + llerrs << "WTF?" << llendl; + } + } +} + BOOL LLRenderTarget::sUseFBO = FALSE; LLRenderTarget::LLRenderTarget() : @@ -48,7 +66,9 @@ LLRenderTarget::LLRenderTarget() : mStencil(0), mUseDepth(FALSE), mRenderDepth(FALSE), - mUsage(LLTexUnit::TT_TEXTURE) + mUsage(LLTexUnit::TT_TEXTURE), + mSamples(0), + mSampleBuffer(NULL) { } @@ -57,40 +77,26 @@ LLRenderTarget::~LLRenderTarget() release(); } -void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, LLTexUnit::eTextureType usage, BOOL use_fbo) + +void LLRenderTarget::setSampleBuffer(LLMultisampleBuffer* buffer) +{ + mSampleBuffer = buffer; +} + +void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo) { stop_glerror(); mResX = resx; mResY = resy; + mStencil = stencil; mUsage = usage; mUseDepth = depth; - release(); - - glGenTextures(1, (GLuint *) &mTex); - gGL.getTexUnit(0)->bindManual(mUsage, mTex); - glTexImage2D(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, 0, color_fmt, GL_UNSIGNED_BYTE, NULL); - - glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - if (mUsage != LLTexUnit::TT_RECT_TEXTURE) - { - glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); - glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - } - else - { - // ATI doesn't support mirrored repeat for rectangular textures. - glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - stop_glerror(); + release(); if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject) { - if (depth) { stop_glerror(); @@ -100,37 +106,141 @@ void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, LLT glGenFramebuffersEXT(1, (GLuint *) &mFBO); + if (mDepth) + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + if (mStencil) + { + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth); + stop_glerror(); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth); + stop_glerror(); + } + else + { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0); + stop_glerror(); + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + stop_glerror(); + } - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + addColorAttachment(color_fmt); +} - stop_glerror(); +void LLRenderTarget::addColorAttachment(U32 color_fmt) +{ + if (color_fmt == 0) + { + return; + } - if (mDepth) - { - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0); - stop_glerror(); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0); - stop_glerror(); - } + U32 offset = mTex.size(); + if (offset >= 4 || + offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers)) + { + llerrs << "Too many color attachments!" << llendl; + } - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - LLTexUnit::getInternalType(mUsage), mTex, 0); - stop_glerror(); + U32 tex; + LLImageGL::generateTextures(1, &tex); + gGL.getTexUnit(0)->bindManual(mUsage, tex); + + stop_glerror(); + + LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + stop_glerror(); + + if (offset == 0) + { + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + else + { //don't filter data attachments + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + if (mUsage != LLTexUnit::TT_RECT_TEXTURE) + { + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR); + } + else + { + // ATI doesn't support mirrored repeat for rectangular textures. + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + } + if (mFBO) + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset, + LLTexUnit::getInternalType(mUsage), tex, 0); + stop_glerror(); + + check_framebuffer_status(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - stop_glerror(); } + + mTex.push_back(tex); + } void LLRenderTarget::allocateDepth() { - glGenTextures(1, (GLuint *) &mDepth); - gGL.getTexUnit(0)->bindManual(mUsage, mDepth); - U32 internal_type = LLTexUnit::getInternalType(mUsage); - glTexParameteri(internal_type, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(internal_type, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage2D(internal_type, 0, GL_DEPTH24_STENCIL8_EXT, mResX, mResY, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL); + if (mStencil) + { + //use render buffers where stencil buffers are in play + glGenRenderbuffersEXT(1, (GLuint *) &mDepth); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, mResX, mResY); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + } + else + { + LLImageGL::generateTextures(1, &mDepth); + 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); + } +} + +void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target) +{ + if (!mFBO || !target.mFBO) + { + llerrs << "Cannot share depth buffer between non FBO render targets." << llendl; + } + + if (mDepth) + { + stop_glerror(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, target.mFBO); + stop_glerror(); + + if (mStencil) + { + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth); + stop_glerror(); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth); + stop_glerror(); + } + else + { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0); + stop_glerror(); + if (mStencil) + { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0); + stop_glerror(); + } + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + target.mUseDepth = TRUE; + } } void LLRenderTarget::release() @@ -141,24 +251,63 @@ void LLRenderTarget::release() mFBO = 0; } - if (mTex) + if (mTex.size() > 0) { - glDeleteTextures(1, (GLuint *) &mTex); - mTex = 0; + LLImageGL::deleteTextures(mTex.size(), &mTex[0]); + mTex.clear(); } if (mDepth) { - glDeleteTextures(1, (GLuint *) &mDepth); + if (mStencil) + { + glDeleteRenderbuffersEXT(1, (GLuint*) &mDepth); + stop_glerror(); + } + else + { + LLImageGL::deleteTextures(1, &mDepth); + stop_glerror(); + } mDepth = 0; } + + mSampleBuffer = NULL; } void LLRenderTarget::bindTarget() { if (mFBO) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + stop_glerror(); + if (mSampleBuffer) + { + mSampleBuffer->bindTarget(this); + stop_glerror(); + } + else + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + stop_glerror(); + if (gGLManager.mHasDrawBuffers) + { //setup multiple render targets + GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT, + GL_COLOR_ATTACHMENT1_EXT, + GL_COLOR_ATTACHMENT2_EXT, + GL_COLOR_ATTACHMENT3_EXT}; + glDrawBuffersARB(mTex.size(), drawbuffers); + } + + if (mTex.empty()) + { //no color buffer to draw to + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + + check_framebuffer_status(); + + stop_glerror(); + } } glViewport(0, 0, mResX, mResY); @@ -173,7 +322,7 @@ void LLRenderTarget::unbindTarget() } } -void LLRenderTarget::clear() +void LLRenderTarget::clear(U32 mask_in) { U32 mask = GL_COLOR_BUFFER_BIT; if (mUseDepth) @@ -182,15 +331,36 @@ void LLRenderTarget::clear() } if (mFBO) { - glClear(mask); + check_framebuffer_status(); + stop_glerror(); + glClear(mask & mask_in); + stop_glerror(); } else { LLGLEnable scissor(GL_SCISSOR_TEST); glScissor(0, 0, mResX, mResY); stop_glerror(); - glClear(mask); + glClear(mask & mask_in); + } +} + +U32 LLRenderTarget::getTexture(U32 attachment) const +{ + if (attachment > mTex.size()-1) + { + llerrs << "Invalid attachment index." << llendl; + } + return mTex[attachment]; +} + +void LLRenderTarget::bindTexture(U32 index, S32 channel) +{ + if (index > mTex.size()-1) + { + llerrs << "Invalid attachment index." << llendl; } + gGL.getTexUnit(channel)->bindManual(mUsage, mTex[index]); } void LLRenderTarget::flush(BOOL fetch_depth) @@ -211,16 +381,87 @@ void LLRenderTarget::flush(BOOL fetch_depth) gGL.getTexUnit(0)->bind(this, true); glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8_EXT, 0, 0, mResX, mResY, 0); } + + gGL.getTexUnit(0)->disable(); + } + else + { +#if !LL_DARWIN + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + if (mSampleBuffer) + { + LLGLEnable multisample(GL_MULTISAMPLE_ARB); + stop_glerror(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + stop_glerror(); + check_framebuffer_status(); + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, mSampleBuffer->mFBO); + check_framebuffer_status(); + + stop_glerror(); + glBlitFramebufferEXT(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); + stop_glerror(); + + if (mTex.size() > 1) + { + for (U32 i = 1; i < mTex.size(); ++i) + { + glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + LLTexUnit::getInternalType(mUsage), mTex[i], 0); + stop_glerror(); + glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, mSampleBuffer->mTex[i]); + stop_glerror(); + glBlitFramebufferEXT(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT, GL_NEAREST); + stop_glerror(); + } + + for (U32 i = 0; i < mTex.size(); ++i) + { + glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i, + LLTexUnit::getInternalType(mUsage), mTex[i], 0); + stop_glerror(); + glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i, GL_RENDERBUFFER_EXT, mSampleBuffer->mTex[i]); + stop_glerror(); + } + } + } +#endif + + 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) +{ +#if !LL_DARWIN + if (!source.mFBO || !mFBO) + { + llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl; + } + + if (mSampleBuffer) + { + mSampleBuffer->copyContents(source, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } else { + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO); + + glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } +#endif } BOOL LLRenderTarget::isComplete() const { - return (mTex || mDepth) ? TRUE : FALSE; + return (!mTex.empty() || mDepth) ? TRUE : FALSE; } void LLRenderTarget::getViewport(S32* viewport) @@ -231,3 +472,191 @@ void LLRenderTarget::getViewport(S32* viewport) viewport[3] = mResY; } +//================================================== +// LLMultisampleBuffer implementation +//================================================== +LLMultisampleBuffer::LLMultisampleBuffer() +{ + +} + +LLMultisampleBuffer::~LLMultisampleBuffer() +{ + releaseSampleBuffer(); +} + +void LLMultisampleBuffer::releaseSampleBuffer() +{ + if (mFBO) + { + glDeleteFramebuffersEXT(1, (GLuint *) &mFBO); + mFBO = 0; + } + + if (mTex.size() > 0) + { + glDeleteRenderbuffersEXT(mTex.size(), (GLuint *) &mTex[0]); + mTex.clear(); + } + + if (mDepth) + { + glDeleteRenderbuffersEXT(1, (GLuint *) &mDepth); + mDepth = 0; + } +} + +void LLMultisampleBuffer::bindTarget() +{ + bindTarget(this); +} + +void LLMultisampleBuffer::bindTarget(LLRenderTarget* ref) +{ + if (!ref) + { + ref = this; + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + if (gGLManager.mHasDrawBuffers) + { //setup multiple render targets + GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT, + GL_COLOR_ATTACHMENT1_EXT, + GL_COLOR_ATTACHMENT2_EXT, + GL_COLOR_ATTACHMENT3_EXT}; + glDrawBuffersARB(ref->mTex.size(), drawbuffers); + } + + check_framebuffer_status(); + + glViewport(0, 0, mResX, mResY); + +} + +void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo ) +{ + allocate(resx,resy,color_fmt,depth,stencil,usage,use_fbo,2); +} + +void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo, U32 samples ) +{ + stop_glerror(); + mResX = resx; + mResY = resy; + + mUsage = usage; + mUseDepth = depth; + mStencil = stencil; + + releaseSampleBuffer(); + + if (!gGLManager.mHasFramebufferMultisample) + { + llerrs << "Attempting to allocate unsupported render target type!" << llendl; + } + + mSamples = samples; + + if (mSamples <= 1) + { + llerrs << "Cannot create a multisample buffer with less than 2 samples." << llendl; + } + + stop_glerror(); + + if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject) + { + + if (depth) + { + stop_glerror(); + allocateDepth(); + stop_glerror(); + } + + glGenFramebuffersEXT(1, (GLuint *) &mFBO); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + + if (mDepth) + { + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth); + if (mStencil) + { + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth); + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + + stop_glerror(); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + stop_glerror(); + } + + addColorAttachment(color_fmt); +} + +void LLMultisampleBuffer::addColorAttachment(U32 color_fmt) +{ +#if !LL_DARWIN + if (color_fmt == 0) + { + return; + } + + U32 offset = mTex.size(); + if (offset >= 4 || + offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers)) + { + llerrs << "Too many color attachments!" << llendl; + } + + U32 tex; + glGenRenderbuffersEXT(1, &tex); + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, tex); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, color_fmt, mResX, mResY); + stop_glerror(); + + if (mFBO) + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset, GL_RENDERBUFFER_EXT, tex); + stop_glerror(); + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + switch (status) + { + case GL_FRAMEBUFFER_COMPLETE_EXT: + break; + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + llerrs << "WTF?" << llendl; + break; + default: + llerrs << "WTF?" << llendl; + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + + mTex.push_back(tex); +#endif +} + +void LLMultisampleBuffer::allocateDepth() +{ +#if !LL_DARWIN + glGenRenderbuffersEXT(1, (GLuint* ) &mDepth); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth); + if (mStencil) + { + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH24_STENCIL8_EXT, mResX, mResY); + } + else + { + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY); + } +#endif +} + diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index d6db054e45..d5d809b791 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -33,6 +33,9 @@ #ifndef LL_LLRENDERTARGET_H #define LL_LLRENDERTARGET_H +// LLRenderTarget is unavailible on the mapserver since it uses FBOs. +#if !LL_MESA_HEADLESS + #include "llgl.h" #include "llrender.h" @@ -60,6 +63,7 @@ */ +class LLMultisampleBuffer; class LLRenderTarget { @@ -68,15 +72,25 @@ public: static BOOL sUseFBO; LLRenderTarget(); - ~LLRenderTarget(); + virtual ~LLRenderTarget(); //allocate resources for rendering //must be called before use //multiple calls will release previously allocated resources - void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, BOOL use_fbo = FALSE); + void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, BOOL use_fbo = FALSE); + + //provide this render target with a multisample resource. + void setSampleBuffer(LLMultisampleBuffer* buffer); + + //add color buffer attachment + //limit of 4 color attachments per render target + virtual void addColorAttachment(U32 color_fmt); //allocate a depth texture - void allocateDepth(); + virtual void allocateDepth(); + + //share depth buffer with provided render target + virtual void shareDepthBuffer(LLRenderTarget& target); //free any allocated resources //safe to call redundantly @@ -84,14 +98,14 @@ public: //bind target for rendering //applies appropriate viewport - void bindTarget(); + virtual void bindTarget(); //unbind target for rendering static void unbindTarget(); //clear render targer, clears depth buffer if present, //uses scissor rect if in copy-to-texture mode - void clear(); + void clear(U32 mask = 0xFFFFFFFF); //get applied viewport void getViewport(S32* viewport); @@ -104,10 +118,12 @@ public: LLTexUnit::eTextureType getUsage(void) const { return mUsage; } - U32 getTexture(void) const { return mTex; } + U32 getTexture(U32 attachment = 0) const; U32 getDepth(void) const { return mDepth; } + void bindTexture(U32 index, S32 channel); + //flush rendering operations //must be called when rendering is complete //should be used 1:1 with bindTarget @@ -116,23 +132,47 @@ public: // the current depth texture. A depth texture will be allocated if needed. void flush(BOOL fetch_depth = FALSE); + void copyContents(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). BOOL isComplete() const; -private: +protected: + friend class LLMultisampleBuffer; U32 mResX; U32 mResY; - U32 mTex; + std::vector<U32> mTex; U32 mFBO; U32 mDepth; - U32 mStencil; + BOOL mStencil; BOOL mUseDepth; BOOL mRenderDepth; LLTexUnit::eTextureType mUsage; + U32 mSamples; + LLMultisampleBuffer* mSampleBuffer; }; +class LLMultisampleBuffer : public LLRenderTarget +{ +public: + LLMultisampleBuffer(); + virtual ~LLMultisampleBuffer(); + + void releaseSampleBuffer(); + + virtual void bindTarget(); + void bindTarget(LLRenderTarget* ref); + virtual void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo); + void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo, U32 samples); + virtual void addColorAttachment(U32 color_fmt); + virtual void allocateDepth(); +}; + +#endif //!LL_MESA_HEADLESS + #endif diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 4d16741794..461edbeec7 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -69,8 +69,10 @@ S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] = { sizeof(LLVector3), // TYPE_VERTEX, sizeof(LLVector3), // TYPE_NORMAL, - sizeof(LLVector2), // TYPE_TEXCOORD, + sizeof(LLVector2), // TYPE_TEXCOORD0, + sizeof(LLVector2), // TYPE_TEXCOORD1, sizeof(LLVector2), // TYPE_TEXCOORD2, + sizeof(LLVector2), // TYPE_TEXCOORD3, sizeof(LLColor4U), // TYPE_COLOR, sizeof(LLVector3), // TYPE_BINORMAL, sizeof(F32), // TYPE_WEIGHT, @@ -103,8 +105,8 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) { MAP_VERTEX, MAP_NORMAL, - MAP_TEXCOORD, - MAP_COLOR + MAP_TEXCOORD0, + MAP_COLOR, }; GLenum array[] = @@ -112,7 +114,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) GL_VERTEX_ARRAY, GL_NORMAL_ARRAY, GL_TEXTURE_COORD_ARRAY, - GL_COLOR_ARRAY + GL_COLOR_ARRAY, }; for (U32 i = 0; i < 4; ++i) @@ -123,7 +125,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) { //needs to be disabled glDisableClientState(array[i]); } - else + else if (gDebugGL) { //needs to be enabled, make sure it was (DEBUG TEMPORARY) if (i > 0 && !glIsEnabled(array[i])) { @@ -137,29 +139,55 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) { //needs to be enabled glEnableClientState(array[i]); } - else if (glIsEnabled(array[i])) + else if (gDebugGL && glIsEnabled(array[i])) { //needs to be disabled, make sure it was (DEBUG TEMPORARY) llerrs << "Bad client state! " << array[i] << " enabled." << llendl; } } } - if (sLastMask & MAP_TEXCOORD2) + U32 map_tc[] = { - if (!(data_mask & MAP_TEXCOORD2)) + MAP_TEXCOORD1, + MAP_TEXCOORD2, + MAP_TEXCOORD3 + }; + + for (U32 i = 0; i < 3; i++) + { + if (sLastMask & map_tc[i]) { - glClientActiveTextureARB(GL_TEXTURE1_ARB); + if (!(data_mask & map_tc[i])) + { + glClientActiveTextureARB(GL_TEXTURE1_ARB+i); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + } + else if (data_mask & map_tc[i]) + { + glClientActiveTextureARB(GL_TEXTURE1_ARB+i); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + } + + if (sLastMask & MAP_BINORMAL) + { + if (!(data_mask & MAP_BINORMAL)) + { + glClientActiveTextureARB(GL_TEXTURE2_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE0_ARB); } } - else if (data_mask & MAP_TEXCOORD2) + else if (data_mask & MAP_BINORMAL) { - glClientActiveTextureARB(GL_TEXTURE1_ARB); + glClientActiveTextureARB(GL_TEXTURE2_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE0_ARB); } - + sLastMask = data_mask; } } @@ -194,6 +222,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi return; } + stop_glerror(); glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, ((U16*) getIndicesPointer()) + indices_offset); stop_glerror(); @@ -223,13 +252,14 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const return; } + stop_glerror(); glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT, ((U16*) getIndicesPointer()) + indices_offset); + stop_glerror(); } void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { - if (first >= (U32) mRequestedNumVerts || first + count > (U32) mRequestedNumVerts) { @@ -247,6 +277,7 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const return; } + stop_glerror(); glDrawArrays(sGLMode[mode], first, count); stop_glerror(); } @@ -767,11 +798,7 @@ U8* LLVertexBuffer::mapBuffer(S32 access) stop_glerror(); mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); stop_glerror(); - /*if (sMapped) - { - llerrs << "Mapped two VBOs at the same time!" << llendl; - } - sMapped = TRUE;*/ + if (!mMappedData) { //-------------------- @@ -896,14 +923,22 @@ bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index) { return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index); } -bool LLVertexBuffer::getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index) +bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index) +{ + return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index); +} +bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index) { - return VertexBufferStrider<LLVector2,TYPE_TEXCOORD>::get(*this, strider, index); + return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index); } -bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index) +/*bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index) { return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index); } +bool LLVertexBuffer::getTexCoord3Strider(LLStrider<LLVector2>& strider, S32 index) +{ + return VertexBufferStrider<LLVector2,TYPE_TEXCOORD3>::get(*this, strider, index); +}*/ bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index) { return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index); @@ -1101,24 +1136,39 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const { glNormalPointer(GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_NORMAL])); } + if (data_mask & MAP_TEXCOORD3) + { + glClientActiveTextureARB(GL_TEXTURE3_ARB); + glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD3])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } if (data_mask & MAP_TEXCOORD2) { - glClientActiveTextureARB(GL_TEXTURE1_ARB); + glClientActiveTextureARB(GL_TEXTURE2_ARB); glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD2])); glClientActiveTextureARB(GL_TEXTURE0_ARB); } - if (data_mask & MAP_TEXCOORD) + if (data_mask & MAP_TEXCOORD1) { - glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD])); + glClientActiveTextureARB(GL_TEXTURE1_ARB); + glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD1])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); } - if (data_mask & MAP_COLOR) + if (data_mask & MAP_BINORMAL) { - glColorPointer(4, GL_UNSIGNED_BYTE, stride, (void*)(base + mOffsets[TYPE_COLOR])); + glClientActiveTextureARB(GL_TEXTURE2_ARB); + glTexCoordPointer(3,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_BINORMAL])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); } - if (data_mask & MAP_BINORMAL) + if (data_mask & MAP_TEXCOORD0) { - glVertexAttribPointerARB(6, 3, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_BINORMAL])); + glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD0])); } + if (data_mask & MAP_COLOR) + { + glColorPointer(4, GL_UNSIGNED_BYTE, stride, (void*)(base + mOffsets[TYPE_COLOR])); + } + if (data_mask & MAP_WEIGHT) { glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_WEIGHT])); diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index fbddd9d887..aad948e17f 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -100,8 +100,10 @@ public: enum { TYPE_VERTEX, TYPE_NORMAL, - TYPE_TEXCOORD, + TYPE_TEXCOORD0, + TYPE_TEXCOORD1, TYPE_TEXCOORD2, + TYPE_TEXCOORD3, TYPE_COLOR, // These use VertexAttribPointer and should possibly be made generic TYPE_BINORMAL, @@ -113,16 +115,15 @@ public: enum { MAP_VERTEX = (1<<TYPE_VERTEX), MAP_NORMAL = (1<<TYPE_NORMAL), - MAP_TEXCOORD = (1<<TYPE_TEXCOORD), + MAP_TEXCOORD0 = (1<<TYPE_TEXCOORD0), + MAP_TEXCOORD1 = (1<<TYPE_TEXCOORD1), MAP_TEXCOORD2 = (1<<TYPE_TEXCOORD2), + MAP_TEXCOORD3 = (1<<TYPE_TEXCOORD3), MAP_COLOR = (1<<TYPE_COLOR), // These use VertexAttribPointer and should possibly be made generic MAP_BINORMAL = (1<<TYPE_BINORMAL), MAP_WEIGHT = (1<<TYPE_WEIGHT), MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT), - MAP_DRAW = 0x2000, // Buffer is in draw (read-only) mode - MAP_MAPPED = 0x4000, // Indicates that buffer has been mapped, but not to any type of data - MAP_UNMAPPED = 0x8000 // Indicates that buffer has been logically un-mapped }; protected: @@ -165,8 +166,8 @@ public: // vb->unmapBuffer(); bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0); bool getIndexStrider(LLStrider<U16>& strider, S32 index=0); - bool getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index=0); - bool getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index=0); + bool getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index=0); + bool getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index=0); bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0); bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0); bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0); |