summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/llfontgl.cpp1
-rw-r--r--indra/llrender/llgl.cpp69
-rw-r--r--indra/llrender/llgl.h1
-rw-r--r--indra/llrender/llglheaders.h22
-rw-r--r--indra/llrender/llglslshader.cpp16
-rw-r--r--indra/llrender/llglslshader.h3
-rw-r--r--indra/llrender/llimagegl.cpp93
-rw-r--r--indra/llrender/llimagegl.h2
-rw-r--r--indra/llrender/llrender.cpp140
-rw-r--r--indra/llrender/llrender.h25
-rw-r--r--indra/llrender/llshadermgr.cpp70
-rw-r--r--indra/llrender/llvertexbuffer.cpp338
-rw-r--r--indra/llrender/llvertexbuffer.h35
13 files changed, 635 insertions, 180 deletions
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index d9e1976341..82db922368 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -247,7 +247,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
}
}
-
const LLFontGlyphInfo* next_glyph = NULL;
for (i = begin_offset; i < begin_offset + length; i++)
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index a3f7a946ec..7ff68fe34b 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -185,6 +185,9 @@ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT =
// GL_EXT_framebuffer_blit
PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL;
+// GL_EXT_blend_func_separate
+PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
+
// GL_ARB_draw_buffers
PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL;
@@ -324,6 +327,7 @@ LLGLManager::LLGLManager() :
mHasCompressedTextures(FALSE),
mHasFramebufferObject(FALSE),
mHasFramebufferMultisample(FALSE),
+ mHasBlendFuncSeparate(FALSE),
mHasVertexBufferObject(FALSE),
mHasPBuffer(FALSE),
@@ -633,6 +637,11 @@ void LLGLManager::initExtensions()
#else
mHasDrawBuffers = FALSE;
# endif
+# if GL_EXT_blend_func_separate
+ mHasBlendFuncSeparate = TRUE;
+#else
+ mHasBlendFuncSeparate = FALSE;
+# endif
mHasMipMapGeneration = FALSE;
mHasSeparateSpecularColor = FALSE;
mHasAnisotropic = FALSE;
@@ -659,6 +668,7 @@ void LLGLManager::initExtensions()
&& 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);
+ mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
#if !LL_DARWIN
mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
@@ -682,6 +692,7 @@ void LLGLManager::initExtensions()
mHasFramebufferObject = FALSE;
mHasFramebufferMultisample = FALSE;
mHasDrawBuffers = FALSE;
+ mHasBlendFuncSeparate = FALSE;
mHasMipMapGeneration = FALSE;
mHasSeparateSpecularColor = FALSE;
mHasAnisotropic = FALSE;
@@ -706,6 +717,7 @@ void LLGLManager::initExtensions()
mHasShaderObjects = FALSE;
mHasVertexShader = FALSE;
mHasFragmentShader = FALSE;
+ mHasBlendFuncSeparate = FALSE;
LL_WARNS("RenderInit") << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << LL_ENDL;
}
if (getenv("LL_GL_BLACKLIST")) /* Flawfinder: ignore */
@@ -734,7 +746,8 @@ void LLGLManager::initExtensions()
if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S
if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE;
if (strchr(blacklist,'t')) mHasTextureRectangle = FALSE;
-
+ if (strchr(blacklist,'u')) mHasBlendFuncSeparate = FALSE;//S
+
}
#endif // LL_LINUX || LL_SOLARIS
@@ -782,6 +795,14 @@ void LLGLManager::initExtensions()
{
LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_fragment_shader" << LL_ENDL;
}
+ if (!mHasBlendFuncSeparate)
+ {
+ LL_INFOS("RenderInit") << "Couldn't initialize GL_EXT_blend_func_separate" << LL_ENDL;
+ }
+ if (!mHasDrawBuffers)
+ {
+ LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_draw_buffers" << LL_ENDL;
+ }
// Disable certain things due to known bugs
if (mIsIntel && mHasMipMapGeneration)
@@ -852,6 +873,10 @@ void LLGLManager::initExtensions()
{
glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDrawBuffersARB");
}
+ if (mHasBlendFuncSeparate)
+ {
+ glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT");
+ }
#if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS
// This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah
glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
@@ -1014,24 +1039,9 @@ void flush_glerror()
glGetError();
}
-void assert_glerror()
+void do_assert_glerror()
{
- if (!gGLActive)
- {
- //llwarns << "GL used while not active!" << llendl;
-
- if (gDebugSession)
- {
- //ll_fail("GL used while not active");
- }
- }
-
- if (gNoRender || !gDebugGL)
- {
- return;
- }
-
- if (!gGLManager.mInited)
+ if (LL_UNLIKELY(!gGLManager.mInited))
{
LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL;
}
@@ -1039,10 +1049,9 @@ void assert_glerror()
GLenum error;
error = glGetError();
BOOL quit = FALSE;
- while (error)
+ while (LL_UNLIKELY(error))
{
quit = TRUE;
-#ifndef LL_LINUX // *FIX: ! This should be an error for linux as well.
GLubyte const * gl_error_msg = gluErrorString(error);
if (NULL != gl_error_msg)
{
@@ -1066,7 +1075,6 @@ void assert_glerror()
}
}
error = glGetError();
-#endif
}
if (quit)
@@ -1082,6 +1090,25 @@ void assert_glerror()
}
}
+void assert_glerror()
+{
+ if (!gGLActive)
+ {
+ //llwarns << "GL used while not active!" << llendl;
+
+ if (gDebugSession)
+ {
+ //ll_fail("GL used while not active");
+ }
+ }
+
+ if (!gNoRender && gDebugGL)
+ {
+ do_assert_glerror();
+ }
+}
+
+
void clear_glerror()
{
// Create or update texture to be used with this data
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 91421f3c95..0c2da7dd08 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -87,6 +87,7 @@ public:
BOOL mHasCompressedTextures;
BOOL mHasFramebufferObject;
BOOL mHasFramebufferMultisample;
+ BOOL mHasBlendFuncSeparate;
// ARB Extensions
BOOL mHasVertexBufferObject;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index f33ae7d8f0..f6d35bc766 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -216,6 +216,9 @@ extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
extern PFNGLCOLORTABLEEXTPROC glColorTableEXT;
+//GL_EXT_blend_func_separate
+extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
+
//GL_EXT_framebuffer_object
extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
@@ -249,7 +252,10 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
# include "GL/glh_extensions.h"
# undef __APPLE__
-#elif LL_LINUX
+#elif LL_LINUX
+//----------------------------------------------------------------------------
+// LL_LINUX
+
//----------------------------------------------------------------------------
// Linux, MESA headers, but not necessarily assuming MESA runtime.
// quotes so we get libraries/.../GL/ version
@@ -285,6 +291,7 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
# define LL_LINUX_NV_GL_HEADERS 0
#endif // LL_LINUX && defined(WINGDIAPI)
+
#if LL_LINUX_NV_GL_HEADERS
// Missing functions when using nvidia headers:
extern PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
@@ -445,6 +452,9 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB;
extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
+//GL_EXT_blend_func_separate
+extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
+
//GL_EXT_framebuffer_object
extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
@@ -473,7 +483,10 @@ extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
//GL_ARB_draw_buffers
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
+
#elif LL_WINDOWS
+//----------------------------------------------------------------------------
+// LL_WINDOWS
// windows gl headers depend on things like APIENTRY, so include windows.
#define WIN32_LEAN_AND_MEAN
@@ -641,6 +654,9 @@ extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB;
extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB;
extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
+//GL_EXT_blend_func_separate
+extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
+
//GL_EXT_framebuffer_object
extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
@@ -669,6 +685,7 @@ extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
//GL_ARB_draw_buffers
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
+
#elif LL_DARWIN
//----------------------------------------------------------------------------
// LL_DARWIN
@@ -685,6 +702,9 @@ extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
// Note that they also must not be called on 10.3.9. This should be taken care of by a runtime check for the existence of the GL extension.
#include <AvailabilityMacros.h>
+//GL_EXT_blend_func_separate
+extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+
// GL_EXT_framebuffer_object
extern GLboolean glIsRenderbufferEXT(GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
extern void glBindRenderbufferEXT(GLenum target, GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index ca92cb6580..9256e3959c 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -61,7 +61,7 @@ BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
LLShaderFeatures::LLShaderFeatures()
: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
-hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false),
+hasTransport(false), hasSkinning(false), hasObjectSkinning(false), hasAtmospherics(false), isSpecular(false),
hasGamma(false), hasLighting(false), calculatesAtmospherics(false)
{
}
@@ -124,7 +124,7 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
{
GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second);
LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
- if (mShaderLevel > 0)
+ if (shaderhandle > 0)
{
attachObject(shaderhandle);
}
@@ -717,6 +717,18 @@ GLint LLGLSLShader::getUniformLocation(const string& uniform)
return -1;
}
+GLint LLGLSLShader::getAttribLocation(U32 attrib)
+{
+ if (attrib < mAttribute.size())
+ {
+ return mAttribute[attrib];
+ }
+ else
+ {
+ return -1;
+ }
+}
+
void LLGLSLShader::uniform1i(const string& uniform, GLint v)
{
GLint location = getUniformLocation(uniform);
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 166d4af04c..dc493ba162 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -48,6 +48,7 @@ public:
bool hasWaterFog; // implies no gamma
bool hasTransport; // implies no lighting (it's possible to have neither though)
bool hasSkinning;
+ bool hasObjectSkinning;
bool hasAtmospherics;
bool hasGamma;
@@ -109,7 +110,7 @@ public:
void vertexAttrib4fv(U32 index, GLfloat* v);
GLint getUniformLocation(const std::string& uniform);
-
+ GLint getAttribLocation(U32 attrib);
GLint mapUniformTextureChannel(GLint location, GLenum type);
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index ff47c57c70..2579bad0b6 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1645,7 +1645,7 @@ void LLImageGL::calcAlphaChannelOffsetAndStride()
}
}
-void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
+void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
{
if(!mNeedsAlphaAndPickMask)
{
@@ -1653,26 +1653,91 @@ void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
}
U32 length = w * h;
- const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset ;
+ U32 alphatotal = 0;
- S32 sample[16];
- memset(sample, 0, sizeof(S32)*16);
-
- for (U32 i = 0; i < length; i++)
+ U32 sample[16];
+ memset(sample, 0, sizeof(U32)*16);
+
+ // generate histogram of quantized alpha.
+ // also add-in the histogram of a 2x2 box-sampled version. The idea is
+ // this will mid-skew the data (and thus increase the chances of not
+ // being used as a mask) from high-frequency alpha maps which
+ // suffer the worst from aliasing when used as alpha masks.
+ if (w >= 2 && h >= 2)
+ {
+ llassert(w%2 == 0);
+ llassert(h%2 == 0);
+ const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset;
+ for (U32 y = 0; y < h; y+=2)
+ {
+ const GLubyte* current = rowstart;
+ for (U32 x = 0; x < w; x+=2)
+ {
+ const U32 s1 = current[0];
+ alphatotal += s1;
+ const U32 s2 = current[w * mAlphaStride];
+ alphatotal += s2;
+ current += mAlphaStride;
+ const U32 s3 = current[0];
+ alphatotal += s3;
+ const U32 s4 = current[w * mAlphaStride];
+ alphatotal += s4;
+ current += mAlphaStride;
+
+ ++sample[s1/16];
+ ++sample[s2/16];
+ ++sample[s3/16];
+ ++sample[s4/16];
+
+ const U32 asum = (s1+s2+s3+s4);
+ alphatotal += asum;
+ sample[asum/(16*4)] += 4;
+ }
+
+ rowstart += 2 * w * mAlphaStride;
+ }
+ length *= 2; // we sampled everything twice, essentially
+ }
+ else
{
- ++sample[*current/16];
- current += mAlphaStride ;
+ const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset;
+ for (U32 i = 0; i < length; i++)
+ {
+ const U32 s1 = *current;
+ alphatotal += s1;
+ ++sample[s1/16];
+ current += mAlphaStride;
+ }
}
+
+ // if more than 1/16th of alpha samples are mid-range, this
+ // shouldn't be treated as a 1-bit mask
- U32 total = 0;
+ // also, if all of the alpha samples are clumped on one half
+ // of the range (but not at an absolute extreme), then consider
+ // this to be an intentional effect and don't treat as a mask.
+
+ U32 midrangetotal = 0;
for (U32 i = 4; i < 11; i++)
{
- total += sample[i];
+ midrangetotal += sample[i];
+ }
+ U32 lowerhalftotal = 0;
+ for (U32 i = 0; i < 8; i++)
+ {
+ lowerhalftotal += sample[i];
+ }
+ U32 upperhalftotal = 0;
+ for (U32 i = 8; i < 16; i++)
+ {
+ upperhalftotal += sample[i];
}
- if (total > length/16)
+ if (midrangetotal > length/16 || // lots of midrange, or
+ (lowerhalftotal == length && alphatotal != 0) || // all close to transparent but not all totally transparent, or
+ (upperhalftotal == length && alphatotal != 255*length)) // all close to opaque but not all totally opaque
{
- mIsMask = FALSE;
+ mIsMask = FALSE; // not suitable for masking
}
else
{
@@ -1748,7 +1813,7 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
{
LL_WARNS_ONCE("render") << "Ugh, non-finite u/v in mask pick" << LL_ENDL;
u = v = 0.f;
- llassert(false);
+ //llassert(false);
}
if (LL_UNLIKELY(u < 0.f || u > 1.f ||
@@ -1756,7 +1821,7 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
{
LL_WARNS_ONCE("render") << "Ugh, u/v out of range in image mask pick" << LL_ENDL;
u = v = 0.f;
- llassert(false);
+ //llassert(false);
}
S32 x = llfloor(u * mPickMaskWidth);
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 41239d24c8..03939888a5 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -91,7 +91,7 @@ public:
protected:
virtual ~LLImageGL();
- void analyzeAlpha(const void* data_in, S32 w, S32 h);
+ void analyzeAlpha(const void* data_in, U32 w, U32 h);
void calcAlphaChannelOffsetAndStride();
public:
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index c3540a717c..70601663e6 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -39,6 +39,7 @@
#include "llimagegl.h"
#include "llrendertarget.h"
#include "lltexture.h"
+#include "llvector4a.h"
LLRender gGL;
@@ -53,6 +54,7 @@ U32 LLRender::sUICalls = 0;
U32 LLRender::sUIVerts = 0;
static const U32 LL_NUM_TEXTURE_LAYERS = 16;
+static const U32 LL_MAX_UI_STACK_DEPTH = 32;
static GLenum sGLTextureType[] =
{
@@ -165,6 +167,7 @@ void LLTexUnit::enable(eTextureType type)
if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) )
{
activate();
+
if (mCurrTexType != TT_NONE && !gGL.mDirty)
{
disable(); // Force a disable of a previous texture type if it's enabled.
@@ -756,14 +759,27 @@ LLRender::LLRender()
mCount(0),
mMode(LLRender::TRIANGLES),
mCurrTextureUnitIndex(0),
- mMaxAnisotropy(0.f)
+ mMaxAnisotropy(0.f),
+ mUIStackDepth(0)
{
mBuffer = new LLVertexBuffer(immediate_mask, 0);
mBuffer->allocateBuffer(4096, 0, TRUE);
- mBuffer->getVertexStrider(mVerticesp);
- mBuffer->getTexCoord0Strider(mTexcoordsp);
- mBuffer->getColorStrider(mColorsp);
-
+
+ LLStrider<LLVector3> vert;
+ LLStrider<LLVector2> tc;
+ LLStrider<LLColor4U> color;
+
+ mBuffer->getVertexStrider(vert);
+ mBuffer->getTexCoord0Strider(tc);
+ mBuffer->getColorStrider(color);
+
+ mVerticesp = (LLVector4a*) vert.get();
+ mTexcoordsp = tc.get();
+ mColorsp = color.get();
+
+ mUIOffset = (LLVector4a*) ll_aligned_malloc_16(LL_MAX_UI_STACK_DEPTH*sizeof(LLVector4a));
+ mUIScale = (LLVector4a*) ll_aligned_malloc_16(LL_MAX_UI_STACK_DEPTH*sizeof(LLVector4a));
+
mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS);
for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++)
{
@@ -778,8 +794,11 @@ LLRender::LLRender()
mCurrAlphaFunc = CF_DEFAULT;
mCurrAlphaFuncVal = 0.01f;
- mCurrBlendSFactor = BF_UNDEF;
- mCurrBlendDFactor = BF_UNDEF;
+
+ mCurrBlendColorSFactor = BF_UNDEF;
+ mCurrBlendAlphaSFactor = BF_UNDEF;
+ mCurrBlendColorDFactor = BF_UNDEF;
+ mCurrBlendAlphaDFactor = BF_UNDEF;
}
LLRender::~LLRender()
@@ -796,6 +815,11 @@ void LLRender::shutdown()
mTexUnits.clear();
delete mDummyTexUnit;
mDummyTexUnit = NULL;
+
+ ll_aligned_free_16(mUIOffset);
+ mUIOffset = NULL;
+ ll_aligned_free_16(mUIScale);
+ mUIScale = NULL;
}
void LLRender::refreshState(void)
@@ -844,84 +868,83 @@ void LLRender::popMatrix()
void LLRender::translateUI(F32 x, F32 y, F32 z)
{
- if (mUIOffset.empty())
+ if (mUIStackDepth == 0)
{
llerrs << "Need to push a UI translation frame before offsetting" << llendl;
}
- mUIOffset.front().mV[0] += x;
- mUIOffset.front().mV[1] += y;
- mUIOffset.front().mV[2] += z;
+ LLVector4a trans(x,y,z);
+ mUIOffset[mUIStackDepth-1].add(trans);
}
void LLRender::scaleUI(F32 x, F32 y, F32 z)
{
- if (mUIScale.empty())
+ if (mUIStackDepth == 0)
{
llerrs << "Need to push a UI transformation frame before scaling." << llendl;
}
- mUIScale.front().scaleVec(LLVector3(x,y,z));
+ LLVector4a scale(x,y,z);
+ mUIScale[mUIStackDepth-1].mul(scale);
}
void LLRender::pushUIMatrix()
{
- if (mUIOffset.empty())
+ if (mUIStackDepth == 0)
{
- mUIOffset.push_front(LLVector3(0,0,0));
+ mUIOffset[0].clear();
+ mUIScale[0].splat(1.f);
}
- else
+ else if (mUIStackDepth < LL_MAX_UI_STACK_DEPTH)
{
- mUIOffset.push_front(mUIOffset.front());
- }
-
- if (mUIScale.empty())
- {
- mUIScale.push_front(LLVector3(1,1,1));
+ mUIOffset[mUIStackDepth] = mUIOffset[mUIStackDepth-1];
+ mUIScale[mUIStackDepth] = mUIScale[mUIStackDepth-1];
}
else
{
- mUIScale.push_front(mUIScale.front());
+ llerrs << "Blown UI matrix stack." << llendl;
}
+
+ ++mUIStackDepth;
+
}
void LLRender::popUIMatrix()
{
- if (mUIOffset.empty())
+ if (mUIStackDepth == 0)
{
llerrs << "UI offset stack blown." << llendl;
}
- mUIOffset.pop_front();
- mUIScale.pop_front();
+ --mUIStackDepth;
}
LLVector3 LLRender::getUITranslation()
{
- if (mUIOffset.empty())
+ if (mUIStackDepth == 0)
{
llerrs << "UI offset stack empty." << llendl;
}
- return mUIOffset.front();
+ return LLVector3(mUIOffset[mUIStackDepth-1].getF32());
}
LLVector3 LLRender::getUIScale()
{
- if (mUIScale.empty())
+ if (mUIStackDepth == 0)
{
llerrs << "UI scale stack empty." << llendl;
}
- return mUIScale.front();
+ return LLVector3(mUIScale[mUIStackDepth-1].getF32());
}
void LLRender::loadUIIdentity()
{
- if (mUIOffset.empty())
+ if (mUIStackDepth == 0)
{
llerrs << "Need to push UI translation frame before clearing offset." << llendl;
}
- mUIOffset.front().setVec(0,0,0);
- mUIScale.front().setVec(1,1,1);
+ mUIOffset[mUIStackDepth-1].clear();
+ mUIScale[mUIStackDepth-1].splat(1.f);
}
void LLRender::setColorMask(bool writeColor, bool writeAlpha)
@@ -995,15 +1018,44 @@ void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)
{
llassert(sfactor < BF_UNDEF);
llassert(dfactor < BF_UNDEF);
- if (mCurrBlendSFactor != sfactor || mCurrBlendDFactor != dfactor)
+ if (mCurrBlendColorSFactor != sfactor || mCurrBlendColorDFactor != dfactor ||
+ mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor)
{
- mCurrBlendSFactor = sfactor;
- mCurrBlendDFactor = dfactor;
+ mCurrBlendColorSFactor = sfactor;
+ mCurrBlendAlphaSFactor = sfactor;
+ mCurrBlendColorDFactor = dfactor;
+ mCurrBlendAlphaDFactor = dfactor;
flush();
glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]);
}
}
+void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor,
+ eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor)
+{
+ llassert(color_sfactor < BF_UNDEF);
+ llassert(color_dfactor < BF_UNDEF);
+ llassert(alpha_sfactor < BF_UNDEF);
+ llassert(alpha_dfactor < BF_UNDEF);
+ if (!gGLManager.mHasBlendFuncSeparate)
+ {
+ LL_WARNS_ONCE("render") << "no glBlendFuncSeparateEXT(), using color-only blend func" << llendl;
+ blendFunc(color_sfactor, color_dfactor);
+ return;
+ }
+ if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor ||
+ mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor)
+ {
+ mCurrBlendColorSFactor = color_sfactor;
+ mCurrBlendAlphaSFactor = alpha_sfactor;
+ mCurrBlendColorDFactor = color_dfactor;
+ mCurrBlendAlphaDFactor = alpha_dfactor;
+ flush();
+ glBlendFuncSeparateEXT(sGLBlendFactor[color_sfactor], sGLBlendFactor[color_dfactor],
+ sGLBlendFactor[alpha_sfactor], sGLBlendFactor[alpha_dfactor]);
+ }
+}
+
LLTexUnit* LLRender::getTexUnit(U32 index)
{
if (index < mTexUnits.size())
@@ -1121,7 +1173,7 @@ void LLRender::flush()
}
#endif
- if (!mUIOffset.empty())
+ if (mUIStackDepth > 0)
{
sUICalls++;
sUIVerts += mCount;
@@ -1173,24 +1225,22 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
return;
}
- if (mUIOffset.empty())
- {
- mVerticesp[mCount] = LLVector3(x,y,z);
- }
- else
+ LLVector3& v = reinterpret_cast<LLVector3&>(mVerticesp[mCount]);
+ v.set(x,y,z);
+ if (mUIStackDepth != 0)
{
- LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.front()).scaledVec(mUIScale.front());
- mVerticesp[mCount] = vert;
+ v += reinterpret_cast<LLVector3&>(mUIOffset[mUIStackDepth-1]);
+ v.scaleVec(reinterpret_cast<LLVector3&>(mUIScale[mUIStackDepth-1]));
}
mCount++;
if (mCount < 4096)
{
- mVerticesp[mCount] = mVerticesp[mCount-1];
mColorsp[mCount] = mColorsp[mCount-1];
mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
}
}
+
void LLRender::vertex2i(const GLint& x, const GLint& y)
{
vertex3f((GLfloat) x, (GLfloat) y, 0);
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index a90fbd4a5c..11cd95646f 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -45,6 +45,7 @@
#include "v4coloru.h"
#include "llstrider.h"
#include "llpointer.h"
+#include "llmemory.h"
#include "llglheaders.h"
class LLVertexBuffer;
@@ -52,6 +53,7 @@ class LLCubeMap;
class LLImageGL;
class LLRenderTarget;
class LLTexture ;
+class LLVector4a;
class LLTexUnit
{
@@ -323,7 +325,11 @@ public:
void setAlphaRejectSettings(eCompareFunc func, F32 value = 0.01f);
+ // applies blend func to both color and alpha
void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor);
+ // applies separate blend functions to color and alpha
+ void blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor,
+ eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor);
LLTexUnit* getTexUnit(U32 index);
@@ -356,20 +362,23 @@ private:
F32 mCurrAlphaFuncVal;
LLPointer<LLVertexBuffer> mBuffer;
- LLStrider<LLVector3> mVerticesp;
- LLStrider<LLVector2> mTexcoordsp;
- LLStrider<LLColor4U> mColorsp;
+ LLVector4a* mVerticesp;
+ LLVector2* mTexcoordsp;
+ LLColor4U* mColorsp;
+
std::vector<LLTexUnit*> mTexUnits;
LLTexUnit* mDummyTexUnit;
- eBlendFactor mCurrBlendSFactor;
- eBlendFactor mCurrBlendDFactor;
-
+ eBlendFactor mCurrBlendColorSFactor;
+ eBlendFactor mCurrBlendColorDFactor;
+ eBlendFactor mCurrBlendAlphaSFactor;
+ eBlendFactor mCurrBlendAlphaDFactor;
F32 mMaxAnisotropy;
- std::list<LLVector3> mUIOffset;
- std::list<LLVector3> mUIScale;
+ LLVector4a* mUIOffset;
+ LLVector4a* mUIScale;
+ U32 mUIStackDepth;
};
extern F64 gGLModelView[16];
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 1286e91e49..0f54ebeb69 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -152,6 +152,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
return FALSE;
}
}
+
+ if (features->hasObjectSkinning)
+ {
+ if (!shader->attachObject("avatar/objectSkinV.glsl"))
+ {
+ return FALSE;
+ }
+ }
///////////////////////////////////////
// Attach Fragment Shader Features Next
@@ -313,11 +321,14 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns)
GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type)
{
- GLenum error;
- error = glGetError();
- if (error != GL_NO_ERROR)
+ GLenum error = GL_NO_ERROR;
+ if (gDebugGL)
{
- LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
+ error = glGetError();
+ if (error != GL_NO_ERROR)
+ {
+ LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
+ }
}
LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL;
@@ -372,31 +383,39 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
//create shader object
GLhandleARB ret = glCreateShaderObjectARB(type);
- error = glGetError();
- if (error != GL_NO_ERROR)
+ if (gDebugGL)
{
- LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
+ error = glGetError();
+ if (error != GL_NO_ERROR)
+ {
+ LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
+ }
}
- else
+
+ //load source
+ glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
+
+ if (gDebugGL)
{
- //load source
- glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
error = glGetError();
if (error != GL_NO_ERROR)
{
LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL;
}
- else
+ }
+
+ //compile source
+ glCompileShaderARB(ret);
+
+ if (gDebugGL)
+ {
+ error = glGetError();
+ if (error != GL_NO_ERROR)
{
- //compile source
- glCompileShaderARB(ret);
- error = glGetError();
- if (error != GL_NO_ERROR)
- {
- LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
- }
+ LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
}
}
+
//free memory
for (GLuint i = 0; i < count; i++)
{
@@ -407,13 +426,16 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
//check for errors
GLint success = GL_TRUE;
glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success);
- error = glGetError();
- if (error != GL_NO_ERROR || success == GL_FALSE)
+ if (gDebugGL || success == GL_FALSE)
{
- //an error occured, print log
- LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
- dumpObjectLog(ret);
- ret = 0;
+ error = glGetError();
+ if (error != GL_NO_ERROR || success == GL_FALSE)
+ {
+ //an error occured, print log
+ LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
+ dumpObjectLog(ret);
+ ret = 0;
+ }
}
}
else
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index bf5eda21eb..48c20b09a8 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -31,6 +31,7 @@
*/
#include "linden_common.h"
+#include "llmemory.h"
#include <boost/static_assert.hpp>
@@ -39,6 +40,7 @@
#include "llglheaders.h"
#include "llmemtype.h"
#include "llrender.h"
+#include "llvector4a.h"
//============================================================================
@@ -61,9 +63,32 @@ BOOL LLVertexBuffer::sVBOActive = FALSE;
BOOL LLVertexBuffer::sIBOActive = FALSE;
U32 LLVertexBuffer::sAllocatedBytes = 0;
BOOL LLVertexBuffer::sMapped = FALSE;
+BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
+S32 LLVertexBuffer::sWeight4Loc = -1;
std::vector<U32> LLVertexBuffer::sDeleteList;
+#define LL_ALIGNED_VB 1
+
+#if LL_ALIGNED_VB
+
+S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
+{
+ sizeof(LLVector4), // TYPE_VERTEX,
+ sizeof(LLVector4), // TYPE_NORMAL,
+ sizeof(LLVector2), // TYPE_TEXCOORD0,
+ sizeof(LLVector2), // TYPE_TEXCOORD1,
+ sizeof(LLVector2), // TYPE_TEXCOORD2,
+ sizeof(LLVector2), // TYPE_TEXCOORD3,
+ sizeof(LLColor4U), // TYPE_COLOR,
+ sizeof(LLVector4), // TYPE_BINORMAL,
+ sizeof(F32), // TYPE_WEIGHT,
+ sizeof(LLVector4), // TYPE_WEIGHT4,
+ sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
+};
+
+#else
+
S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
{
sizeof(LLVector3), // TYPE_VERTEX,
@@ -75,9 +100,12 @@ S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
sizeof(LLColor4U), // TYPE_COLOR,
sizeof(LLVector3), // TYPE_BINORMAL,
sizeof(F32), // TYPE_WEIGHT,
+ sizeof(LLVector4), // TYPE_WEIGHT4,
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
};
+#endif
+
U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
{
GL_TRIANGLES,
@@ -209,14 +237,33 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
+ if (sLastMask & MAP_WEIGHT4)
+ {
+ if (sWeight4Loc < 0)
+ {
+ llerrs << "Weighting disabled but vertex buffer still bound!" << llendl;
+ }
+
+ if (!(data_mask & MAP_WEIGHT4))
+ { //disable 4-component skin weight
+ glDisableVertexAttribArrayARB(sWeight4Loc);
+ }
+ }
+ else if (data_mask & MAP_WEIGHT4)
+ {
+ if (sWeight4Loc >= 0)
+ { //enable 4-component skin weight
+ glEnableVertexAttribArrayARB(sWeight4Loc);
+ }
+ }
+
+
sLastMask = data_mask;
}
}
-void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
+void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
{
- llassert(mRequestedNumVerts >= 0);
-
if (start >= (U32) mRequestedNumVerts ||
end >= (U32) mRequestedNumVerts)
{
@@ -231,6 +278,25 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
+ if (gDebugGL && !useVBOs())
+ {
+ U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+ for (U32 i = 0; i < count; ++i)
+ {
+ if (idx[i] < start || idx[i] > end)
+ {
+ llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl;
+ }
+ }
+ }
+}
+
+void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
+{
+ validateRange(start, end, count, indices_offset);
+
+ llassert(mRequestedNumVerts >= 0);
+
if (mGLIndices != sGLRenderIndices)
{
llerrs << "Wrong index buffer bound." << llendl;
@@ -247,9 +313,11 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
return;
}
+ U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+
stop_glerror();
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
- ((U16*) getIndicesPointer()) + indices_offset);
+ idx);
stop_glerror();
}
@@ -381,16 +449,52 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
{
mUsage = 0 ;
}
+
+ if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
+ {
+ mUsage = 0;
+ }
S32 stride = calcStride(typemask, mOffsets);
mTypeMask = typemask;
mStride = stride;
+ mAlignedOffset = 0;
+ mAlignedIndexOffset = 0;
+
sCount++;
}
+#if LL_ALIGNED_VB
//static
-S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets)
+S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets, S32 num_vertices)
+{
+ S32 offset = 0;
+ for (S32 i=0; i<TYPE_MAX; i++)
+ {
+ U32 mask = 1<<i;
+ if (typemask & mask)
+ {
+ if (offsets)
+ {
+ offsets[i] = offset;
+ offset += LLVertexBuffer::sTypeOffsets[i]*num_vertices;
+ offset = (offset + 0xF) & ~0xF;
+ }
+ }
+ }
+
+ return offset+16;
+}
+
+S32 LLVertexBuffer::getSize() const
+{
+ return mStride;
+}
+
+#else
+//static
+S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets, S32 num_vertices)
{
S32 stride = 0;
for (S32 i=0; i<TYPE_MAX; i++)
@@ -409,6 +513,12 @@ S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets)
return stride;
}
+S32 LLVertexBuffer::getSize() const
+{
+ return mNumVerts*mStride;
+}
+
+#endif
// protected, use unref()
//virtual
LLVertexBuffer::~LLVertexBuffer()
@@ -518,7 +628,7 @@ void LLVertexBuffer::createGLBuffer()
{
static int gl_buffer_idx = 0;
mGLBuffer = ++gl_buffer_idx;
- mMappedData = new U8[size];
+ mMappedData = (U8*) ll_aligned_malloc_16(size);
memset(mMappedData, 0, size);
}
}
@@ -540,16 +650,20 @@ void LLVertexBuffer::createGLIndices()
mEmpty = TRUE;
+ //pad by 16 bytes for aligned copies
+ size += 16;
+
if (useVBOs())
{
+ //pad by another 16 bytes for VBO pointer adjustment
+ size += 16;
mMappedIndexData = NULL;
genIndices();
mResized = TRUE;
}
else
{
- mMappedIndexData = new U8[size];
- memset(mMappedIndexData, 0, size);
+ mMappedIndexData = (U8*) ll_aligned_malloc_16(size);
static int gl_buffer_idx = 0;
mGLIndices = ++gl_buffer_idx;
}
@@ -570,7 +684,7 @@ void LLVertexBuffer::destroyGLBuffer()
}
else
{
- delete [] mMappedData;
+ ll_aligned_free_16(mMappedData);
mMappedData = NULL;
mEmpty = TRUE;
}
@@ -579,7 +693,7 @@ void LLVertexBuffer::destroyGLBuffer()
}
mGLBuffer = 0;
- unbind();
+ //unbind();
}
void LLVertexBuffer::destroyGLIndices()
@@ -597,7 +711,7 @@ void LLVertexBuffer::destroyGLIndices()
}
else
{
- delete [] mMappedIndexData;
+ ll_aligned_free_16(mMappedIndexData);
mMappedIndexData = NULL;
mEmpty = TRUE;
}
@@ -606,7 +720,7 @@ void LLVertexBuffer::destroyGLIndices()
}
mGLIndices = 0;
- unbind();
+ //unbind();
}
void LLVertexBuffer::updateNumVerts(S32 nverts)
@@ -622,7 +736,7 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
}
mRequestedNumVerts = nverts;
-
+
if (!mDynamicSize)
{
mNumVerts = nverts;
@@ -637,6 +751,9 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
}
mNumVerts = nverts;
}
+#if LL_ALIGNED_VB
+ mStride = calcStride(mTypeMask, mOffsets, mNumVerts);
+#endif
}
@@ -668,6 +785,12 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
+ if (nverts < 0 || nindices < 0 ||
+ nverts > 65536)
+ {
+ llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl;
+ }
+
updateNumVerts(nverts);
updateNumIndices(nindices);
@@ -706,9 +829,6 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
{
sAllocatedBytes -= getSize() + getIndicesSize();
- S32 oldsize = getSize();
- S32 old_index_size = getIndicesSize();
-
updateNumVerts(newnverts);
updateNumIndices(newnindices);
@@ -725,26 +845,10 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
}
else
{
- //delete old buffer, keep GL buffer for now
if (!useVBOs())
{
- U8* old = mMappedData;
- mMappedData = new U8[newsize];
- if (old)
- {
- memcpy(mMappedData, old, llmin(newsize, oldsize));
- if (newsize > oldsize)
- {
- memset(mMappedData+oldsize, 0, newsize-oldsize);
- }
-
- delete [] old;
- }
- else
- {
- memset(mMappedData, 0, newsize);
- mEmpty = TRUE;
- }
+ ll_aligned_free_16(mMappedData);
+ mMappedData = (U8*) ll_aligned_malloc_16(newsize);
}
mResized = TRUE;
}
@@ -764,24 +868,8 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
{
if (!useVBOs())
{
- //delete old buffer, keep GL buffer for now
- U8* old = mMappedIndexData;
- mMappedIndexData = new U8[new_index_size];
-
- if (old)
- {
- memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size));
- if (new_index_size > old_index_size)
- {
- memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size);
- }
- delete [] old;
- }
- else
- {
- memset(mMappedIndexData, 0, new_index_size);
- mEmpty = TRUE;
- }
+ ll_aligned_free_16(mMappedIndexData);
+ mMappedIndexData = (U8*) ll_aligned_malloc_16(new_index_size);
}
mResized = TRUE;
}
@@ -813,7 +901,7 @@ BOOL LLVertexBuffer::useVBOs() const
return FALSE;
}
#endif
- return sEnableVBOs;
+ return TRUE;
}
//----------------------------------------------------------------------------
@@ -838,12 +926,19 @@ U8* LLVertexBuffer::mapBuffer(S32 access)
setBuffer(0);
mLocked = TRUE;
stop_glerror();
- mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+
+ U8* src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
+ mAlignedOffset = mMappedData - src;
+
stop_glerror();
}
{
LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
- mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ U8* src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ mMappedIndexData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
+ mAlignedIndexOffset = mMappedIndexData - src;
+
stop_glerror();
}
@@ -927,6 +1022,45 @@ void LLVertexBuffer::unmapBuffer()
//----------------------------------------------------------------------------
+#if LL_ALIGNED_VB
+
+template <class T,S32 type> struct VertexBufferStrider
+{
+ typedef LLStrider<T> strider_t;
+ static bool get(LLVertexBuffer& vbo,
+ strider_t& strider,
+ S32 index)
+ {
+ if (vbo.mapBuffer() == NULL)
+ {
+ llwarns << "mapBuffer failed!" << llendl;
+ return FALSE;
+ }
+
+ if (type == LLVertexBuffer::TYPE_INDEX)
+ {
+ S32 stride = sizeof(T);
+ strider = (T*)(vbo.getMappedIndices() + index*stride);
+ strider.setStride(0);
+ return TRUE;
+ }
+ else if (vbo.hasDataType(type))
+ {
+ S32 stride = LLVertexBuffer::sTypeOffsets[type];
+ strider = (T*)(vbo.getMappedData() + vbo.getOffset(type)+index*stride);
+ strider.setStride(stride);
+ return TRUE;
+ }
+ else
+ {
+ llerrs << "VertexBufferStrider could not find valid vertex data." << llendl;
+ }
+ return FALSE;
+ }
+};
+
+#else
+
template <class T,S32 type> struct VertexBufferStrider
{
typedef LLStrider<T> strider_t;
@@ -962,6 +1096,7 @@ template <class T,S32 type> struct VertexBufferStrider
}
};
+#endif
bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index)
{
@@ -1003,6 +1138,12 @@ bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index)
{
return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index);
}
+
+bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index)
+{
+ return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index);
+}
+
bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index)
{
return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index);
@@ -1177,7 +1318,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
{
if (mGLBuffer)
{
- if (sEnableVBOs && sVBOActive)
+ if (useVBOs() && sVBOActive)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
sBindCount++;
@@ -1189,7 +1330,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
setup = TRUE; // ... or a client memory pointer changed
}
}
- if (sEnableVBOs && mGLIndices && sIBOActive)
+ if (useVBOs() && mGLIndices && sIBOActive)
{
/*if (sMapped)
{
@@ -1218,6 +1359,81 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
}
}
+#if LL_ALIGNED_VB
+
+// virtual (default)
+void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER);
+ stop_glerror();
+ U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
+
+ if ((data_mask & mTypeMask) != data_mask)
+ {
+ llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
+ }
+
+ if (data_mask & MAP_NORMAL)
+ {
+ glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+ }
+ if (data_mask & MAP_TEXCOORD3)
+ {
+ glClientActiveTextureARB(GL_TEXTURE3_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD2)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD1)
+ {
+ glClientActiveTextureARB(GL_TEXTURE1_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_BINORMAL)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD0)
+ {
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ }
+ if (data_mask & MAP_COLOR)
+ {
+ glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeOffsets[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+ }
+
+ if (data_mask & MAP_WEIGHT)
+ {
+ glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeOffsets[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT]));
+ }
+
+ if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1)
+ {
+ glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeOffsets[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4]));
+ }
+
+ if (data_mask & MAP_CLOTHWEIGHT)
+ {
+ glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeOffsets[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
+ }
+ if (data_mask & MAP_VERTEX)
+ {
+ glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_VERTEX], (void*)(base + 0));
+ }
+
+ llglassertok();
+}
+
+#else
+
// virtual (default)
void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
{
@@ -1272,6 +1488,12 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
{
glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_WEIGHT]));
}
+
+ if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1)
+ {
+ glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, stride, (void*)(base+mOffsets[TYPE_WEIGHT4]));
+ }
+
if (data_mask & MAP_CLOTHWEIGHT)
{
glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, stride, (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
@@ -1284,6 +1506,8 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
llglassertok();
}
+#endif
+
void LLVertexBuffer::markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count)
{
// TODO: use GL_APPLE_flush_buffer_range here
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index b785a22976..715309b64a 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -79,10 +79,25 @@ protected:
class LLVertexBuffer : public LLRefCount
{
public:
+ LLVertexBuffer(const LLVertexBuffer& rhs)
+ {
+ *this = rhs;
+ }
+
+ const LLVertexBuffer& operator=(const LLVertexBuffer& rhs)
+ {
+ llerrs << "Illegal operation!" << llendl;
+ return *this;
+ }
+
static LLVBOPool sStreamVBOPool;
static LLVBOPool sDynamicVBOPool;
static LLVBOPool sStreamIBOPool;
static LLVBOPool sDynamicIBOPool;
+
+ static S32 sWeight4Loc;
+
+ static BOOL sUseStreamDraw;
static void initClass(bool use_vbo);
static void cleanupClass();
@@ -94,7 +109,7 @@ public:
//if offsets is not NULL, its contents will be filled
//with the offset of each vertex component in the buffer,
// indexed by the following enum
- static S32 calcStride(const U32& typemask, S32* offsets = NULL);
+ static S32 calcStride(const U32& typemask, S32* offsets = NULL, S32 num_vertices = 0);
enum {
TYPE_VERTEX,
@@ -107,6 +122,7 @@ public:
// These use VertexAttribPointer and should possibly be made generic
TYPE_BINORMAL,
TYPE_WEIGHT,
+ TYPE_WEIGHT4,
TYPE_CLOTHWEIGHT,
TYPE_MAX,
TYPE_INDEX,
@@ -122,6 +138,7 @@ public:
// These use VertexAttribPointer and should possibly be made generic
MAP_BINORMAL = (1<<TYPE_BINORMAL),
MAP_WEIGHT = (1<<TYPE_WEIGHT),
+ MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
};
@@ -171,6 +188,7 @@ public:
bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0);
bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0);
bool getWeightStrider(LLStrider<F32>& strider, S32 index=0);
+ bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0);
bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0);
BOOL isEmpty() const { return mEmpty; }
@@ -180,12 +198,12 @@ public:
S32 getRequestedVerts() const { return mRequestedNumVerts; }
S32 getRequestedIndices() const { return mRequestedNumIndices; }
- U8* getIndicesPointer() const { return useVBOs() ? NULL : mMappedIndexData; }
+ U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
U8* getVerticesPointer() const { return useVBOs() ? NULL : mMappedData; }
S32 getStride() const { return mStride; }
- S32 getTypeMask() const { return mTypeMask; }
+ U32 getTypeMask() const { return mTypeMask; }
BOOL hasDataType(S32 type) const { return ((1 << type) & getTypeMask()) ? TRUE : FALSE; }
- S32 getSize() const { return mNumVerts*mStride; }
+ S32 getSize() const;
S32 getIndicesSize() const { return mNumIndices * sizeof(U16); }
U8* getMappedData() const { return mMappedData; }
U8* getMappedIndices() const { return mMappedIndexData; }
@@ -200,12 +218,19 @@ public:
void drawArrays(U32 mode, U32 offset, U32 count) const;
void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
+ //for debugging, validate data in given range is valid
+ void validateRange(U32 start, U32 end, U32 count, U32 offset) const;
+
+
+
protected:
S32 mNumVerts; // Number of vertices allocated
S32 mNumIndices; // Number of indices allocated
S32 mRequestedNumVerts; // Number of vertices requested
S32 mRequestedNumIndices; // Number of indices requested
+ ptrdiff_t mAlignedOffset;
+ ptrdiff_t mAlignedIndexOffset;
S32 mStride;
U32 mTypeMask;
S32 mUsage; // GL usage
@@ -220,7 +245,7 @@ protected:
S32 mOffsets[TYPE_MAX];
BOOL mResized; // if TRUE, client buffer has been resized and GL buffer has not
BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded)
-
+
class DirtyRegion
{
public: