summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
authorBrad Kittenbrink <brad@lindenlab.com>2009-02-18 21:10:16 +0000
committerBrad Kittenbrink <brad@lindenlab.com>2009-02-18 21:10:16 +0000
commitabdc99f21b542c4fea67030ddbd7166c9d1c6c63 (patch)
tree3e984e405adfdec189ca8a047daca5250737ffbf /indra/llrender
parent34412f0530cf6a411b4de906a8e9da59cbcb3a85 (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.txt6
-rw-r--r--indra/llrender/llcubemap.cpp11
-rw-r--r--indra/llrender/llfontgl.cpp69
-rw-r--r--indra/llrender/llfontgl.h2
-rw-r--r--indra/llrender/llgl.cpp101
-rw-r--r--indra/llrender/llgl.h4
-rw-r--r--indra/llrender/llglheaders.h32
-rw-r--r--indra/llrender/llglslshader.cpp86
-rw-r--r--indra/llrender/llglslshader.h4
-rw-r--r--indra/llrender/llimagegl.cpp305
-rw-r--r--indra/llrender/llimagegl.h75
-rw-r--r--indra/llrender/llpostprocess.cpp22
-rw-r--r--indra/llrender/llpostprocess.h2
-rw-r--r--indra/llrender/llrender.cpp134
-rw-r--r--indra/llrender/llrender.h44
-rw-r--r--indra/llrender/llrendertarget.cpp533
-rw-r--r--indra/llrender/llrendertarget.h58
-rw-r--r--indra/llrender/llvertexbuffer.cpp106
-rw-r--r--indra/llrender/llvertexbuffer.h15
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);