summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2012-06-07 05:47:50 -0400
committerNat Goodspeed <nat@lindenlab.com>2012-06-07 05:47:50 -0400
commitce563795e1f5d7493b975393bea9ec5cab90fd6a (patch)
treeedc0b403ee80989bfa55b6d1cae3680093fb61fc /indra/llrender
parentd167ebe35f8cdec1ca88e0d817e2878f14a5aa68 (diff)
parent89ea7ccfc7fd4c33eab4ad9123141fa40231a00d (diff)
MAINT-1144: Merge llhttpclient_test.cpp fix back to tip
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/llcubemap.cpp25
-rw-r--r--indra/llrender/llfontfreetype.cpp7
-rw-r--r--indra/llrender/llfontgl.cpp108
-rw-r--r--indra/llrender/llfontgl.h9
-rw-r--r--indra/llrender/llgl.cpp404
-rw-r--r--indra/llrender/llgl.h17
-rw-r--r--indra/llrender/llglheaders.h55
-rw-r--r--indra/llrender/llglslshader.cpp95
-rw-r--r--indra/llrender/llglslshader.h12
-rw-r--r--indra/llrender/llimagegl.cpp112
-rw-r--r--indra/llrender/llpostprocess.cpp22
-rw-r--r--indra/llrender/llrender.cpp765
-rw-r--r--indra/llrender/llrender.h62
-rw-r--r--indra/llrender/llrendersphere.cpp98
-rw-r--r--indra/llrender/llrendersphere.h5
-rw-r--r--indra/llrender/llrendertarget.cpp115
-rw-r--r--indra/llrender/llrendertarget.h2
-rw-r--r--indra/llrender/llshadermgr.cpp462
-rw-r--r--indra/llrender/llshadermgr.h130
-rw-r--r--indra/llrender/llvertexbuffer.cpp1741
-rw-r--r--indra/llrender/llvertexbuffer.h181
21 files changed, 3109 insertions, 1318 deletions
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index 1b10354c22..45a3b18179 100644
--- a/indra/llrender/llcubemap.cpp
+++ b/indra/llrender/llcubemap.cpp
@@ -36,6 +36,7 @@
#include "m4math.h"
#include "llrender.h"
+#include "llglslshader.h"
#include "llglheaders.h"
@@ -195,7 +196,7 @@ void LLCubeMap::enableTexture(S32 stage)
void LLCubeMap::enableTextureCoords(S32 stage)
{
mTextureCoordStage = stage;
- if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
+ if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
{
if (stage > 0)
{
@@ -237,7 +238,7 @@ void LLCubeMap::disableTexture(void)
void LLCubeMap::disableTextureCoords(void)
{
- if (gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
+ if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
{
if (mTextureCoordStage > 0)
{
@@ -264,19 +265,19 @@ void LLCubeMap::setMatrix(S32 stage)
gGL.getTexUnit(stage)->activate();
}
- LLVector3 x(LLVector3d(gGLModelView+0));
- LLVector3 y(LLVector3d(gGLModelView+4));
- LLVector3 z(LLVector3d(gGLModelView+8));
+ LLVector3 x(gGLModelView+0);
+ LLVector3 y(gGLModelView+4);
+ LLVector3 z(gGLModelView+8);
LLMatrix3 mat3;
mat3.setRows(x,y,z);
LLMatrix4 trans(mat3);
trans.transpose();
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glLoadMatrixf((F32 *)trans.mMatrix);
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_TEXTURE);
+ gGL.pushMatrix();
+ gGL.loadMatrix((F32 *)trans.mMatrix);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
/*if (stage > 0)
{
@@ -292,9 +293,9 @@ void LLCubeMap::restoreMatrix()
{
gGL.getTexUnit(mMatrixStage)->activate();
}
- glMatrixMode(GL_TEXTURE);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_TEXTURE);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
/*if (mMatrixStage > 0)
{
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index 91c8a37022..66d4ad2d87 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -55,7 +55,10 @@ FT_Library gFTLibrary = NULL;
//static
void LLFontManager::initClass()
{
- gFontManagerp = new LLFontManager;
+ if (!gFontManagerp)
+ {
+ gFontManagerp = new LLFontManager;
+ }
}
//static
@@ -136,7 +139,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
FT_Done_Face(mFTFace);
mFTFace = NULL;
}
-
+
int error;
error = FT_New_Face( gFTLibrary,
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 607473d416..fccbf37a8d 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -56,8 +56,9 @@ std::string LLFontGL::sAppDir;
LLColor4 LLFontGL::sShadowColor(0.f, 0.f, 0.f, 1.f);
LLFontRegistry* LLFontGL::sFontRegistry = NULL;
-LLCoordFont LLFontGL::sCurOrigin;
-std::vector<LLCoordFont> LLFontGL::sOriginStack;
+LLCoordGL LLFontGL::sCurOrigin;
+F32 LLFontGL::sCurDepth;
+std::vector<std::pair<LLCoordGL, F32> > LLFontGL::sOriginStack;
const F32 EXT_X_BEARING = 1.f;
const F32 EXT_Y_BEARING = 0.f;
@@ -68,20 +69,6 @@ const F32 PIXEL_CORRECTION_DISTANCE = 0.01f;
const F32 PAD_UVY = 0.5f; // half of vertical padding between glyphs in the glyph texture
const F32 DROP_SHADOW_SOFT_STRENGTH = 0.3f;
-static F32 llfont_round_x(F32 x)
-{
- //return llfloor((x-LLFontGL::sCurOrigin.mX)/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleX+LLFontGL::sCurOrigin.mX;
- //return llfloor(x/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleY;
- return x;
-}
-
-static F32 llfont_round_y(F32 y)
-{
- //return llfloor((y-LLFontGL::sCurOrigin.mY)/LLFontGL::sScaleY+0.5f)*LLFontGL::sScaleY+LLFontGL::sCurOrigin.mY;
- //return llfloor(y+0.5f);
- return y;
-}
-
LLFontGL::LLFontGL()
{
}
@@ -115,23 +102,23 @@ static LLFastTimer::DeclareTimer FTM_RENDER_FONTS("Fonts");
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const
{
- F32 x = rect.mLeft;
+ F32 x = (F32)rect.mLeft;
F32 y = 0.f;
switch(valign)
{
case TOP:
- y = rect.mTop;
+ y = (F32)rect.mTop;
break;
case VCENTER:
- y = rect.getCenterY();
+ y = (F32)rect.getCenterY();
break;
case BASELINE:
case BOTTOM:
- y = rect.mBottom;
+ y = (F32)rect.mBottom;
break;
default:
- y = rect.mBottom;
+ y = (F32)rect.mBottom;
break;
}
return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses);
@@ -177,21 +164,11 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
gGL.loadUIIdentity();
- //gGL.translateUI(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
-
- // this code snaps the text origin to a pixel grid to start with
- //F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
- //F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
- //gGL.translateUI(-pixel_offset_x, -pixel_offset_y, 0.f);
-
LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY));
- // snap the text origin to a pixel grid to start with
- origin.mV[VX] -= llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
- origin.mV[VY] -= llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
- // Depth translation, so that floating text appears 'inworld'
- // and is correclty occluded.
- gGL.translatef(0.f,0.f,sCurOrigin.mZ);
+ // Depth translation, so that floating text appears 'in-world'
+ // and is correctly occluded.
+ gGL.translatef(0.f,0.f,sCurDepth);
S32 chars_drawn = 0;
S32 i;
@@ -215,16 +192,17 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
cur_y = ((F32)y * sScaleY) + origin.mV[VY];
// Offset y by vertical alignment.
+ // use unscaled font metrics here
switch (valign)
{
case TOP:
- cur_y -= mFontFreetype->getAscenderHeight();
+ cur_y -= llceil(mFontFreetype->getAscenderHeight());
break;
case BOTTOM:
- cur_y += mFontFreetype->getDescenderHeight();
+ cur_y += llceil(mFontFreetype->getDescenderHeight());
break;
case VCENTER:
- cur_y -= (mFontFreetype->getAscenderHeight() - mFontFreetype->getDescenderHeight()) / 2.f;
+ cur_y -= llceil((llceil(mFontFreetype->getAscenderHeight()) - llceil(mFontFreetype->getDescenderHeight())) / 2.f);
break;
case BASELINE:
// Baseline, do nothing.
@@ -250,7 +228,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
cur_render_y = cur_y;
cur_render_x = cur_x;
- F32 start_x = llround(cur_x);
+ F32 start_x = (F32)llround(cur_x);
const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();
@@ -304,6 +282,18 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
S32 next_bitmap_num = fgi->mBitmapNum;
if (next_bitmap_num != bitmap_num)
{
+ // Actually draw the queued glyphs before switching their texture;
+ // otherwise the queued glyphs will be taken from wrong textures.
+ if (glyph_count > 0)
+ {
+ gGL.begin(LLRender::QUADS);
+ {
+ gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
+ }
+ gGL.end();
+ glyph_count = 0;
+ }
+
bitmap_num = next_bitmap_num;
LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num);
gGL.getTexUnit(0)->bind(font_image);
@@ -322,10 +312,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
(fgi->mXBitmapOffset + fgi->mWidth) * inv_width,
(fgi->mYBitmapOffset - PAD_UVY) * inv_height);
// snap glyph origin to whole screen pixel
- LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing),
- llround(cur_render_y + (F32)fgi->mYBearing),
- llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
- llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
+ LLRectf screen_rect((F32)llround(cur_render_x + (F32)fgi->mXBearing),
+ (F32)llround(cur_render_y + (F32)fgi->mYBearing),
+ (F32)llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
+ (F32)llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
if (glyph_count >= GLYPH_BATCH_SIZE)
{
@@ -378,12 +368,12 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
//FIXME: add underline as glyph?
if (style_to_add & UNDERLINE)
{
- F32 descender = mFontFreetype->getDescenderHeight();
+ F32 descender = (F32)llfloor(mFontFreetype->getDescenderHeight());
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.begin(LLRender::LINES);
- gGL.vertex2f(start_x, cur_y - (descender));
- gGL.vertex2f(cur_x, cur_y - (descender));
+ gGL.vertex2f(start_x, cur_y - descender);
+ gGL.vertex2f(cur_x, cur_y - descender);
gGL.end();
}
@@ -432,19 +422,9 @@ S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y
}
// font metrics - override for LLFontFreetype that returns units of virtual pixels
-F32 LLFontGL::getLineHeight() const
-{
- return (F32)llround(mFontFreetype->getLineHeight() / sScaleY);
-}
-
-F32 LLFontGL::getAscenderHeight() const
+S32 LLFontGL::getLineHeight() const
{
- return (F32)llround(mFontFreetype->getAscenderHeight() / sScaleY);
-}
-
-F32 LLFontGL::getDescenderHeight() const
-{
- return (F32)llround(mFontFreetype->getDescenderHeight() / sScaleY);
+ return llceil(mFontFreetype->getAscenderHeight() / sScaleY) + llceil(mFontFreetype->getDescenderHeight() / sScaleY);
}
S32 LLFontGL::getWidth(const std::string& utf8text) const
@@ -633,7 +613,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
}
// Round after kerning.
- cur_x = llround(cur_x);
+ cur_x = (F32)llround(cur_x);
drawn_x = cur_x;
}
@@ -704,7 +684,7 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_
}
// Round after kerning.
- total_width = llround(total_width);
+ total_width = (F32)llround(total_width);
}
if (drawable_chars == 0)
@@ -787,7 +767,7 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 t
// Round after kerning.
- cur_x = llround(cur_x);
+ cur_x = (F32)llround(cur_x);
}
return llmin(max_chars, pos - begin_offset);
@@ -1134,22 +1114,22 @@ void LLFontGL::renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* c
{
S32 index = 0;
- vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mRight), llfont_round_y(screen_rect.mTop), 0.f);
+ vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mTop, 0.f);
uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
colors_out[index] = color;
index++;
- vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mLeft), llfont_round_y(screen_rect.mTop), 0.f);
+ vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 0.f);
uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
colors_out[index] = color;
index++;
- vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mLeft), llfont_round_y(screen_rect.mBottom), 0.f);
+ vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 0.f);
uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
colors_out[index] = color;
index++;
- vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mRight), llfont_round_y(screen_rect.mBottom), 0.f);
+ vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 0.f);
uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
colors_out[index] = color;
}
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index dc8d848ed2..74bdbb43e7 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -115,9 +115,7 @@ public:
S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const;
// font metrics - override for LLFontFreetype that returns units of virtual pixels
- F32 getLineHeight() const;
- F32 getAscenderHeight() const;
- F32 getDescenderHeight() const;
+ S32 getLineHeight() const;
S32 getWidth(const std::string& utf8text) const;
S32 getWidth(const llwchar* wchars) const;
@@ -188,8 +186,9 @@ public:
static std::string getFontPathLocal();
static std::string getFontPathSystem();
- static LLCoordFont sCurOrigin;
- static std::vector<LLCoordFont> sOriginStack;
+ static LLCoordGL sCurOrigin;
+ static F32 sCurDepth;
+ static std::vector<std::pair<LLCoordGL, F32> > sOriginStack;
static LLColor4 sShadowColor;
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 4e3cfb9c8a..197bc2b422 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -67,6 +67,38 @@ static const std::string HEADLESS_VERSION_STRING("1.0");
std::ofstream gFailLog;
+#if GL_ARB_debug_output
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+
+void APIENTRY gl_debug_callback(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar* message,
+ GLvoid* userParam)
+{
+ if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+ {
+ llwarns << "----- GL ERROR --------" << llendl;
+ }
+ else
+ {
+ llwarns << "----- GL WARNING -------" << llendl;
+ }
+ llwarns << "Type: " << std::hex << type << llendl;
+ llwarns << "ID: " << std::hex << id << llendl;
+ llwarns << "Severity: " << std::hex << severity << llendl;
+ llwarns << "Message: " << message << llendl;
+ llwarns << "-----------------------" << llendl;
+}
+#endif
+
+void parse_glsl_version(S32& major, S32& minor);
+
void ll_init_fail_log(std::string filename)
{
gFailLog.open(filename.c_str());
@@ -110,6 +142,11 @@ std::list<LLGLUpdate*> LLGLUpdate::sGLQ;
#if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS
// ATI prototypes
+
+#if LL_WINDOWS
+PFNGLGETSTRINGIPROC glGetStringi = NULL;
+#endif
+
// vertex blending prototypes
PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB = NULL;
PFNGLVERTEXBLENDARBPROC glVertexBlendARB = NULL;
@@ -128,6 +165,12 @@ PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL;
PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL;
+//GL_ARB_vertex_array_object
+PFNGLBINDVERTEXARRAYPROC glBindVertexArray = NULL;
+PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = NULL;
+PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = NULL;
+PFNGLISVERTEXARRAYPROC glIsVertexArray = NULL;
+
// GL_ARB_map_buffer_range
PFNGLMAPBUFFERRANGEPROC glMapBufferRange = NULL;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange = NULL;
@@ -197,10 +240,16 @@ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = NULL;
PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = NULL;
//GL_ARB_texture_multisample
-PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
-PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
-PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
-PFNGLSAMPLEMASKIPROC glSampleMaski;
+PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample = NULL;
+PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL;
+PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL;
+PFNGLSAMPLEMASKIPROC glSampleMaski = NULL;
+
+//GL_ARB_debug_output
+PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL;
+PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL;
+PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB = NULL;
+PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB = NULL;
// GL_EXT_blend_func_separate
PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
@@ -248,6 +297,11 @@ PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB = NULL;
PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB = NULL;
PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL;
PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL;
+PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer = NULL;
+
+#if LL_WINDOWS
+PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
+#endif
// vertex shader prototypes
#if LL_LINUX || LL_SOLARIS
@@ -349,6 +403,7 @@ LLGLManager::LLGLManager() :
mHasBlendFuncSeparate(FALSE),
mHasSync(FALSE),
mHasVertexBufferObject(FALSE),
+ mHasVertexArrayObject(FALSE),
mHasMapBufferRange(FALSE),
mHasFlushBufferRange(FALSE),
mHasPBuffer(FALSE),
@@ -370,6 +425,7 @@ LLGLManager::LLGLManager() :
mHasAnisotropic(FALSE),
mHasARBEnvCombine(FALSE),
mHasCubeMap(FALSE),
+ mHasDebugOutput(FALSE),
mIsATI(FALSE),
mIsNVIDIA(FALSE),
@@ -390,7 +446,8 @@ LLGLManager::LLGLManager() :
mDriverVersionMinor(0),
mDriverVersionRelease(0),
mGLVersion(1.0f),
-
+ mGLSLVersionMajor(0),
+ mGLSLVersionMinor(0),
mVRAM(0),
mGLMaxVertexRange(0),
mGLMaxIndexRange(0)
@@ -409,6 +466,15 @@ void LLGLManager::initWGL()
LL_WARNS("RenderInit") << "No ARB pixel format extensions" << LL_ENDL;
}
+ if (ExtensionExists("WGL_ARB_create_context",gGLHExts.mSysExts))
+ {
+ GLH_EXT_NAME(wglCreateContextAttribsARB) = (PFNWGLCREATECONTEXTATTRIBSARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreateContextAttribsARB");
+ }
+ else
+ {
+ LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL;
+ }
+
if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts))
{
GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT");
@@ -438,13 +504,45 @@ bool LLGLManager::initGL()
LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL;
}
- GLint alpha_bits;
- glGetIntegerv( GL_ALPHA_BITS, &alpha_bits );
- if( 8 != alpha_bits )
+ stop_glerror();
+
+#if LL_WINDOWS
+ if (!glGetStringi)
{
- LL_WARNS("RenderInit") << "Frame buffer has less than 8 bits of alpha. Avatar texture compositing will fail." << LL_ENDL;
+ glGetStringi = (PFNGLGETSTRINGIPROC) GLH_EXT_GET_PROC_ADDRESS("glGetStringi");
}
+ //reload extensions string (may have changed after using wglCreateContextAttrib)
+ if (glGetStringi)
+ {
+ std::stringstream str;
+
+ GLint count = 0;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &count);
+ for (GLint i = 0; i < count; ++i)
+ {
+ std::string ext((const char*) glGetStringi(GL_EXTENSIONS, i));
+ str << ext << " ";
+ LL_DEBUGS("GLExtensions") << ext << llendl;
+ }
+
+ {
+ PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
+ wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
+ if(wglGetExtensionsStringARB)
+ {
+ str << (const char*) wglGetExtensionsStringARB(wglGetCurrentDC());
+ }
+ }
+
+ free(gGLHExts.mSysExts);
+ std::string extensions = str.str();
+ gGLHExts.mSysExts = strdup(extensions.c_str());
+ }
+#endif
+
+ stop_glerror();
+
// Extract video card strings and convert to upper case to
// work around driver-to-driver variation in capitalization.
mGLVendor = std::string((const char *)glGetString(GL_VENDOR));
@@ -459,7 +557,21 @@ bool LLGLManager::initGL()
&mDriverVersionVendorString );
mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f;
-
+
+ if (mGLVersion >= 2.f)
+ {
+ parse_glsl_version(mGLSLVersionMajor, mGLSLVersionMinor);
+
+#if LL_DARWIN
+ //never use GLSL greater than 1.20 on OSX
+ if (mGLSLVersionMajor > 1 || mGLSLVersionMinor >= 30)
+ {
+ mGLSLVersionMajor = 1;
+ mGLSLVersionMinor = 20;
+ }
+#endif
+ }
+
// Trailing space necessary to keep "nVidia Corpor_ati_on" cards
// from being recognized as ATI.
if (mGLVendor.substr(0,4) == "ATI ")
@@ -531,8 +643,12 @@ bool LLGLManager::initGL()
mGLVendorShort = "MISC";
}
+ stop_glerror();
// This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture.
initExtensions();
+ stop_glerror();
+
+ S32 old_vram = mVRAM;
if (mHasATIMemInfo)
{ //ask the gl how much vram is free at startup and attempt to use no more than half of that
@@ -548,7 +664,27 @@ bool LLGLManager::initGL()
mVRAM = dedicated_memory/1024;
}
- if (mHasMultitexture)
+ if (mVRAM < 256)
+ { //something likely went wrong using the above extensions, fall back to old method
+ mVRAM = old_vram;
+ }
+
+ stop_glerror();
+
+ stop_glerror();
+
+ if (mHasFragmentShader)
+ {
+ GLint num_tex_image_units;
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units);
+ mNumTextureImageUnits = llmin(num_tex_image_units, 32);
+ }
+
+ if (LLRender::sGLCoreProfile)
+ {
+ mNumTextureUnits = llmin(mNumTextureImageUnits, MAX_GL_TEXTURE_UNITS);
+ }
+ else if (mHasMultitexture)
{
GLint num_tex_units;
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &num_tex_units);
@@ -567,12 +703,7 @@ bool LLGLManager::initGL()
return false;
}
- if (mHasFragmentShader)
- {
- GLint num_tex_image_units;
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units);
- mNumTextureImageUnits = llmin(num_tex_image_units, 32);
- }
+ stop_glerror();
if (mHasTextureMultisample)
{
@@ -582,6 +713,21 @@ bool LLGLManager::initGL()
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
}
+ stop_glerror();
+
+#if LL_WINDOWS
+ if (mHasDebugOutput && gDebugGL)
+ { //setup debug output callback
+ //glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE);
+ glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL);
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+ }
+#endif
+
+ stop_glerror();
+
+ //HACK always disable texture multisample, use FXAA instead
+ mHasTextureMultisample = FALSE;
#if LL_WINDOWS
if (mIsATI)
{ //using multisample textures on ATI results in black screen for some reason
@@ -593,10 +739,17 @@ bool LLGLManager::initGL()
{
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
}
+
+ stop_glerror();
setToDebugGPU();
+ stop_glerror();
+
initGLStates();
+
+ stop_glerror();
+
return true;
}
@@ -700,14 +853,6 @@ std::string LLGLManager::getRawGLString()
return gl_string;
}
-U32 LLGLManager::getNumFBOFSAASamples(U32 samples)
-{
- samples = llmin(samples, (U32) mMaxColorTextureSamples);
- samples = llmin(samples, (U32) mMaxDepthTextureSamples);
- samples = llmin(samples, (U32) 4);
- return samples;
-}
-
void LLGLManager::shutdownGL()
{
if (mInited)
@@ -774,7 +919,7 @@ void LLGLManager::initExtensions()
mHasVertexShader = FALSE;
mHasFragmentShader = FALSE;
mHasTextureRectangle = FALSE;
-#else // LL_MESA_HEADLESS
+#else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called
mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts);
mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
@@ -788,6 +933,7 @@ void LLGLManager::initExtensions()
mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
+ mHasVertexArrayObject = ExtensionExists("GL_ARB_vertex_array_object", gGLHExts.mSysExts);
mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts);
@@ -806,13 +952,14 @@ void LLGLManager::initExtensions()
mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts);
+ mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
#if !LL_DARWIN
mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
#endif
- mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
+ mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts)
- && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
- mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
+ && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
+ mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
#endif
#if LL_LINUX || LL_SOLARIS
@@ -985,6 +1132,13 @@ void LLGLManager::initExtensions()
mHasVertexBufferObject = FALSE;
}
}
+ if (mHasVertexArrayObject)
+ {
+ glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) GLH_EXT_GET_PROC_ADDRESS("glBindVertexArray");
+ glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteVertexArrays");
+ glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenVertexArrays");
+ glIsVertexArray = (PFNGLISVERTEXARRAYPROC) GLH_EXT_GET_PROC_ADDRESS("glIsVertexArray");
+ }
if (mHasSync)
{
glFenceSync = (PFNGLFENCESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glFenceSync");
@@ -1039,6 +1193,13 @@ void LLGLManager::initExtensions()
glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv");
glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski");
}
+ if (mHasDebugOutput)
+ {
+ glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB");
+ glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageInsertARB");
+ glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageCallbackARB");
+ glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetDebugMessageLogARB");
+ }
#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");
@@ -1157,6 +1318,7 @@ void LLGLManager::initExtensions()
glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB");
glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB");
glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB");
+ glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribIPointer");
glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB");
glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB");
glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB");
@@ -1193,7 +1355,7 @@ void rotate_quat(LLQuaternion& rotation)
{
F32 angle_radians, x, y, z;
rotation.getAngleAxis(&angle_radians, &x, &y, &z);
- glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
+ gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
}
void flush_glerror()
@@ -1230,10 +1392,6 @@ void log_glerror()
void do_assert_glerror()
{
- if (LL_UNLIKELY(!gGLManager.mInited))
- {
- LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL;
- }
// Create or update texture to be used with this data
GLenum error;
error = glGetError();
@@ -1326,11 +1484,6 @@ 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
@@ -1604,7 +1757,7 @@ void LLGLState::checkTextureChannels(const std::string& msg)
void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
{
- if (!gDebugGL)
+ if (!gDebugGL || LLGLSLShader::sNoFixedFunction)
{
return;
}
@@ -1625,7 +1778,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
error = TRUE;
}
- glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture);
+ /*glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture);
if (active_texture != GL_TEXTURE0_ARB)
{
llwarns << "Active texture corrupted: " << active_texture << llendl;
@@ -1634,7 +1787,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
gFailLog << "Active texture corrupted: " << active_texture << std::endl;
}
error = TRUE;
- }
+ }*/
static const char* label[] =
{
@@ -1661,7 +1814,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
};
- for (S32 j = 0; j < 4; j++)
+ for (S32 j = 1; j < 4; j++)
{
if (glIsEnabled(value[j]))
{
@@ -1783,17 +1936,26 @@ LLGLState::LLGLState(LLGLenum state, S32 enabled) :
mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
{
if (LLGLSLShader::sNoFixedFunction)
- { //always disable state that's deprecated post GL 3.0
+ { //always ignore state that's deprecated post GL 3.0
switch (state)
{
case GL_ALPHA_TEST:
- enabled = 0;
+ case GL_NORMALIZE:
+ case GL_TEXTURE_GEN_R:
+ case GL_TEXTURE_GEN_S:
+ case GL_TEXTURE_GEN_T:
+ case GL_TEXTURE_GEN_Q:
+ case GL_LIGHTING:
+ case GL_COLOR_MATERIAL:
+ case GL_FOG:
+ case GL_LINE_STIPPLE:
+ mState = 0;
break;
}
}
stop_glerror();
- if (state)
+ if (mState)
{
mWasEnabled = sStateMap[state];
llassert(mWasEnabled == glIsEnabled(state));
@@ -1875,79 +2037,6 @@ void LLGLManager::initGLStates()
////////////////////////////////////////////////////////////////////////////////
-void enable_vertex_weighting(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glEnableVertexAttribArrayARB(index); // vertex weights
-#endif
-}
-
-void disable_vertex_weighting(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glDisableVertexAttribArrayARB(index); // vertex weights
-#endif
-}
-
-void enable_binormals(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0)
- {
- glEnableVertexAttribArrayARB(index); // binormals
- }
-#endif
-}
-
-void disable_binormals(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0)
- {
- glDisableVertexAttribArrayARB(index); // binormals
- }
-#endif
-}
-
-
-void enable_cloth_weights(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glEnableVertexAttribArrayARB(index);
-#endif
-}
-
-void disable_cloth_weights(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glDisableVertexAttribArrayARB(index);
-#endif
-}
-
-void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glVertexAttribPointerARB(index, 1, GL_FLOAT, FALSE, stride, weights);
- stop_glerror();
-#endif
-}
-
-void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glVertexAttribPointerARB(index, 4, GL_FLOAT, TRUE, stride, weights);
- stop_glerror();
-#endif
-}
-
-void set_binormals(const S32 index, const U32 stride,const LLVector3 *binormals)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glVertexAttribPointerARB(index, 3, GL_FLOAT, FALSE, stride, binormals);
- stop_glerror();
-#endif
-}
-
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific )
{
// GL_VERSION returns a null-terminated string with the format:
@@ -2028,6 +2117,55 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor
}
}
+
+void parse_glsl_version(S32& major, S32& minor)
+{
+ // GL_SHADING_LANGUAGE_VERSION returns a null-terminated string with the format:
+ // <major>.<minor>[.<release>] [<vendor specific>]
+
+ const char* version = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION);
+ major = 0;
+ minor = 0;
+
+ if( !version )
+ {
+ return;
+ }
+
+ std::string ver_copy( version );
+ S32 len = (S32)strlen( version ); /* Flawfinder: ignore */
+ S32 i = 0;
+ S32 start;
+ // Find the major version
+ start = i;
+ for( ; i < len; i++ )
+ {
+ if( '.' == version[i] )
+ {
+ break;
+ }
+ }
+ std::string major_str = ver_copy.substr(start,i-start);
+ LLStringUtil::convertToS32(major_str, major);
+
+ if( '.' == version[i] )
+ {
+ i++;
+ }
+
+ // Find the minor version
+ start = i;
+ for( ; i < len; i++ )
+ {
+ if( ('.' == version[i]) || isspace(version[i]) )
+ {
+ break;
+ }
+ }
+ std::string minor_str = ver_copy.substr(start,i-start);
+ LLStringUtil::convertToS32(minor_str, minor);
+}
+
LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply)
{
mApply = apply;
@@ -2060,20 +2198,20 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
glh::matrix4f suffix;
suffix.set_row(2, cplane);
glh::matrix4f newP = suffix * P;
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixf(newP.m);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadMatrix(newP.m);
gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m);
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
}
LLGLUserClipPlane::~LLGLUserClipPlane()
{
if (mApply)
{
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
}
}
@@ -2263,16 +2401,16 @@ LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P, U32 layer)
P.element(2, i) = P.element(3, i) * depth;
}
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixf(P.m);
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadMatrix(P.m);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
}
LLGLSquashToFarClip::~LLGLSquashToFarClip()
{
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
}
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index d736133f3f..5a33c98708 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -88,6 +88,7 @@ public:
// ARB Extensions
BOOL mHasVertexBufferObject;
+ BOOL mHasVertexArrayObject;
BOOL mHasSync;
BOOL mHasMapBufferRange;
BOOL mHasFlushBufferRange;
@@ -112,6 +113,7 @@ public:
BOOL mHasAnisotropic;
BOOL mHasARBEnvCombine;
BOOL mHasCubeMap;
+ BOOL mHasDebugOutput;
// Vendor-specific extensions
BOOL mIsATI;
@@ -136,6 +138,8 @@ public:
S32 mDriverVersionMinor;
S32 mDriverVersionRelease;
F32 mGLVersion; // e.g = 1.4
+ S32 mGLSLVersionMajor;
+ S32 mGLSLVersionMinor;
std::string mDriverVersionVendorString;
S32 mVRAM; // VRAM in MB
@@ -148,7 +152,6 @@ public:
void printGLInfoString();
void getGLInfo(LLSD& info);
- U32 getNumFBOFSAASamples(U32 desired_samples = 32);
// In ALL CAPS
std::string mGLVendor;
std::string mGLVendorShort;
@@ -252,7 +255,7 @@ public:
static void dumpStates();
static void checkStates(const std::string& msg = "");
static void checkTextureChannels(const std::string& msg = "");
- static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0x0001);
+ static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0);
protected:
static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap;
@@ -419,15 +422,7 @@ extern LLMatrix4 gGLObliqueProjectionInverse;
#include "llglstates.h"
void init_glstates();
-void enable_vertex_weighting(const S32 index);
-void disable_vertex_weighting(const S32 index);
-void enable_binormals(const S32 index);
-void disable_binormals(const S32 index);
-void enable_cloth_weights(const S32 index);
-void disable_cloth_weights(const S32 index);
-void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights);
-void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights);
-void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals);
+
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );
extern BOOL gClothRipple;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 851a75629e..d61ec707f0 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -68,6 +68,12 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
+// GL_ARB_vertex_array_object
+extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
+extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
+extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
+extern PFNGLISVERTEXARRAYPROC glIsVertexArray;
+
// GL_ARB_sync
extern PFNGLFENCESYNCPROC glFenceSync;
extern PFNGLISSYNCPROC glIsSync;
@@ -193,6 +199,7 @@ extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB;
extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB;
extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB;
extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
+extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB;
extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
@@ -310,6 +317,12 @@ extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;
extern PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements;
#endif // LL_LINUX_NV_GL_HEADERS
+// GL_ARB_vertex_array_object
+extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
+extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
+extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
+extern PFNGLISVERTEXARRAYPROC glIsVertexArray;
+
// GL_ARB_vertex_buffer_object
extern PFNGLBINDBUFFERARBPROC glBindBufferARB;
extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB;
@@ -448,6 +461,7 @@ extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB;
extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB;
extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB;
extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
+extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB;
extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
@@ -531,6 +545,9 @@ extern PFNGLSAMPLEMASKIPROC glSampleMaski;
#include "GL/glext.h"
#include "GL/glh_extensions.h"
+// WGL_ARB_create_context
+extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
+extern PFNGLGETSTRINGIPROC glGetStringi;
// GL_ARB_vertex_buffer_object
extern PFNGLBINDBUFFERARBPROC glBindBufferARB;
@@ -545,6 +562,12 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
+// GL_ARB_vertex_array_object
+extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
+extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
+extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
+extern PFNGLISVERTEXARRAYPROC glIsVertexArray;
+
// GL_ARB_sync
extern PFNGLFENCESYNCPROC glFenceSync;
extern PFNGLISSYNCPROC glIsSync;
@@ -672,6 +695,7 @@ extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB;
extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB;
extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB;
extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
+extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB;
extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
@@ -735,6 +759,12 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
+//GL_ARB_debug_output
+extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
+extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
+extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
+extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB;
+
#elif LL_DARWIN
//----------------------------------------------------------------------------
// LL_DARWIN
@@ -899,6 +929,31 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
#endif /* GL_GLEXT_FUNCTION_POINTERS */
#endif
+#ifndef GL_ARB_texture_rg
+#define GL_RG 0x8227
+#define GL_RG_INTEGER 0x8228
+#define GL_R8 0x8229
+#define GL_R16 0x822A
+#define GL_RG8 0x822B
+#define GL_RG16 0x822C
+#define GL_R16F 0x822D
+#define GL_R32F 0x822E
+#define GL_RG16F 0x822F
+#define GL_RG32F 0x8230
+#define GL_R8I 0x8231
+#define GL_R8UI 0x8232
+#define GL_R16I 0x8233
+#define GL_R16UI 0x8234
+#define GL_R32I 0x8235
+#define GL_R32UI 0x8236
+#define GL_RG8I 0x8237
+#define GL_RG8UI 0x8238
+#define GL_RG16I 0x8239
+#define GL_RG16UI 0x823A
+#define GL_RG32I 0x823B
+#define GL_RG32UI 0x823C
+#endif
+
// May be needed for DARWIN...
// #ifndef GL_ARB_compressed_tex_image
// #define GL_ARB_compressed_tex_image 1
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index f51d83abe4..4b7e639aed 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -31,6 +31,7 @@
#include "llshadermgr.h"
#include "llfile.h"
#include "llrender.h"
+#include "llvertexbuffer.h"
#if LL_DARWIN
#include "OpenGL/OpenGL.h"
@@ -50,6 +51,7 @@ using std::string;
GLhandleARB LLGLSLShader::sCurBoundShader = 0;
LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
+S32 LLGLSLShader::sIndexedTextureChannels = 0;
bool LLGLSLShader::sNoFixedFunction = false;
//UI shader -- declared here so llui_libtest will link properly
@@ -62,10 +64,23 @@ BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
}
LLShaderFeatures::LLShaderFeatures()
-: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
-hasTransport(false), hasSkinning(false), hasObjectSkinning(false), hasAtmospherics(false), isSpecular(false),
-hasGamma(false), hasLighting(false), calculatesAtmospherics(false), mIndexedTextureChannels(0), disableTextureIndex(false),
-hasAlphaMask(false)
+ : atmosphericHelpers(false)
+ , calculatesLighting(false)
+ , calculatesAtmospherics(false)
+ , hasLighting(false)
+ , isAlphaLighting(false)
+ , isShiny(false)
+ , isFullbright(false)
+ , isSpecular(false)
+ , hasWaterFog(false)
+ , hasTransport(false)
+ , hasSkinning(false)
+ , hasObjectSkinning(false)
+ , hasAtmospherics(false)
+ , hasGamma(false)
+ , mIndexedTextureChannels(0)
+ , disableTextureIndex(false)
+ , hasAlphaMask(false)
{
}
@@ -75,6 +90,7 @@ hasAlphaMask(false)
LLGLSLShader::LLGLSLShader()
: mProgramObject(0), mActiveTextureChannels(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT), mUniformsDirty(FALSE)
{
+
}
void LLGLSLShader::unload()
@@ -93,7 +109,12 @@ void LLGLSLShader::unload()
glGetAttachedObjectsARB(mProgramObject, 1024, &count, obj);
for (GLsizei i = 0; i < count; i++)
{
- glDeleteObjectARB(obj[i]);
+#if !LL_DARWIN
+ if (glIsProgramARB(obj[i]))
+#endif
+ {
+ glDeleteObjectARB(obj[i]);
+ }
}
glDeleteObjectARB(mProgramObject);
@@ -110,17 +131,19 @@ void LLGLSLShader::unload()
BOOL LLGLSLShader::createShader(vector<string> * attributes,
vector<string> * uniforms)
{
+ //reloading, reset matrix hash values
+ for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i)
+ {
+ mMatHash[i] = 0xFFFFFFFF;
+ }
+ mLightHash = 0xFFFFFFFF;
+
llassert_always(!mShaderFiles.empty());
BOOL success = TRUE;
// Create program
mProgramObject = glCreateProgramObjectARB();
- if (gGLManager.mGLVersion < 3.1f)
- { //force indexed texture channels to 1 if GL version is old (performance improvement for drivers with poor branching shader model support)
- mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
- }
-
//compile new source
vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
for ( ; fileIter != mShaderFiles.end(); fileIter++ )
@@ -143,8 +166,9 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
return FALSE;
}
- if (gGLManager.mGLVersion < 3.1f)
- { //attachShaderFeatures may have set the number of indexed texture channels, so set to 1 again
+ if (gGLManager.mGLSLVersionMajor < 2 && gGLManager.mGLSLVersionMinor < 3)
+ { //indexed texture rendering requires GLSL 1.3 or later
+ //attachShaderFeatures may have set the number of indexed texture channels, so set to 1 again
mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
}
@@ -235,6 +259,13 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count)
BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
{
+ //before linking, make sure reserved attributes always have consistent locations
+ for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
+ {
+ const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str();
+ glBindAttribLocationARB(mProgramObject, i, (const GLcharARB *) name);
+ }
+
//link the program
BOOL res = link();
@@ -308,7 +339,7 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
for (S32 i = 0; i < (S32) LLShaderMgr::instance()->mReservedUniforms.size(); i++)
{
if ( (mUniform[i] == -1)
- && (LLShaderMgr::instance()->mReservedUniforms[i].compare(0, length, name, LLShaderMgr::instance()->mReservedUniforms[i].length()) == 0))
+ && (LLShaderMgr::instance()->mReservedUniforms[i] == name))
{
//found it
mUniform[i] = location;
@@ -322,7 +353,7 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
for (U32 i = 0; i < uniforms->size(); i++)
{
if ( (mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] == -1)
- && ((*uniforms)[i].compare(0, length, name, (*uniforms)[i].length()) == 0))
+ && ((*uniforms)[i] == name))
{
//found it
mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] = location;
@@ -386,6 +417,7 @@ void LLGLSLShader::bind()
gGL.flush();
if (gGLManager.mHasShaderObjects)
{
+ LLVertexBuffer::unbind();
glUseProgramObjectARB(mProgramObject);
sCurBoundShader = mProgramObject;
sCurBoundShaderPtr = this;
@@ -411,6 +443,7 @@ void LLGLSLShader::unbind()
stop_glerror();
}
}
+ LLVertexBuffer::unbind();
glUseProgramObjectARB(0);
sCurBoundShader = 0;
sCurBoundShaderPtr = NULL;
@@ -420,9 +453,13 @@ void LLGLSLShader::unbind()
void LLGLSLShader::bindNoShader(void)
{
- glUseProgramObjectARB(0);
- sCurBoundShader = 0;
- sCurBoundShaderPtr = NULL;
+ LLVertexBuffer::unbind();
+ if (gGLManager.mHasShaderObjects)
+ {
+ glUseProgramObjectARB(0);
+ sCurBoundShader = 0;
+ sCurBoundShaderPtr = NULL;
+ }
}
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode)
@@ -768,13 +805,17 @@ GLint LLGLSLShader::getUniformLocation(const string& uniform)
}
}
- /*if (gDebugGL)
+ return ret;
+}
+
+GLint LLGLSLShader::getUniformLocation(U32 index)
+{
+ GLint ret = -1;
+ if (mProgramObject > 0)
{
- if (ret == -1 && ret != glGetUniformLocationARB(mProgramObject, uniform.c_str()))
- {
- llerrs << "Uniform map invalid." << llendl;
- }
- }*/
+ llassert(index < mUniform.size());
+ return mUniform[index];
+ }
return ret;
}
@@ -930,7 +971,9 @@ void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v
std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
{
+ stop_glerror();
glUniform4fvARB(location, count, v);
+ stop_glerror();
mValue[location] = vec;
}
}
@@ -985,8 +1028,8 @@ void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v)
}
}
-void LLGLSLShader::setAlphaRange(F32 minimum, F32 maximum)
+void LLGLSLShader::setMinimumAlpha(F32 minimum)
{
- uniform1f("minimum_alpha", minimum);
- uniform1f("maximum_alpha", maximum);
+ gGL.flush();
+ uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum);
}
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 558ea66b50..7873fe3c4e 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -33,9 +33,11 @@
class LLShaderFeatures
{
public:
+ bool atmosphericHelpers;
bool calculatesLighting;
bool calculatesAtmospherics;
bool hasLighting; // implies no transport (it's possible to have neither though)
+ bool isAlphaLighting; // indicates lighting shaders need not be linked in (lighting performed directly in alpha shader to match deferred lighting functions)
bool isShiny;
bool isFullbright; // implies no lighting
bool isSpecular;
@@ -69,7 +71,7 @@ public:
static GLhandleARB sCurBoundShader;
static LLGLSLShader* sCurBoundShaderPtr;
-
+ static S32 sIndexedTextureChannels;
static bool sNoFixedFunction;
void unload();
@@ -108,16 +110,17 @@ public:
void uniformMatrix3fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
void uniformMatrix4fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
- void setAlphaRange(F32 minimum, F32 maximum);
+ void setMinimumAlpha(F32 minimum);
void vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void vertexAttrib4fv(U32 index, GLfloat* v);
GLint getUniformLocation(const std::string& uniform);
+ GLint getUniformLocation(U32 index);
+
GLint getAttribLocation(U32 attrib);
GLint mapUniformTextureChannel(GLint location, GLenum type);
-
//enable/disable texture channel for specified uniform
//if given texture uniform is active in the shader,
//the corresponding channel will be active upon return
@@ -132,6 +135,9 @@ public:
// Unbinds any previously bound shader by explicitly binding no shader.
static void bindNoShader(void);
+ U32 mMatHash[LLRender::NUM_MATRIX_MODES];
+ U32 mLightHash;
+
GLhandleARB mProgramObject;
std::vector<GLint> mAttribute; //lookup table of attribute enum to attribute channel
std::vector<GLint> mUniform; //lookup table of uniform enum to uniform location
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 7188b0fa44..78591ddd38 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -36,7 +36,9 @@
#include "llmath.h"
#include "llgl.h"
+#include "llglslshader.h"
#include "llrender.h"
+
//----------------------------------------------------------------------------
const F32 MIN_TEXTURE_LIFETIME = 10.f;
@@ -725,7 +727,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
{
if (mAutoGenMips)
{
- glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
+ if (!gGLManager.mHasFramebufferObject)
+ {
+ glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
+ }
stop_glerror();
{
// LLFastTimer t2(FTM_TEMP4);
@@ -754,6 +759,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
stop_glerror();
}
}
+
+ if (gGLManager.mHasFramebufferObject)
+ {
+ glGenerateMipmap(LLTexUnit::getInternalType(mBindTarget));
+ }
}
else
{
@@ -875,6 +885,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
{
+ //not compatible with core GL profile
+ llassert(!LLRender::sGLCoreProfile);
+
if (gGLManager.mIsDisabled)
{
llwarns << "Trying to create a texture while GL is disabled!" << llendl;
@@ -901,29 +914,29 @@ BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
{
switch (mComponents)
{
- case 1:
+ case 1:
// Use luminance alpha (for fonts)
mFormatInternal = GL_LUMINANCE8;
mFormatPrimary = GL_LUMINANCE;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 2:
+ case 2:
// Use luminance alpha (for fonts)
mFormatInternal = GL_LUMINANCE8_ALPHA8;
mFormatPrimary = GL_LUMINANCE_ALPHA;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 3:
+ case 3:
mFormatInternal = GL_RGB8;
mFormatPrimary = GL_RGB;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 4:
+ case 4:
mFormatInternal = GL_RGBA8;
mFormatPrimary = GL_RGBA;
mFormatType = GL_UNSIGNED_BYTE;
break;
- default:
+ default:
llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
}
}
@@ -1099,8 +1112,75 @@ void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate)
// 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);
+ bool use_scratch = false;
+ U32* scratch = NULL;
+ if (LLRender::sGLCoreProfile)
+ {
+ if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+ { //GL_ALPHA is deprecated, convert to RGBA
+ use_scratch = true;
+ scratch = new U32[width*height];
+
+ U32 pixel_count = (U32) (width*height);
+ for (U32 i = 0; i < pixel_count; i++)
+ {
+ U8* pix = (U8*) &scratch[i];
+ pix[0] = pix[1] = pix[2] = 0;
+ pix[3] = ((U8*) pixels)[i];
+ }
+
+ pixformat = GL_RGBA;
+ intformat = GL_RGBA8;
+ }
+
+ if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+ { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
+ use_scratch = true;
+ scratch = new U32[width*height];
+
+ U32 pixel_count = (U32) (width*height);
+ for (U32 i = 0; i < pixel_count; i++)
+ {
+ U8 lum = ((U8*) pixels)[i*2+0];
+ U8 alpha = ((U8*) pixels)[i*2+1];
+
+ U8* pix = (U8*) &scratch[i];
+ pix[0] = pix[1] = pix[2] = lum;
+ pix[3] = alpha;
+ }
+
+ pixformat = GL_RGBA;
+ intformat = GL_RGBA8;
+ }
+
+ if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
+ { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
+ use_scratch = true;
+ scratch = new U32[width*height];
+
+ U32 pixel_count = (U32) (width*height);
+ for (U32 i = 0; i < pixel_count; i++)
+ {
+ U8 lum = ((U8*) pixels)[i];
+
+ U8* pix = (U8*) &scratch[i];
+ pix[0] = pix[1] = pix[2] = lum;
+ pix[3] = 255;
+ }
+
+ pixformat = GL_RGBA;
+ intformat = GL_RGB8;
+ }
+ }
+
stop_glerror();
+ glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
+ stop_glerror();
+
+ if (use_scratch)
+ {
+ delete [] scratch;
+ }
}
//create an empty GL texture: just create a texture name
@@ -1167,29 +1247,29 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
{
switch (mComponents)
{
- case 1:
+ case 1:
// Use luminance alpha (for fonts)
mFormatInternal = GL_LUMINANCE8;
mFormatPrimary = GL_LUMINANCE;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 2:
+ case 2:
// Use luminance alpha (for fonts)
mFormatInternal = GL_LUMINANCE8_ALPHA8;
mFormatPrimary = GL_LUMINANCE_ALPHA;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 3:
+ case 3:
mFormatInternal = GL_RGB8;
mFormatPrimary = GL_RGB;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 4:
+ case 4:
mFormatInternal = GL_RGBA8;
mFormatPrimary = GL_RGBA;
mFormatType = GL_UNSIGNED_BYTE;
break;
- default:
+ default:
llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
}
@@ -1212,6 +1292,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)
{
llassert(data_in);
+ stop_glerror();
if (discard_level < 0)
{
@@ -1240,8 +1321,11 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
stop_glerror();
{
llverify(gGL.getTexUnit(0)->bind(this));
+ stop_glerror();
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);
+ stop_glerror();
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel-discard_level);
+ stop_glerror();
}
}
if (!mTexName)
@@ -1754,7 +1838,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
// this to be an intentional effect and don't treat as a mask.
U32 midrangetotal = 0;
- for (U32 i = 4; i < 11; i++)
+ for (U32 i = 2; i < 13; i++)
{
midrangetotal += sample[i];
}
@@ -1769,7 +1853,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
upperhalftotal += sample[i];
}
- if (midrangetotal > length/16 || // lots of midrange, or
+ if (midrangetotal > length/48 || // 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
{
diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp
index d76b2d9004..c0045c8044 100644
--- a/indra/llrender/llpostprocess.cpp
+++ b/indra/llrender/llpostprocess.cpp
@@ -466,21 +466,21 @@ void LLPostProcess::drawOrthoQuad(unsigned int width, unsigned int height, QuadT
void LLPostProcess::viewOrthogonal(unsigned int width, unsigned int height)
{
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f );
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.ortho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f );
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
}
void LLPostProcess::viewPerspective(void)
{
- glMatrixMode( GL_PROJECTION );
- glPopMatrix();
- glMatrixMode( GL_MODELVIEW );
- glPopMatrix();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
}
void LLPostProcess::changeOrthogonal(unsigned int width, unsigned int height)
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index edcc47aa14..b0ddacbb05 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -1,4 +1,4 @@
-/**
+ /**
* @file llrender.cpp
* @brief LLRender implementation
*
@@ -34,19 +34,21 @@
#include "llimagegl.h"
#include "llrendertarget.h"
#include "lltexture.h"
+#include "llshadermgr.h"
LLRender gGL;
// Handy copies of last good GL matrices
-F64 gGLModelView[16];
-F64 gGLLastModelView[16];
-F64 gGLLastProjection[16];
-F64 gGLProjection[16];
+F32 gGLModelView[16];
+F32 gGLLastModelView[16];
+F32 gGLLastProjection[16];
+F32 gGLProjection[16];
S32 gGLViewport[4];
U32 LLRender::sUICalls = 0;
U32 LLRender::sUIVerts = 0;
U32 LLTexUnit::sWhiteTexture = 0;
+bool LLRender::sGLCoreProfile = false;
static const U32 LL_NUM_TEXTURE_LAYERS = 32;
static const U32 LL_NUM_LIGHT_UNITS = 8;
@@ -178,10 +180,13 @@ void LLTexUnit::enable(eTextureType type)
if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) )
{
+ stop_glerror();
activate();
+ stop_glerror();
if (mCurrTexType != TT_NONE && !gGL.mDirty)
{
disable(); // Force a disable of a previous texture type if it's enabled.
+ stop_glerror();
}
mCurrTexType = type;
@@ -190,7 +195,9 @@ void LLTexUnit::enable(eTextureType type)
type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
mIndex < gGLManager.mNumTextureUnits)
{
+ stop_glerror();
glEnable(sGLTextureType[type]);
+ stop_glerror();
}
}
}
@@ -286,26 +293,35 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
{
return bind(LLImageGL::sDefaultGLTexture) ;
}
+ stop_glerror();
return false ;
}
if ((mCurrTexture != texture->getTexName()) || forceBind)
{
gGL.flush();
+ stop_glerror();
activate();
+ stop_glerror();
enable(texture->getTarget());
+ stop_glerror();
mCurrTexture = texture->getTexName();
glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture);
+ stop_glerror();
texture->updateBindStats(texture->mTextureMemory);
mHasMipMaps = texture->mHasMipMaps;
if (texture->mTexOptionsDirty)
{
+ stop_glerror();
texture->mTexOptionsDirty = false;
setTextureAddressMode(texture->mAddressMode);
setTextureFilteringOption(texture->mFilterOption);
+ stop_glerror();
}
}
+ stop_glerror();
+
return true;
}
@@ -814,14 +830,16 @@ LLLightState::LLLightState(S32 index)
mAmbient.set(0,0,0,1);
mPosition.set(0,0,1,0);
mSpotDirection.set(0,0,-1);
-
}
void LLLightState::enable()
{
if (!mEnabled)
{
- glEnable(GL_LIGHT0+mIndex);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glEnable(GL_LIGHT0+mIndex);
+ }
mEnabled = true;
}
}
@@ -830,7 +848,10 @@ void LLLightState::disable()
{
if (mEnabled)
{
- glDisable(GL_LIGHT0+mIndex);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glDisable(GL_LIGHT0+mIndex);
+ }
mEnabled = false;
}
}
@@ -839,8 +860,12 @@ void LLLightState::setDiffuse(const LLColor4& diffuse)
{
if (mDiffuse != diffuse)
{
+ ++gGL.mLightHash;
mDiffuse = diffuse;
- glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV);
+ }
}
}
@@ -848,8 +873,12 @@ void LLLightState::setAmbient(const LLColor4& ambient)
{
if (mAmbient != ambient)
{
+ ++gGL.mLightHash;
mAmbient = ambient;
- glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV);
+ }
}
}
@@ -857,16 +886,34 @@ void LLLightState::setSpecular(const LLColor4& specular)
{
if (mSpecular != specular)
{
+ ++gGL.mLightHash;
mSpecular = specular;
- glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV);
+ }
}
}
void LLLightState::setPosition(const LLVector4& position)
{
//always set position because modelview matrix may have changed
+ ++gGL.mLightHash;
mPosition = position;
- glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV);
+ }
+ else
+ { //transform position by current modelview matrix
+ glh::vec4f pos(position.mV);
+
+ const glh::matrix4f& mat = gGL.getModelviewMatrix();
+ mat.mult_matrix_vec(pos);
+
+ mPosition.set(pos.v);
+ }
+
}
void LLLightState::setConstantAttenuation(const F32& atten)
@@ -874,7 +921,11 @@ void LLLightState::setConstantAttenuation(const F32& atten)
if (mConstantAtten != atten)
{
mConstantAtten = atten;
- glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten);
+ ++gGL.mLightHash;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten);
+ }
}
}
@@ -882,8 +933,12 @@ void LLLightState::setLinearAttenuation(const F32& atten)
{
if (mLinearAtten != atten)
{
+ ++gGL.mLightHash;
mLinearAtten = atten;
- glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten);
+ }
}
}
@@ -891,8 +946,12 @@ void LLLightState::setQuadraticAttenuation(const F32& atten)
{
if (mQuadraticAtten != atten)
{
+ ++gGL.mLightHash;
mQuadraticAtten = atten;
- glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten);
+ }
}
}
@@ -900,8 +959,12 @@ void LLLightState::setSpotExponent(const F32& exponent)
{
if (mSpotExponent != exponent)
{
+ ++gGL.mLightHash;
mSpotExponent = exponent;
- glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent);
+ }
}
}
@@ -909,21 +972,39 @@ void LLLightState::setSpotCutoff(const F32& cutoff)
{
if (mSpotCutoff != cutoff)
{
+ ++gGL.mLightHash;
mSpotCutoff = cutoff;
- glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff);
+ }
}
}
void LLLightState::setSpotDirection(const LLVector3& direction)
{
//always set direction because modelview matrix may have changed
+ ++gGL.mLightHash;
mSpotDirection = direction;
- glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV);
+ }
+ else
+ { //transform direction by current modelview matrix
+ glh::vec3f dir(direction.mV);
+
+ const glh::matrix4f& mat = gGL.getModelviewMatrix();
+ mat.mult_matrix_dir(dir);
+
+ mSpotDirection.set(dir.v);
+ }
}
LLRender::LLRender()
: mDirty(false),
mCount(0),
+ mQuadCycle(0),
mMode(LLRender::TRIANGLES),
mCurrTextureUnitIndex(0),
mMaxAnisotropy(0.f)
@@ -951,6 +1032,17 @@ LLRender::LLRender()
mCurrBlendAlphaSFactor = BF_UNDEF;
mCurrBlendColorDFactor = BF_UNDEF;
mCurrBlendAlphaDFactor = BF_UNDEF;
+
+ mMatrixMode = LLRender::MM_MODELVIEW;
+
+ for (U32 i = 0; i < NUM_MATRIX_MODES; ++i)
+ {
+ mMatIdx[i] = 0;
+ mMatHash[i] = 0;
+ mCurMatHash[i] = 0xFFFFFFFF;
+ }
+
+ mLightHash = 0;
}
LLRender::~LLRender()
@@ -961,12 +1053,13 @@ LLRender::~LLRender()
void LLRender::init()
{
llassert_always(mBuffer.isNull()) ;
-
+ stop_glerror();
mBuffer = new LLVertexBuffer(immediate_mask, 0);
mBuffer->allocateBuffer(4096, 0, TRUE);
mBuffer->getVertexStrider(mVerticesp);
mBuffer->getTexCoord0Strider(mTexcoordsp);
mBuffer->getColorStrider(mColorsp);
+ stop_glerror();
}
void LLRender::shutdown()
@@ -1007,28 +1100,355 @@ void LLRender::refreshState(void)
mDirty = false;
}
+void LLRender::syncLightState()
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (!shader)
+ {
+ return;
+ }
+
+ if (shader->mLightHash != mLightHash)
+ {
+ shader->mLightHash = mLightHash;
+
+ LLVector4 position[8];
+ LLVector3 direction[8];
+ LLVector3 attenuation[8];
+ LLVector3 diffuse[8];
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ LLLightState* light = mLightState[i];
+
+ position[i] = light->mPosition;
+ direction[i] = light->mSpotDirection;
+ attenuation[i].set(light->mLinearAtten, light->mQuadraticAtten, light->mSpecular.mV[3]);
+ diffuse[i].set(light->mDiffuse.mV);
+ }
+
+ shader->uniform4fv(LLShaderMgr::LIGHT_POSITION, 8, position[0].mV);
+ shader->uniform3fv(LLShaderMgr::LIGHT_DIRECTION, 8, direction[0].mV);
+ shader->uniform3fv(LLShaderMgr::LIGHT_ATTENUATION, 8, attenuation[0].mV);
+ shader->uniform3fv(LLShaderMgr::LIGHT_DIFFUSE, 8, diffuse[0].mV);
+ shader->uniform4fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV);
+ //HACK -- duplicate sunlight color for compatibility with drivers that can't deal with multiple shader objects referencing the same uniform
+ shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV);
+ }
+}
+
+void LLRender::syncMatrices()
+{
+ stop_glerror();
+
+ U32 name[] =
+ {
+ LLShaderMgr::MODELVIEW_MATRIX,
+ LLShaderMgr::PROJECTION_MATRIX,
+ LLShaderMgr::TEXTURE_MATRIX0,
+ LLShaderMgr::TEXTURE_MATRIX1,
+ LLShaderMgr::TEXTURE_MATRIX2,
+ LLShaderMgr::TEXTURE_MATRIX3,
+ };
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ static glh::matrix4f cached_mvp;
+ static U32 cached_mvp_mdv_hash = 0xFFFFFFFF;
+ static U32 cached_mvp_proj_hash = 0xFFFFFFFF;
+
+ static glh::matrix4f cached_normal;
+ static U32 cached_normal_hash = 0xFFFFFFFF;
+
+ if (shader)
+ {
+ llassert(shader);
+
+ bool mvp_done = false;
+
+ U32 i = MM_MODELVIEW;
+ if (mMatHash[i] != shader->mMatHash[i])
+ { //update modelview, normal, and MVP
+ glh::matrix4f& mat = mMatrix[i][mMatIdx[i]];
+
+ shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m);
+ shader->mMatHash[i] = mMatHash[i];
+
+ //update normal matrix
+ S32 loc = shader->getUniformLocation(LLShaderMgr::NORMAL_MATRIX);
+ if (loc > -1)
+ {
+ if (cached_normal_hash != mMatHash[i])
+ {
+ cached_normal = mat.inverse().transpose();
+ cached_normal_hash = mMatHash[i];
+ }
+
+ glh::matrix4f& norm = cached_normal;
+
+ F32 norm_mat[] =
+ {
+ norm.m[0], norm.m[1], norm.m[2],
+ norm.m[4], norm.m[5], norm.m[6],
+ norm.m[8], norm.m[9], norm.m[10]
+ };
+
+ shader->uniformMatrix3fv(LLShaderMgr::NORMAL_MATRIX, 1, GL_FALSE, norm_mat);
+ }
+
+ //update MVP matrix
+ mvp_done = true;
+ loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX);
+ if (loc > -1)
+ {
+ U32 proj = MM_PROJECTION;
+
+ if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION])
+ {
+ cached_mvp = mat;
+ cached_mvp.mult_left(mMatrix[proj][mMatIdx[proj]]);
+ cached_mvp_mdv_hash = mMatHash[i];
+ cached_mvp_proj_hash = mMatHash[MM_PROJECTION];
+ }
+
+ shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m);
+ }
+ }
+
+
+ i = MM_PROJECTION;
+ if (mMatHash[i] != shader->mMatHash[i])
+ { //update projection matrix, normal, and MVP
+ glh::matrix4f& mat = mMatrix[i][mMatIdx[i]];
+
+ shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m);
+ shader->mMatHash[i] = mMatHash[i];
+
+ if (!mvp_done)
+ {
+ //update MVP matrix
+ S32 loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX);
+ if (loc > -1)
+ {
+ if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION])
+ {
+ U32 mdv = MM_MODELVIEW;
+ cached_mvp = mat;
+ cached_mvp.mult_right(mMatrix[mdv][mMatIdx[mdv]]);
+ cached_mvp_mdv_hash = mMatHash[MM_MODELVIEW];
+ cached_mvp_proj_hash = mMatHash[MM_PROJECTION];
+ }
+
+ shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m);
+ }
+ }
+ }
+
+ for (i = MM_TEXTURE0; i < NUM_MATRIX_MODES; ++i)
+ {
+ if (mMatHash[i] != shader->mMatHash[i])
+ {
+ shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mMatrix[i][mMatIdx[i]].m);
+ shader->mMatHash[i] = mMatHash[i];
+ }
+ }
+
+
+ if (shader->mFeatures.hasLighting || shader->mFeatures.calculatesLighting)
+ { //also sync light state
+ syncLightState();
+ }
+ }
+ else if (!LLGLSLShader::sNoFixedFunction)
+ {
+ GLenum mode[] =
+ {
+ GL_MODELVIEW,
+ GL_PROJECTION,
+ GL_TEXTURE,
+ GL_TEXTURE,
+ GL_TEXTURE,
+ GL_TEXTURE,
+ };
+
+ for (U32 i = 0; i < 2; ++i)
+ {
+ if (mMatHash[i] != mCurMatHash[i])
+ {
+ glMatrixMode(mode[i]);
+ glLoadMatrixf(mMatrix[i][mMatIdx[i]].m);
+ mCurMatHash[i] = mMatHash[i];
+ }
+ }
+
+ for (U32 i = 2; i < NUM_MATRIX_MODES; ++i)
+ {
+ if (mMatHash[i] != mCurMatHash[i])
+ {
+ gGL.getTexUnit(i-2)->activate();
+ glMatrixMode(mode[i]);
+ glLoadMatrixf(mMatrix[i][mMatIdx[i]].m);
+ mCurMatHash[i] = mMatHash[i];
+ }
+ }
+ }
+
+ stop_glerror();
+}
+
void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
flush();
- glTranslatef(x,y,z);
+
+ {
+ glh::matrix4f trans_mat(1,0,0,x,
+ 0,1,0,y,
+ 0,0,1,z,
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(trans_mat);
+ mMatHash[mMatrixMode]++;
+ }
}
void LLRender::scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
flush();
- glScalef(x,y,z);
+
+ {
+ glh::matrix4f scale_mat(x,0,0,0,
+ 0,y,0,0,
+ 0,0,z,0,
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(scale_mat);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar)
+{
+ flush();
+
+ {
+
+ glh::matrix4f ortho_mat(2.f/(right-left),0,0, -(right+left)/(right-left),
+ 0,2.f/(top-bottom),0, -(top+bottom)/(top-bottom),
+ 0,0,-2.f/(zFar-zNear), -(zFar+zNear)/(zFar-zNear),
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(ortho_mat);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z)
+{
+ flush();
+
+ {
+ F32 r = a * DEG_TO_RAD;
+
+ F32 c = cosf(r);
+ F32 s = sinf(r);
+
+ F32 ic = 1.f-c;
+
+ glh::matrix4f rot_mat(x*x*ic+c, x*y*ic-z*s, x*z*ic+y*s, 0,
+ x*y*ic+z*s, y*y*ic+c, y*z*ic-x*s, 0,
+ x*z*ic-y*s, y*z*ic+x*s, z*z*ic+c, 0,
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(rot_mat);
+ mMatHash[mMatrixMode]++;
+ }
}
void LLRender::pushMatrix()
{
flush();
- glPushMatrix();
+
+ {
+ if (mMatIdx[mMatrixMode] < LL_MATRIX_STACK_DEPTH-1)
+ {
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]+1] = mMatrix[mMatrixMode][mMatIdx[mMatrixMode]];
+ ++mMatIdx[mMatrixMode];
+ }
+ else
+ {
+ llwarns << "Matrix stack overflow." << llendl;
+ }
+ }
}
void LLRender::popMatrix()
{
flush();
- glPopMatrix();
+ {
+ if (mMatIdx[mMatrixMode] > 0)
+ {
+ --mMatIdx[mMatrixMode];
+ mMatHash[mMatrixMode]++;
+ }
+ else
+ {
+ llwarns << "Matrix stack underflow." << llendl;
+ }
+ }
+}
+
+void LLRender::loadMatrix(const GLfloat* m)
+{
+ flush();
+ {
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].set_value((GLfloat*) m);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::multMatrix(const GLfloat* m)
+{
+ flush();
+ {
+ glh::matrix4f mat((GLfloat*) m);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(mat);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::matrixMode(U32 mode)
+{
+ if (mode == MM_TEXTURE)
+ {
+ mode = MM_TEXTURE0 + gGL.getCurrentTexUnitIndex();
+ }
+
+ llassert(mode < NUM_MATRIX_MODES);
+ mMatrixMode = mode;
+}
+
+void LLRender::loadIdentity()
+{
+ flush();
+
+ {
+ llassert_always(mMatrixMode < NUM_MATRIX_MODES) ;
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity();
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+const glh::matrix4f& LLRender::getModelviewMatrix()
+{
+ return mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]];
+}
+
+const glh::matrix4f& LLRender::getProjectionMatrix()
+{
+ return mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]];
}
void LLRender::translateUI(F32 x, F32 y, F32 z)
@@ -1284,6 +1704,19 @@ LLLightState* LLRender::getLight(U32 index)
return NULL;
}
+void LLRender::setAmbientLightColor(const LLColor4& color)
+{
+ if (color != mAmbientLightColor)
+ {
+ ++mLightHash;
+ mAmbientLightColor = color;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.mV);
+ }
+ }
+}
+
bool LLRender::verifyTexUnitActive(U32 unitToVerify)
{
if (mCurrTextureUnitIndex == unitToVerify)
@@ -1309,6 +1742,11 @@ void LLRender::begin(const GLuint& mode)
{
if (mode != mMode)
{
+ if (mode == LLRender::QUADS)
+ {
+ mQuadCycle = 1;
+ }
+
if (mMode == LLRender::QUADS ||
mMode == LLRender::LINES ||
mMode == LLRender::TRIANGLES ||
@@ -1396,7 +1834,7 @@ void LLRender::flush()
if (gDebugGL)
{
- if (mMode == LLRender::QUADS)
+ if (mMode == LLRender::QUADS && !sGLCoreProfile)
{
if (mCount%4 != 0)
{
@@ -1421,12 +1859,34 @@ void LLRender::flush()
}
}
+ //store mCount in a local variable to avoid re-entrance (drawArrays may call flush)
+ U32 count = mCount;
+ mCount = 0;
+
+ if (mBuffer->useVBOs() && !mBuffer->isLocked())
+ { //hack to only flush the part of the buffer that was updated (relies on stream draw using buffersubdata)
+ mBuffer->getVertexStrider(mVerticesp, 0, count);
+ mBuffer->getTexCoord0Strider(mTexcoordsp, 0, count);
+ mBuffer->getColorStrider(mColorsp, 0, count);
+ }
+
+ mBuffer->flush();
mBuffer->setBuffer(immediate_mask);
- mBuffer->drawArrays(mMode, 0, mCount);
+
+ if (mMode == LLRender::QUADS && sGLCoreProfile)
+ {
+ mBuffer->drawArrays(LLRender::TRIANGLES, 0, count);
+ mQuadCycle = 1;
+ }
+ else
+ {
+ mBuffer->drawArrays(mMode, 0, count);
+ }
+
+ mVerticesp[0] = mVerticesp[count];
+ mTexcoordsp[0] = mTexcoordsp[count];
+ mColorsp[0] = mColorsp[count];
- mVerticesp[0] = mVerticesp[mCount];
- mTexcoordsp[0] = mTexcoordsp[mCount];
- mColorsp[0] = mColorsp[mCount];
mCount = 0;
}
}
@@ -1434,6 +1894,17 @@ void LLRender::flush()
void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
//the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095]
+ if (mCount > 2048)
+ { //break when buffer gets reasonably full to keep GL command buffers happy and avoid overflow below
+ switch (mMode)
+ {
+ case LLRender::POINTS: flush(); break;
+ case LLRender::TRIANGLES: if (mCount%3==0) flush(); break;
+ case LLRender::QUADS: if(mCount%4 == 0) flush(); break;
+ case LLRender::LINES: if (mCount%2 == 0) flush(); break;
+ }
+ }
+
if (mCount > 4094)
{
// llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl;
@@ -1450,10 +1921,29 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
mVerticesp[mCount] = vert;
}
+ if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile)
+ {
+ mQuadCycle++;
+ if (mQuadCycle == 4)
+ { //copy two vertices so fourth quad element will add a triangle
+ mQuadCycle = 0;
+
+ mCount++;
+ mVerticesp[mCount] = mVerticesp[mCount-3];
+ mColorsp[mCount] = mColorsp[mCount-3];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-3];
+
+ mCount++;
+ mVerticesp[mCount] = mVerticesp[mCount-2];
+ mColorsp[mCount] = mColorsp[mCount-2];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-2];
+ }
+ }
+
mCount++;
mVerticesp[mCount] = mVerticesp[mCount-1];
mColorsp[mCount] = mColorsp[mCount-1];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
}
void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count)
@@ -1464,13 +1954,50 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count)
return;
}
- for (S32 i = 0; i < vert_count; i++)
+ if (sGLCoreProfile && mMode == LLRender::QUADS)
+ { //quads are deprecated, convert to triangle list
+ S32 i = 0;
+
+ while (i < vert_count)
+ {
+ //read first three
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy two
+ mVerticesp[mCount++] = verts[i-3];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount++] = verts[i-1];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy last one
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
+ }
+ else
{
- mVerticesp[mCount] = verts[i];
+ for (S32 i = 0; i < vert_count; i++)
+ {
+ mVerticesp[mCount] = verts[i];
- mCount++;
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
+ mCount++;
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
}
mVerticesp[mCount] = mVerticesp[mCount-1];
@@ -1484,13 +2011,50 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 v
return;
}
- for (S32 i = 0; i < vert_count; i++)
+ if (sGLCoreProfile && mMode == LLRender::QUADS)
+ { //quads are deprecated, convert to triangle list
+ S32 i = 0;
+
+ while (i < vert_count)
+ {
+ //read first three
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy last two
+ mVerticesp[mCount] = verts[i-3];
+ mTexcoordsp[mCount++] = uvs[i-3];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount] = verts[i-1];
+ mTexcoordsp[mCount++] = uvs[i-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy last one
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
+ }
+ else
{
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount] = uvs[i];
+ for (S32 i = 0; i < vert_count; i++)
+ {
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
- mCount++;
- mColorsp[mCount] = mColorsp[mCount-1];
+ mCount++;
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
}
mVerticesp[mCount] = mVerticesp[mCount-1];
@@ -1505,13 +2069,51 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLCol
return;
}
- for (S32 i = 0; i < vert_count; i++)
+
+ if (sGLCoreProfile && mMode == LLRender::QUADS)
+ { //quads are deprecated, convert to triangle list
+ S32 i = 0;
+
+ while (i < vert_count)
+ {
+ //read first three
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+
+ //copy last two
+ mVerticesp[mCount] = verts[i-3];
+ mTexcoordsp[mCount] = uvs[i-3];
+ mColorsp[mCount++] = colors[i-3];
+
+ mVerticesp[mCount] = verts[i-1];
+ mTexcoordsp[mCount] = uvs[i-1];
+ mColorsp[mCount++] = colors[i-1];
+
+ //copy last one
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+ }
+ }
+ else
{
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount] = uvs[i];
- mColorsp[mCount] = colors[i];
+ for (S32 i = 0; i < vert_count; i++)
+ {
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount] = colors[i];
- mCount++;
+ mCount++;
+ }
}
mVerticesp[mCount] = mVerticesp[mCount-1];
@@ -1586,6 +2188,81 @@ void LLRender::color3fv(const GLfloat* c)
color4f(c[0],c[1],c[2],1);
}
+void LLRender::diffuseColor3f(F32 r, F32 g, F32 b)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f);
+ }
+ else
+ {
+ glColor3f(r,g,b);
+ }
+}
+
+void LLRender::diffuseColor3fv(const F32* c)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f);
+ }
+ else
+ {
+ glColor3fv(c);
+ }
+}
+
+void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a);
+ }
+ else
+ {
+ glColor4f(r,g,b,a);
+ }
+}
+
+void LLRender::diffuseColor4fv(const F32* c)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c);
+ }
+ else
+ {
+ glColor4fv(c);
+ }
+}
+
+void LLRender::diffuseColor4ubv(const U8* c)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f);
+ }
+ else
+ {
+ glColor4ubv(c);
+ }
+}
+
void LLRender::debugTexUnits(void)
{
LL_INFOS("TextureUnit") << "Active TexUnit: " << mCurrTextureUnitIndex << LL_ENDL;
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 8f7ee30d87..fa5f7f311d 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -41,6 +41,8 @@
#include "llstrider.h"
#include "llpointer.h"
#include "llglheaders.h"
+#include "llmatrix4a.h"
+#include "glh/glh_linear.h"
class LLVertexBuffer;
class LLCubeMap;
@@ -48,6 +50,8 @@ class LLImageGL;
class LLRenderTarget;
class LLTexture ;
+#define LL_MATRIX_STACK_DEPTH 32
+
class LLTexUnit
{
friend class LLRender;
@@ -235,6 +239,8 @@ public:
void setSpotDirection(const LLVector3& direction);
protected:
+ friend class LLRender;
+
S32 mIndex;
bool mEnabled;
LLColor4 mDiffuse;
@@ -308,6 +314,18 @@ public:
BF_UNDEF
} eBlendFactor;
+ typedef enum
+ {
+ MM_MODELVIEW = 0,
+ MM_PROJECTION,
+ MM_TEXTURE0,
+ MM_TEXTURE1,
+ MM_TEXTURE2,
+ MM_TEXTURE3,
+ NUM_MATRIX_MODES,
+ MM_TEXTURE
+ } eMatrixMode;
+
LLRender();
~LLRender();
void init() ;
@@ -319,8 +337,21 @@ public:
void translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z);
void scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z);
+ void rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z);
+ void ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar);
+
void pushMatrix();
void popMatrix();
+ void loadMatrix(const GLfloat* m);
+ void loadIdentity();
+ void multMatrix(const GLfloat* m);
+ void matrixMode(U32 mode);
+
+ const glh::matrix4f& getModelviewMatrix();
+ const glh::matrix4f& getProjectionMatrix();
+
+ void syncMatrices();
+ void syncLightState();
void translateUI(F32 x, F32 y, F32 z);
void scaleUI(F32 x, F32 y, F32 z);
@@ -351,6 +382,12 @@ public:
void color3fv(const GLfloat* c);
void color4ubv(const GLubyte* c);
+ void diffuseColor3f(F32 r, F32 g, F32 b);
+ void diffuseColor3fv(const F32* c);
+ void diffuseColor4f(F32 r, F32 g, F32 b, F32 a);
+ void diffuseColor4fv(const F32* c);
+ void diffuseColor4ubv(const U8* c);
+
void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
@@ -368,7 +405,8 @@ public:
eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor);
LLLightState* getLight(U32 index);
-
+ void setAmbientLightColor(const LLColor4& color);
+
LLTexUnit* getTexUnit(U32 index);
U32 getCurrentTexUnitIndex(void) const { return mCurrTextureUnitIndex; }
@@ -389,9 +427,21 @@ public:
public:
static U32 sUICalls;
static U32 sUIVerts;
+ static bool sGLCoreProfile;
private:
- bool mDirty;
+ friend class LLLightState;
+
+ U32 mMatrixMode;
+ U32 mMatIdx[NUM_MATRIX_MODES];
+ U32 mMatHash[NUM_MATRIX_MODES];
+ glh::matrix4f mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH];
+ U32 mCurMatHash[NUM_MATRIX_MODES];
+ U32 mLightHash;
+ LLColor4 mAmbientLightColor;
+
+ bool mDirty;
+ U32 mQuadCycle;
U32 mCount;
U32 mMode;
U32 mCurrTextureUnitIndex;
@@ -419,10 +469,10 @@ private:
};
-extern F64 gGLModelView[16];
-extern F64 gGLLastModelView[16];
-extern F64 gGLLastProjection[16];
-extern F64 gGLProjection[16];
+extern F32 gGLModelView[16];
+extern F32 gGLLastModelView[16];
+extern F32 gGLLastProjection[16];
+extern F32 gGLProjection[16];
extern S32 gGLViewport[4];
extern LLRender gGL;
diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp
index a5cd70445f..26bfe036e8 100644
--- a/indra/llrender/llrendersphere.cpp
+++ b/indra/llrender/llrendersphere.cpp
@@ -35,106 +35,12 @@
#include "llglheaders.h"
-GLUquadricObj *gQuadObj2 = NULL;
LLRenderSphere gSphere;
-void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks);
-
-void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks)
-{
- if (!gQuadObj2)
- {
- gQuadObj2 = gluNewQuadric();
- if (!gQuadObj2)
- {
- llwarns << "drawSolidSphere couldn't allocate quadric" << llendl;
- return;
- }
- }
-
- gluQuadricDrawStyle(gQuadObj2, GLU_FILL);
- gluQuadricNormals(gQuadObj2, GLU_SMOOTH);
- // If we ever changed/used the texture or orientation state
- // of quadObj, we'd need to change it to the defaults here
- // with gluQuadricTexture and/or gluQuadricOrientation.
- gluQuadricTexture(gQuadObj2, GL_TRUE);
- gluSphere(gQuadObj2, radius, slices, stacks);
-}
-
-
-// A couple thoughts on sphere drawing:
-// 1) You need more slices than stacks, but little less than 2:1
-// 2) At low LOD, setting stacks to an odd number avoids a "band" around the equator, making things look smoother
-void LLRenderSphere::prerender()
-{
- // Create a series of display lists for different LODs
- mDList[0] = glGenLists(1);
- glNewList(mDList[0], GL_COMPILE);
- drawSolidSphere(1.0, 30, 20);
- glEndList();
-
- mDList[1] = glGenLists(1);
- glNewList(mDList[1], GL_COMPILE);
- drawSolidSphere(1.0, 20, 15);
- glEndList();
-
- mDList[2] = glGenLists(1);
- glNewList(mDList[2], GL_COMPILE);
- drawSolidSphere(1.0, 12, 8);
- glEndList();
-
- mDList[3] = glGenLists(1);
- glNewList(mDList[3], GL_COMPILE);
- drawSolidSphere(1.0, 8, 5);
- glEndList();
-}
-
-void LLRenderSphere::cleanupGL()
-{
- for (S32 detail = 0; detail < 4; detail++)
- {
- glDeleteLists(mDList[detail], 1);
- mDList[detail] = 0;
- }
-
- if (gQuadObj2)
- {
- gluDeleteQuadric(gQuadObj2);
- gQuadObj2 = NULL;
- }
-}
-
-// Constants here are empirically derived from my eyeballs, JNC
-//
-// The toughest adjustment is the cutoff for the lowest LOD
-// Maybe we should have more LODs at the low end?
-void LLRenderSphere::render(F32 pixel_area)
-{
- S32 level_of_detail;
-
- if (pixel_area > 10000.f)
- {
- level_of_detail = 0;
- }
- else if (pixel_area > 800.f)
- {
- level_of_detail = 1;
- }
- else if (pixel_area > 100.f)
- {
- level_of_detail = 2;
- }
- else
- {
- level_of_detail = 3;
- }
- glCallList(mDList[level_of_detail]);
-}
-
-
void LLRenderSphere::render()
{
- glCallList(mDList[0]);
+ renderGGL();
+ gGL.flush();
}
inline LLVector3 polar_to_cart(F32 latitude, F32 longitude)
diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h
index 96a6bec80c..f8e9e86e7f 100644
--- a/indra/llrender/llrendersphere.h
+++ b/indra/llrender/llrendersphere.h
@@ -40,11 +40,6 @@ void lat2xyz(LLVector3 * result, F32 lat, F32 lon); // utility routine
class LLRenderSphere
{
public:
- LLGLuint mDList[5];
-
- void prerender();
- void cleanupGL();
- void render(F32 pixel_area); // of a box of size 1.0 at that position
void render(); // render at highest LOD
void renderGGL(); // render using LLRender
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 8c0d3592df..ef2a7395da 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -31,8 +31,7 @@
#include "llgl.h"
LLRenderTarget* LLRenderTarget::sBoundTarget = NULL;
-
-
+U32 LLRenderTarget::sBytesAllocated = 0;
void check_framebuffer_status()
{
@@ -62,8 +61,7 @@ LLRenderTarget::LLRenderTarget() :
mStencil(0),
mUseDepth(false),
mRenderDepth(false),
- mUsage(LLTexUnit::TT_TEXTURE),
- mSamples(0)
+ mUsage(LLTexUnit::TT_TEXTURE)
{
}
@@ -84,20 +82,6 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
mStencil = stencil;
mUsage = usage;
mUseDepth = depth;
- mSamples = samples;
-
- mSamples = gGLManager.getNumFBOFSAASamples(mSamples);
-
- if (mSamples > 1 && gGLManager.mHasTextureMultisample)
- {
- mUsage = LLTexUnit::TT_MULTISAMPLE_TEXTURE;
- //no support for multisampled stencil targets yet
- mStencil = false;
- }
- else
- {
- mSamples = 0;
- }
if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
{
@@ -157,21 +141,6 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
stop_glerror();
-#ifdef GL_ARB_texture_multisample
- if (mSamples > 1)
- {
- clear_glerror();
- glTexImage2DMultisample(LLTexUnit::getInternalType(mUsage), mSamples, color_fmt, mResX, mResY, GL_TRUE);
- if (glGetError() != GL_NO_ERROR)
- {
- llwarns << "Could not allocate multisample color buffer for render target." << llendl;
- return false;
- }
- }
- else
-#else
- llassert_always(mSamples <= 1);
-#endif
{
clear_glerror();
LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
@@ -182,32 +151,32 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
}
}
+ sBytesAllocated += mResX*mResY*4;
+
stop_glerror();
- if (mSamples == 0)
- {
- if (offset == 0)
- { //use bilinear filtering on single texture render targets that aren't multisampled
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- stop_glerror();
- }
- else
- { //don't filter data attachments
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- stop_glerror();
- }
+
+ if (offset == 0)
+ { //use bilinear filtering on single texture render targets that aren't multisampled
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ stop_glerror();
+ }
+ else
+ { //don't filter data attachments
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ stop_glerror();
+ }
- if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
- {
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
- stop_glerror();
- }
- else
- {
- // ATI doesn't support mirrored repeat for rectangular textures.
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- stop_glerror();
- }
+ if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
+ {
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
+ stop_glerror();
+ }
+ else
+ {
+ // ATI doesn't support mirrored repeat for rectangular textures.
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ stop_glerror();
}
if (mFBO)
@@ -250,26 +219,16 @@ bool LLRenderTarget::allocateDepth()
{
LLImageGL::generateTextures(1, &mDepth);
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
- if (mSamples == 0)
- {
- U32 internal_type = LLTexUnit::getInternalType(mUsage);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- stop_glerror();
- clear_glerror();
- LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
- }
-#ifdef GL_ARB_texture_multisample
- else
- {
- stop_glerror();
- clear_glerror();
- glTexImage2DMultisample(LLTexUnit::getInternalType(mUsage), mSamples, GL_DEPTH_COMPONENT32, mResX, mResY, GL_TRUE);
- }
-#else
- llassert_always(mSamples <= 1);
-#endif
+
+ U32 internal_type = LLTexUnit::getInternalType(mUsage);
+ stop_glerror();
+ clear_glerror();
+ LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
}
+ sBytesAllocated += mResX*mResY*4;
+
if (glGetError() != GL_NO_ERROR)
{
llwarns << "Unable to allocate depth buffer for render target." << llendl;
@@ -339,14 +298,16 @@ void LLRenderTarget::release()
stop_glerror();
}
mDepth = 0;
+
+ sBytesAllocated -= mResX*mResY*4;
}
else if (mUseDepth && mFBO)
{ //detach shared depth buffer
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (mStencil)
{ //attached as a renderbuffer
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
mStencil = false;
}
else
@@ -364,6 +325,7 @@ void LLRenderTarget::release()
if (mTex.size() > 0)
{
+ sBytesAllocated -= mResX*mResY*4*mTex.size();
LLImageGL::deleteTextures(mTex.size(), &mTex[0], true);
mTex.clear();
}
@@ -495,7 +457,8 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
gGL.flush();
if (!source.mFBO || !mFBO)
{
- llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
+ llwarns << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
+ return;
}
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index dea1de12d8..2735ab21c5 100644
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -64,6 +64,7 @@ class LLRenderTarget
public:
//whether or not to use FBO implementation
static bool sUseFBO;
+ static U32 sBytesAllocated;
LLRenderTarget();
~LLRenderTarget();
@@ -147,7 +148,6 @@ protected:
bool mUseDepth;
bool mRenderDepth;
LLTexUnit::eTextureType mUsage;
- U32 mSamples;
static LLRenderTarget* sBoundTarget;
};
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 986c1f2774..7d384450e6 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -81,29 +81,42 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (features->calculatesAtmospherics)
{
- if (!shader->attachObject("windlight/atmosphericsVarsV.glsl"))
+ if (features->hasWaterFog)
+ {
+ if (!shader->attachObject("windlight/atmosphericsVarsWaterV.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else if (!shader->attachObject("windlight/atmosphericsVarsV.glsl"))
{
return FALSE;
}
}
- if (features->calculatesLighting)
+ if (features->calculatesLighting || features->atmosphericHelpers)
{
if (!shader->attachObject("windlight/atmosphericsHelpersV.glsl"))
{
return FALSE;
}
+ }
+ if (features->calculatesLighting)
+ {
if (features->isSpecular)
{
if (!shader->attachObject("lighting/lightFuncSpecularV.glsl"))
{
return FALSE;
}
-
- if (!shader->attachObject("lighting/sumLightsSpecularV.glsl"))
+
+ if (!features->isAlphaLighting)
{
- return FALSE;
+ if (!shader->attachObject("lighting/sumLightsSpecularV.glsl"))
+ {
+ return FALSE;
+ }
}
if (!shader->attachObject("lighting/lightSpecularV.glsl"))
@@ -118,9 +131,12 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
return FALSE;
}
- if (!shader->attachObject("lighting/sumLightsV.glsl"))
+ if (!features->isAlphaLighting)
{
- return FALSE;
+ if (!shader->attachObject("lighting/sumLightsV.glsl"))
+ {
+ return FALSE;
+ }
}
if (!shader->attachObject("lighting/lightV.glsl"))
@@ -161,7 +177,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
if(features->calculatesAtmospherics)
{
- if (!shader->attachObject("windlight/atmosphericsVarsF.glsl"))
+ if (features->hasWaterFog)
+ {
+ if (!shader->attachObject("windlight/atmosphericsVarsWaterF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else if (!shader->attachObject("windlight/atmosphericsVarsF.glsl"))
{
return FALSE;
}
@@ -241,7 +264,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
return FALSE;
}
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -280,9 +303,9 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
return FALSE;
}
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
- }
+ }
}
// NOTE order of shader object attaching is VERY IMPORTANT!!!
@@ -304,7 +327,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
else if (features->hasWaterFog)
@@ -336,7 +359,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -355,7 +378,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -395,7 +418,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
return FALSE;
}
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
}
@@ -419,7 +442,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -438,10 +461,26 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
}
+
+ if (features->mIndexedTextureChannels <= 1)
+ {
+ if (!shader->attachObject("objects/nonindexedTextureV.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!shader->attachObject("objects/indexedTextureV.glsl"))
+ {
+ return FALSE;
+ }
+ }
+
return TRUE;
}
@@ -477,7 +516,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns)
}
else
{
- LL_DEBUGS("ShaderLoading") << log << LL_ENDL;
+ LL_INFOS("ShaderLoading") << log << LL_ENDL;
}
}
}
@@ -531,23 +570,85 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
}
//we can't have any lines longer than 1024 characters
- //or any shaders longer than 1024 lines... deal - DaveP
+ //or any shaders longer than 4096 lines... deal - DaveP
GLcharARB buff[1024];
- GLcharARB* text[1024];
+ GLcharARB* text[4096];
GLuint count = 0;
- if (gGLManager.mGLVersion < 2.1f)
- {
- text[count++] = strdup("#version 110\n");
- }
- else if (gGLManager.mGLVersion < 3.f)
+ S32 major_version = gGLManager.mGLSLVersionMajor;
+ S32 minor_version = gGLManager.mGLSLVersionMinor;
+
+ if (major_version == 1 && minor_version < 30)
{
- //set version to 1.20
- text[count++] = strdup("#version 120\n");
+ if (minor_version < 10)
+ {
+ //should NEVER get here -- if major version is 1 and minor version is less than 10,
+ // viewer should never attempt to use shaders, continuing will result in undefined behavior
+ llerrs << "Unsupported GLSL Version." << llendl;
+ }
+
+ if (minor_version <= 19)
+ {
+ text[count++] = strdup("#version 110\n");
+ text[count++] = strdup("#define ATTRIBUTE attribute\n");
+ text[count++] = strdup("#define VARYING varying\n");
+ text[count++] = strdup("#define VARYING_FLAT varying\n");
+ }
+ else if (minor_version <= 29)
+ {
+ //set version to 1.20
+ text[count++] = strdup("#version 120\n");
+ text[count++] = strdup("#define FXAA_GLSL_120 1\n");
+ text[count++] = strdup("#define FXAA_FAST_PIXEL_OFFSET 0\n");
+ text[count++] = strdup("#define ATTRIBUTE attribute\n");
+ text[count++] = strdup("#define VARYING varying\n");
+ text[count++] = strdup("#define VARYING_FLAT varying\n");
+ }
}
else
- { //set version to 1.30
- text[count++] = strdup("#version 130\n");
+ {
+ if (major_version < 4)
+ {
+ //set version to 1.30
+ text[count++] = strdup("#version 130\n");
+
+ //some implementations of GLSL 1.30 require integer precision be explicitly declared
+ text[count++] = strdup("precision mediump int;\n");
+ text[count++] = strdup("precision highp float;\n");
+ }
+ else
+ { //set version to 400
+ text[count++] = strdup("#version 400\n");
+ }
+
+ text[count++] = strdup("#define DEFINE_GL_FRAGCOLOR 1\n");
+ text[count++] = strdup("#define FXAA_GLSL_130 1\n");
+
+ text[count++] = strdup("#define ATTRIBUTE in\n");
+
+ if (type == GL_VERTEX_SHADER_ARB)
+ { //"varying" state is "out" in a vertex program, "in" in a fragment program
+ // ("varying" is deprecated after version 1.20)
+ text[count++] = strdup("#define VARYING out\n");
+ text[count++] = strdup("#define VARYING_FLAT flat out\n");
+ }
+ else
+ {
+ text[count++] = strdup("#define VARYING in\n");
+ text[count++] = strdup("#define VARYING_FLAT flat in\n");
+ }
+
+ //backwards compatibility with legacy texture lookup syntax
+ text[count++] = strdup("#define texture2D texture\n");
+ text[count++] = strdup("#define textureCube texture\n");
+ text[count++] = strdup("#define texture2DLod textureLod\n");
+ text[count++] = strdup("#define shadow2D(a,b) vec2(texture(a,b))\n");
+
+ if (major_version > 1 || minor_version >= 40)
+ { //GLSL 1.40 replaces texture2DRect et al with texture
+ text[count++] = strdup("#define texture2DRect texture\n");
+ text[count++] = strdup("#define shadow2DRect(a,b) vec2(texture(a,b))\n");
+ }
}
//copy preprocessor definitions into buffer
@@ -571,22 +672,24 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
.
uniform sampler2D texN;
- varying float vary_texture_index;
+ VARYING_FLAT ivec4 vary_texture_index;
+
+ vec4 ret = vec4(1,0,1,1);
vec4 diffuseLookup(vec2 texcoord)
{
- switch (int(vary_texture_index+0.25))
+ switch (vary_texture_index.r))
{
- case 0: return texture2D(tex0, texcoord);
- case 1: return texture2D(tex1, texcoord);
- case 2: return texture2D(tex2, texcoord);
+ case 0: ret = texture2D(tex0, texcoord); break;
+ case 1: ret = texture2D(tex1, texcoord); break;
+ case 2: ret = texture2D(tex2, texcoord); break;
.
.
.
- case N: return texture2D(texN, texcoord);
+ case N: return texture2D(texN, texcoord); break;
}
- return vec4(0,0,0,0);
+ return ret;
}
*/
@@ -597,7 +700,11 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
text[count++] = strdup(decl.c_str());
}
- text[count++] = strdup("varying float vary_texture_index;\n");
+ if (texture_index_channels > 1)
+ {
+ text[count++] = strdup("VARYING_FLAT ivec4 vary_texture_index;\n");
+ }
+
text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
text[count++] = strdup("{\n");
@@ -607,49 +714,32 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
text[count++] = strdup("return texture2D(tex0, texcoord);\n");
text[count++] = strdup("}\n");
}
- else if (gGLManager.mGLVersion >= 3.f)
- {
- text[count++] = strdup("\tswitch (int(vary_texture_index+0.25))\n");
+ else if (major_version > 1 || minor_version >= 30)
+ { //switches are supported in GLSL 1.30 and later
+ text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n");
+ text[count++] = strdup("\tswitch (vary_texture_index.r)\n");
text[count++] = strdup("\t{\n");
//switch body
for (S32 i = 0; i < texture_index_channels; ++i)
{
- std::string case_str = llformat("\t\tcase %d: return texture2D(tex%d, texcoord);\n", i, i);
+ std::string case_str = llformat("\t\tcase %d: ret = texture2D(tex%d, texcoord); break;\n", i, i);
text[count++] = strdup(case_str.c_str());
}
text[count++] = strdup("\t}\n");
- text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
+ text[count++] = strdup("\treturn ret;\n");
text[count++] = strdup("}\n");
}
else
- {
- //switches aren't supported, make block that looks like:
- /*
- int ti = int(vary_texture_index+0.25);
- if (ti == 0) return texture2D(tex0, texcoord);
- if (ti == 1) return texture2D(tex1, texcoord);
- .
- .
- .
- if (ti == N) return texture2D(texN, texcoord);
- */
-
- text[count++] = strdup("int ti = int(vary_texture_index+0.25);\n");
- for (S32 i = 0; i < texture_index_channels; ++i)
- {
- std::string if_str = llformat("if (ti == %d) return texture2D(tex%d, texcoord);\n", i, i);
- text[count++] = strdup(if_str.c_str());
- }
-
- text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
- text[count++] = strdup("}\n");
- }
+ { //should never get here. Indexed texture rendering requires GLSL 1.30 or later
+ // (for passing integers between vertex and fragment shaders)
+ llerrs << "Indexed texture rendering requires GLSL 1.30 or later." << llendl;
+ }
}
//copy file into memory
- while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(buff) )
+ while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(text) )
{
text[count++] = (GLcharARB *)strdup((char *)buff);
}
@@ -704,14 +794,24 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
dumpObjectLog(ret);
+#if LL_WINDOWS
std::stringstream ostr;
//dump shader source for debugging
for (GLuint i = 0; i < count; i++)
{
ostr << i << ": " << text[i];
+
+ if (i % 128 == 0)
+ { //dump every 128 lines
+
+ LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
+ ostr = std::stringstream();
+ }
+
}
LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
+#endif // LL_WINDOWS
ret = 0;
}
@@ -760,28 +860,42 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors)
LL_WARNS("ShaderLoading") << "GLSL Linker Error:" << LL_ENDL;
}
-// NOTE: Removing LL_DARWIN block as it doesn't seem to actually give the correct answer,
-// but want it for reference once I move it.
-#if 0
- // Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software
- // per Apple's suggestion
- glBegin(gGL.mMode);
- glEnd();
+#if LL_DARWIN
- // Query whether the shader can or cannot run in hardware
- // http://developer.apple.com/qa/qa2007/qa1502.html
- long vertexGPUProcessing;
- CGLContextObj ctx = CGLGetCurrentContext();
- CGLGetParameter (ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing);
- long fragmentGPUProcessing;
- CGLGetParameter (ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
- if (!fragmentGPUProcessing || !vertexGPUProcessing)
+ // For some reason this absolutely kills the frame rate when VBO's are enabled
+ if (0)
{
- LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL;
- success = GL_FALSE;
- suppress_errors = FALSE;
+ // Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software
+ // per Apple's suggestion
+ LLGLSLShader::sNoFixedFunction = false;
+
+ glUseProgramObjectARB(obj);
+
+ gGL.begin(LLRender::TRIANGLES);
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.end();
+ gGL.flush();
+
+ glUseProgramObjectARB(0);
+
+ LLGLSLShader::sNoFixedFunction = true;
+
+ // Query whether the shader can or cannot run in hardware
+ // http://developer.apple.com/qa/qa2007/qa1502.html
+ GLint vertexGPUProcessing, fragmentGPUProcessing;
+ CGLContextObj ctx = CGLGetCurrentContext();
+ CGLGetParameter(ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing);
+ CGLGetParameter(ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
+ if (!fragmentGPUProcessing || !vertexGPUProcessing)
+ {
+ LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL;
+ success = GL_FALSE;
+ suppress_errors = FALSE;
+ }
}
-
+
#else
std::string log = get_object_log(obj);
LLStringUtil::toLower(log);
@@ -819,3 +933,183 @@ BOOL LLShaderMgr::validateProgramObject(GLhandleARB obj)
return success;
}
+//virtual
+void LLShaderMgr::initAttribsAndUniforms()
+{
+ //MUST match order of enum in LLVertexBuffer.h
+ mReservedAttribs.push_back("position");
+ mReservedAttribs.push_back("normal");
+ mReservedAttribs.push_back("texcoord0");
+ mReservedAttribs.push_back("texcoord1");
+ mReservedAttribs.push_back("texcoord2");
+ mReservedAttribs.push_back("texcoord3");
+ mReservedAttribs.push_back("diffuse_color");
+ mReservedAttribs.push_back("emissive");
+ mReservedAttribs.push_back("binormal");
+ mReservedAttribs.push_back("weight");
+ mReservedAttribs.push_back("weight4");
+ mReservedAttribs.push_back("clothing");
+ mReservedAttribs.push_back("texture_index");
+
+ //matrix state
+ mReservedUniforms.push_back("modelview_matrix");
+ mReservedUniforms.push_back("projection_matrix");
+ mReservedUniforms.push_back("inv_proj");
+ mReservedUniforms.push_back("modelview_projection_matrix");
+ mReservedUniforms.push_back("normal_matrix");
+ mReservedUniforms.push_back("texture_matrix0");
+ mReservedUniforms.push_back("texture_matrix1");
+ mReservedUniforms.push_back("texture_matrix2");
+ mReservedUniforms.push_back("texture_matrix3");
+ llassert(mReservedUniforms.size() == LLShaderMgr::TEXTURE_MATRIX3+1);
+
+ mReservedUniforms.push_back("viewport");
+
+ mReservedUniforms.push_back("light_position");
+ mReservedUniforms.push_back("light_direction");
+ mReservedUniforms.push_back("light_attenuation");
+ mReservedUniforms.push_back("light_diffuse");
+ mReservedUniforms.push_back("light_ambient");
+ mReservedUniforms.push_back("light_count");
+ mReservedUniforms.push_back("light");
+ mReservedUniforms.push_back("light_col");
+ mReservedUniforms.push_back("far_z");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::MULTI_LIGHT_FAR_Z+1);
+
+
+ mReservedUniforms.push_back("proj_mat");
+ mReservedUniforms.push_back("proj_near");
+ mReservedUniforms.push_back("proj_p");
+ mReservedUniforms.push_back("proj_n");
+ mReservedUniforms.push_back("proj_origin");
+ mReservedUniforms.push_back("proj_range");
+ mReservedUniforms.push_back("proj_ambiance");
+ mReservedUniforms.push_back("proj_shadow_idx");
+ mReservedUniforms.push_back("shadow_fade");
+ mReservedUniforms.push_back("proj_focus");
+ mReservedUniforms.push_back("proj_lod");
+ mReservedUniforms.push_back("proj_ambient_lod");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::PROJECTOR_AMBIENT_LOD+1);
+
+ mReservedUniforms.push_back("color");
+
+ mReservedUniforms.push_back("diffuseMap");
+ mReservedUniforms.push_back("specularMap");
+ mReservedUniforms.push_back("bumpMap");
+ mReservedUniforms.push_back("environmentMap");
+ mReservedUniforms.push_back("cloude_noise_texture");
+ mReservedUniforms.push_back("fullbright");
+ mReservedUniforms.push_back("lightnorm");
+ mReservedUniforms.push_back("sunlight_color_copy");
+ mReservedUniforms.push_back("ambient");
+ mReservedUniforms.push_back("blue_horizon");
+ mReservedUniforms.push_back("blue_density");
+ mReservedUniforms.push_back("haze_horizon");
+ mReservedUniforms.push_back("haze_density");
+ mReservedUniforms.push_back("cloud_shadow");
+ mReservedUniforms.push_back("density_multiplier");
+ mReservedUniforms.push_back("distance_multiplier");
+ mReservedUniforms.push_back("max_y");
+ mReservedUniforms.push_back("glow");
+ mReservedUniforms.push_back("cloud_color");
+ mReservedUniforms.push_back("cloud_pos_density1");
+ mReservedUniforms.push_back("cloud_pos_density2");
+ mReservedUniforms.push_back("cloud_scale");
+ mReservedUniforms.push_back("gamma");
+ mReservedUniforms.push_back("scene_light_strength");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::SCENE_LIGHT_STRENGTH+1);
+
+ mReservedUniforms.push_back("center");
+ mReservedUniforms.push_back("size");
+ mReservedUniforms.push_back("falloff");
+
+
+ mReservedUniforms.push_back("minLuminance");
+ mReservedUniforms.push_back("maxExtractAlpha");
+ mReservedUniforms.push_back("lumWeights");
+ mReservedUniforms.push_back("warmthWeights");
+ mReservedUniforms.push_back("warmthAmount");
+ mReservedUniforms.push_back("glowStrength");
+ mReservedUniforms.push_back("glowDelta");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::GLOW_DELTA+1);
+
+
+ mReservedUniforms.push_back("minimum_alpha");
+
+ mReservedUniforms.push_back("shadow_matrix");
+ mReservedUniforms.push_back("env_mat");
+ mReservedUniforms.push_back("shadow_clip");
+ mReservedUniforms.push_back("sun_wash");
+ mReservedUniforms.push_back("shadow_noise");
+ mReservedUniforms.push_back("blur_size");
+ mReservedUniforms.push_back("ssao_radius");
+ mReservedUniforms.push_back("ssao_max_radius");
+ mReservedUniforms.push_back("ssao_factor");
+ mReservedUniforms.push_back("ssao_factor_inv");
+ mReservedUniforms.push_back("ssao_effect_mat");
+ mReservedUniforms.push_back("screen_res");
+ mReservedUniforms.push_back("near_clip");
+ mReservedUniforms.push_back("shadow_offset");
+ mReservedUniforms.push_back("shadow_bias");
+ mReservedUniforms.push_back("spot_shadow_bias");
+ mReservedUniforms.push_back("spot_shadow_offset");
+ mReservedUniforms.push_back("sun_dir");
+ mReservedUniforms.push_back("shadow_res");
+ mReservedUniforms.push_back("proj_shadow_res");
+ mReservedUniforms.push_back("depth_cutoff");
+ mReservedUniforms.push_back("norm_cutoff");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_NORM_CUTOFF+1);
+
+ mReservedUniforms.push_back("tc_scale");
+ mReservedUniforms.push_back("rcp_screen_res");
+ mReservedUniforms.push_back("rcp_frame_opt");
+ mReservedUniforms.push_back("rcp_frame_opt2");
+
+ mReservedUniforms.push_back("focal_distance");
+ mReservedUniforms.push_back("blur_constant");
+ mReservedUniforms.push_back("tan_pixel_angle");
+ mReservedUniforms.push_back("magnification");
+ mReservedUniforms.push_back("max_cof");
+ mReservedUniforms.push_back("res_scale");
+ mReservedUniforms.push_back("dof_width");
+ mReservedUniforms.push_back("dof_height");
+
+ mReservedUniforms.push_back("depthMap");
+ mReservedUniforms.push_back("shadowMap0");
+ mReservedUniforms.push_back("shadowMap1");
+ mReservedUniforms.push_back("shadowMap2");
+ mReservedUniforms.push_back("shadowMap3");
+ mReservedUniforms.push_back("shadowMap4");
+ mReservedUniforms.push_back("shadowMap5");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW5+1);
+
+ mReservedUniforms.push_back("normalMap");
+ mReservedUniforms.push_back("positionMap");
+ mReservedUniforms.push_back("diffuseRect");
+ mReservedUniforms.push_back("specularRect");
+ mReservedUniforms.push_back("noiseMap");
+ mReservedUniforms.push_back("lightFunc");
+ mReservedUniforms.push_back("lightMap");
+ mReservedUniforms.push_back("bloomMap");
+ mReservedUniforms.push_back("projectionMap");
+
+ llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
+
+ std::set<std::string> dupe_check;
+
+ for (U32 i = 0; i < mReservedUniforms.size(); ++i)
+ {
+ if (dupe_check.find(mReservedUniforms[i]) != dupe_check.end())
+ {
+ llerrs << "Duplicate reserved uniform name found: " << mReservedUniforms[i] << llendl;
+ }
+ dupe_check.insert(mReservedUniforms[i]);
+ }
+}
+
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index 2f30103811..e28bda6de2 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -36,9 +36,139 @@ public:
LLShaderMgr();
virtual ~LLShaderMgr();
+ typedef enum
+ {
+ MODELVIEW_MATRIX = 0,
+ PROJECTION_MATRIX,
+ INVERSE_PROJECTION_MATRIX,
+ MODELVIEW_PROJECTION_MATRIX,
+ NORMAL_MATRIX,
+ TEXTURE_MATRIX0,
+ TEXTURE_MATRIX1,
+ TEXTURE_MATRIX2,
+ TEXTURE_MATRIX3,
+ VIEWPORT,
+ LIGHT_POSITION,
+ LIGHT_DIRECTION,
+ LIGHT_ATTENUATION,
+ LIGHT_DIFFUSE,
+ LIGHT_AMBIENT,
+ MULTI_LIGHT_COUNT,
+ MULTI_LIGHT,
+ MULTI_LIGHT_COL,
+ MULTI_LIGHT_FAR_Z,
+ PROJECTOR_MATRIX,
+ PROJECTOR_NEAR,
+ PROJECTOR_P,
+ PROJECTOR_N,
+ PROJECTOR_ORIGIN,
+ PROJECTOR_RANGE,
+ PROJECTOR_AMBIANCE,
+ PROJECTOR_SHADOW_INDEX,
+ PROJECTOR_SHADOW_FADE,
+ PROJECTOR_FOCUS,
+ PROJECTOR_LOD,
+ PROJECTOR_AMBIENT_LOD,
+ DIFFUSE_COLOR,
+ DIFFUSE_MAP,
+ SPECULAR_MAP,
+ BUMP_MAP,
+ ENVIRONMENT_MAP,
+ CLOUD_NOISE_MAP,
+ FULLBRIGHT,
+ LIGHTNORM,
+ SUNLIGHT_COLOR,
+ AMBIENT,
+ BLUE_HORIZON,
+ BLUE_DENSITY,
+ HAZE_HORIZON,
+ HAZE_DENSITY,
+ CLOUD_SHADOW,
+ DENSITY_MULTIPLIER,
+ DISTANCE_MULTIPLIER,
+ MAX_Y,
+ GLOW,
+ CLOUD_COLOR,
+ CLOUD_POS_DENSITY1,
+ CLOUD_POS_DENSITY2,
+ CLOUD_SCALE,
+ GAMMA,
+ SCENE_LIGHT_STRENGTH,
+ LIGHT_CENTER,
+ LIGHT_SIZE,
+ LIGHT_FALLOFF,
+
+ GLOW_MIN_LUMINANCE,
+ GLOW_MAX_EXTRACT_ALPHA,
+ GLOW_LUM_WEIGHTS,
+ GLOW_WARMTH_WEIGHTS,
+ GLOW_WARMTH_AMOUNT,
+ GLOW_STRENGTH,
+ GLOW_DELTA,
+
+ MINIMUM_ALPHA,
+
+ DEFERRED_SHADOW_MATRIX,
+ DEFERRED_ENV_MAT,
+ DEFERRED_SHADOW_CLIP,
+ DEFERRED_SUN_WASH,
+ DEFERRED_SHADOW_NOISE,
+ DEFERRED_BLUR_SIZE,
+ DEFERRED_SSAO_RADIUS,
+ DEFERRED_SSAO_MAX_RADIUS,
+ DEFERRED_SSAO_FACTOR,
+ DEFERRED_SSAO_FACTOR_INV,
+ DEFERRED_SSAO_EFFECT_MAT,
+ DEFERRED_SCREEN_RES,
+ DEFERRED_NEAR_CLIP,
+ DEFERRED_SHADOW_OFFSET,
+ DEFERRED_SHADOW_BIAS,
+ DEFERRED_SPOT_SHADOW_BIAS,
+ DEFERRED_SPOT_SHADOW_OFFSET,
+ DEFERRED_SUN_DIR,
+ DEFERRED_SHADOW_RES,
+ DEFERRED_PROJ_SHADOW_RES,
+ DEFERRED_DEPTH_CUTOFF,
+ DEFERRED_NORM_CUTOFF,
+
+ FXAA_TC_SCALE,
+ FXAA_RCP_SCREEN_RES,
+ FXAA_RCP_FRAME_OPT,
+ FXAA_RCP_FRAME_OPT2,
+
+ DOF_FOCAL_DISTANCE,
+ DOF_BLUR_CONSTANT,
+ DOF_TAN_PIXEL_ANGLE,
+ DOF_MAGNIFICATION,
+ DOF_MAX_COF,
+ DOF_RES_SCALE,
+ DOF_WIDTH,
+ DOF_HEIGHT,
+
+ DEFERRED_DEPTH,
+ DEFERRED_SHADOW0,
+ DEFERRED_SHADOW1,
+ DEFERRED_SHADOW2,
+ DEFERRED_SHADOW3,
+ DEFERRED_SHADOW4,
+ DEFERRED_SHADOW5,
+ DEFERRED_NORMAL,
+ DEFERRED_POSITION,
+ DEFERRED_DIFFUSE,
+ DEFERRED_SPECULAR,
+ DEFERRED_NOISE,
+ DEFERRED_LIGHTFUNC,
+ DEFERRED_LIGHT,
+ DEFERRED_BLOOM,
+ DEFERRED_PROJECTION,
+ END_RESERVED_UNIFORMS
+ } eGLSLReservedUniforms;
+
// singleton pattern implementation
static LLShaderMgr * instance();
+ virtual void initAttribsAndUniforms(void);
+
BOOL attachShaderFeatures(LLGLSLShader * shader);
void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE);
BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 8fd1193780..8b5503229f 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -34,39 +34,50 @@
#include "llmemtype.h"
#include "llrender.h"
#include "llvector4a.h"
+#include "llshadermgr.h"
#include "llglslshader.h"
#include "llmemory.h"
+//Next Highest Power Of Two
+//helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
+U32 nhpo2(U32 v)
+{
+ U32 r = 1;
+ while (r < v) {
+ r *= 2;
+ }
+ return r;
+}
+
//============================================================================
//static
-LLVBOPool LLVertexBuffer::sStreamVBOPool;
-LLVBOPool LLVertexBuffer::sDynamicVBOPool;
-LLVBOPool LLVertexBuffer::sStreamIBOPool;
-LLVBOPool LLVertexBuffer::sDynamicIBOPool;
+LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
+U32 LLVBOPool::sBytesPooled = 0;
-LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL ;
+LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL;
U32 LLVertexBuffer::sBindCount = 0;
U32 LLVertexBuffer::sSetCount = 0;
S32 LLVertexBuffer::sCount = 0;
S32 LLVertexBuffer::sGLCount = 0;
S32 LLVertexBuffer::sMappedCount = 0;
-BOOL LLVertexBuffer::sDisableVBOMapping = FALSE ;
-BOOL LLVertexBuffer::sEnableVBOs = TRUE;
+bool LLVertexBuffer::sDisableVBOMapping = false;
+bool LLVertexBuffer::sEnableVBOs = true;
U32 LLVertexBuffer::sGLRenderBuffer = 0;
+U32 LLVertexBuffer::sGLRenderArray = 0;
U32 LLVertexBuffer::sGLRenderIndices = 0;
U32 LLVertexBuffer::sLastMask = 0;
-BOOL LLVertexBuffer::sVBOActive = FALSE;
-BOOL LLVertexBuffer::sIBOActive = FALSE;
+bool LLVertexBuffer::sVBOActive = false;
+bool LLVertexBuffer::sIBOActive = false;
U32 LLVertexBuffer::sAllocatedBytes = 0;
-BOOL LLVertexBuffer::sMapped = FALSE;
-BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
-BOOL LLVertexBuffer::sPreferStreamDraw = FALSE;
-S32 LLVertexBuffer::sWeight4Loc = -1;
-
-std::vector<U32> LLVertexBuffer::sDeleteList;
-
+bool LLVertexBuffer::sMapped = false;
+bool LLVertexBuffer::sUseStreamDraw = true;
+bool LLVertexBuffer::sUseVAO = false;
+bool LLVertexBuffer::sPreferStreamDraw = false;
const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms
@@ -84,7 +95,7 @@ public:
#endif
}
- ~LLGLSyncFence()
+ virtual ~LLGLSyncFence()
{
#ifdef GL_ARB_sync
if (mSync)
@@ -122,6 +133,120 @@ public:
};
+
+//which power of 2 is i?
+//assumes i is a power of 2 > 0
+U32 wpo2(U32 i)
+{
+ llassert(i > 0);
+ llassert(nhpo2(i) == i);
+
+ U32 r = 0;
+
+ while (i >>= 1) ++r;
+
+ return r;
+}
+
+volatile U8* LLVBOPool::allocate(U32& name, U32 size)
+{
+ llassert(nhpo2(size) == size);
+
+ U32 i = wpo2(size);
+
+ if (mFreeList.size() <= i)
+ {
+ mFreeList.resize(i+1);
+ }
+
+ volatile U8* ret = NULL;
+
+ if (mFreeList[i].empty())
+ {
+ //make a new buffer
+ glGenBuffersARB(1, &name);
+ glBindBufferARB(mType, name);
+ LLVertexBuffer::sAllocatedBytes += size;
+
+ if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB)
+ {
+ glBufferDataARB(mType, size, 0, mUsage);
+ ret = (U8*) ll_aligned_malloc_16(size);
+ }
+ else
+ { //always use a true hint of static draw when allocating non-client-backed buffers
+ glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB);
+ }
+
+ glBindBufferARB(mType, 0);
+ }
+ else
+ {
+ name = mFreeList[i].front().mGLName;
+ ret = mFreeList[i].front().mClientData;
+
+ sBytesPooled -= size;
+
+ mFreeList[i].pop_front();
+ }
+
+ return ret;
+}
+
+void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
+{
+ llassert(nhpo2(size) == size);
+
+ U32 i = wpo2(size);
+
+ llassert(mFreeList.size() > i);
+
+ Record rec;
+ rec.mGLName = name;
+ rec.mClientData = buffer;
+
+ if (buffer == NULL)
+ {
+ glDeleteBuffersARB(1, &rec.mGLName);
+ }
+ else
+ {
+ sBytesPooled += size;
+ mFreeList[i].push_back(rec);
+ }
+}
+
+void LLVBOPool::cleanup()
+{
+ U32 size = 1;
+
+ for (U32 i = 0; i < mFreeList.size(); ++i)
+ {
+ record_list_t& l = mFreeList[i];
+
+ while (!l.empty())
+ {
+ Record& r = l.front();
+
+ glDeleteBuffersARB(1, &r.mGLName);
+
+ if (r.mClientData)
+ {
+ ll_aligned_free_16((void*) r.mClientData);
+ }
+
+ l.pop_front();
+
+ LLVertexBuffer::sAllocatedBytes -= size;
+ sBytesPooled -= size;
+ }
+
+ size *= 2;
+ }
+}
+
+
+//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware
S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
{
sizeof(LLVector4), // TYPE_VERTEX,
@@ -131,10 +256,12 @@ S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
sizeof(LLVector2), // TYPE_TEXCOORD2,
sizeof(LLVector2), // TYPE_TEXCOORD3,
sizeof(LLColor4U), // TYPE_COLOR,
+ sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently
sizeof(LLVector4), // TYPE_BINORMAL,
sizeof(F32), // TYPE_WEIGHT,
sizeof(LLVector4), // TYPE_WEIGHT4,
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
+ sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
};
U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
@@ -149,146 +276,153 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
GL_LINE_LOOP,
};
+
//static
void LLVertexBuffer::setupClientArrays(U32 data_mask)
{
- /*if (LLGLImmediate::sStarted)
- {
- llerrs << "Cannot use LLGLImmediate and LLVertexBuffer simultaneously!" << llendl;
- }*/
-
if (sLastMask != data_mask)
{
- U32 mask[] =
+ bool error = false;
+
+ if (gGLManager.mGLSLVersionMajor < 2 && gGLManager.mGLSLVersionMinor < 30)
{
- MAP_VERTEX,
- MAP_NORMAL,
- MAP_TEXCOORD0,
- MAP_COLOR,
- };
-
- GLenum array[] =
- {
- GL_VERTEX_ARRAY,
- GL_NORMAL_ARRAY,
- GL_TEXTURE_COORD_ARRAY,
- GL_COLOR_ARRAY,
- };
-
- BOOL error = FALSE;
- for (U32 i = 0; i < 4; ++i)
- {
- if (sLastMask & mask[i])
- { //was enabled
- if (!(data_mask & mask[i]) && i > 0)
- { //needs to be disabled
- glDisableClientState(array[i]);
+ //make sure texture index is disabled
+ data_mask = data_mask & ~MAP_TEXTURE_INDEX;
+ }
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ for (U32 i = 0; i < TYPE_MAX; ++i)
+ {
+ S32 loc = i;
+
+ U32 mask = 1 << i;
+
+ if (sLastMask & (1 << i))
+ { //was enabled
+ if (!(data_mask & mask))
+ { //needs to be disabled
+ glDisableVertexAttribArrayARB(loc);
+ }
}
- else if (gDebugGL)
- { //needs to be enabled, make sure it was (DEBUG TEMPORARY)
- if (i > 0 && !glIsEnabled(array[i]))
- {
+ else
+ { //was disabled
+ if (data_mask & mask)
+ { //needs to be enabled
+ glEnableVertexAttribArrayARB(loc);
+ }
+ }
+ }
+ }
+ else
+ {
+
+ GLenum array[] =
+ {
+ GL_VERTEX_ARRAY,
+ GL_NORMAL_ARRAY,
+ GL_TEXTURE_COORD_ARRAY,
+ GL_COLOR_ARRAY,
+ };
+
+ GLenum mask[] =
+ {
+ MAP_VERTEX,
+ MAP_NORMAL,
+ MAP_TEXCOORD0,
+ MAP_COLOR
+ };
+
+
+
+ for (U32 i = 0; i < 4; ++i)
+ {
+ if (sLastMask & mask[i])
+ { //was enabled
+ if (!(data_mask & mask[i]))
+ { //needs to be disabled
+ glDisableClientState(array[i]);
+ }
+ else if (gDebugGL)
+ { //needs to be enabled, make sure it was (DEBUG)
+ if (!glIsEnabled(array[i]))
+ {
+ if (gDebugSession)
+ {
+ error = true;
+ gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
+ }
+ else
+ {
+ llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
+ }
+ }
+ }
+ }
+ else
+ { //was disabled
+ if (data_mask & mask[i])
+ { //needs to be enabled
+ glEnableClientState(array[i]);
+ }
+ else if (gDebugGL && glIsEnabled(array[i]))
+ { //needs to be disabled, make sure it was (DEBUG TEMPORARY)
if (gDebugSession)
{
- error = TRUE;
- gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
+ error = true;
+ gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
}
else
{
- llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
+ llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
}
}
}
}
- else
- { //was disabled
- if (data_mask & mask[i] && i > 0)
- { //needs to be enabled
- glEnableClientState(array[i]);
- }
- else if (gDebugGL && i > 0 && glIsEnabled(array[i]))
- { //needs to be disabled, make sure it was (DEBUG TEMPORARY)
- if (gDebugSession)
- {
- error = TRUE;
- gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
- }
- else
- {
- llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
+
+ U32 map_tc[] =
+ {
+ MAP_TEXCOORD1,
+ MAP_TEXCOORD2,
+ MAP_TEXCOORD3
+ };
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (sLastMask & map_tc[i])
+ {
+ if (!(data_mask & map_tc[i]))
+ { //disable
+ 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 (error)
- {
- ll_fail("LLVertexBuffer::setupClientArrays failed");
- }
- U32 map_tc[] =
- {
- MAP_TEXCOORD1,
- MAP_TEXCOORD2,
- MAP_TEXCOORD3
- };
-
- for (U32 i = 0; i < 3; i++)
- {
- if (sLastMask & map_tc[i])
+ if (sLastMask & MAP_BINORMAL)
{
- if (!(data_mask & map_tc[i]))
+ if (!(data_mask & MAP_BINORMAL))
{
- glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
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))
+ else if (data_mask & MAP_BINORMAL)
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
- else if (data_mask & MAP_BINORMAL)
- {
- glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- 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;
}
}
@@ -296,32 +430,90 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
//static
void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+ gGL.syncMatrices();
+
U32 count = pos.size();
llassert_always(norm.size() >= pos.size());
- llassert_always(count > 0) ;
+ llassert_always(count > 0);
unbind();
setupClientArrays(MAP_VERTEX | MAP_NORMAL);
- glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
- glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (shader)
+ {
+ S32 loc = LLVertexBuffer::TYPE_VERTEX;
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
+ }
+ loc = LLVertexBuffer::TYPE_NORMAL;
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
+ }
+ }
+ else
+ {
+ glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
+ glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+ }
glDrawArrays(sGLMode[mode], 0, count);
}
+//static
+void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
+{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
+ gGL.syncMatrices();
+
+ U32 mask = LLVertexBuffer::MAP_VERTEX;
+ if (tc)
+ {
+ mask = mask | LLVertexBuffer::MAP_TEXCOORD0;
+ }
+
+ unbind();
+
+ setupClientArrays(mask);
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ S32 loc = LLVertexBuffer::TYPE_VERTEX;
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
+
+ if (tc)
+ {
+ loc = LLVertexBuffer::TYPE_TEXCOORD0;
+ glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
+ }
+ }
+ else
+ {
+ glTexCoordPointer(2, GL_FLOAT, 0, tc);
+ glVertexPointer(3, GL_FLOAT, 16, pos);
+ }
+
+ glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
+}
+
void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
{
- if (start >= (U32) mRequestedNumVerts ||
- end >= (U32) mRequestedNumVerts)
+ if (start >= (U32) mNumVerts ||
+ end >= (U32) mNumVerts)
{
- llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mRequestedNumVerts << llendl;
+ llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl;
}
- llassert(mRequestedNumIndices >= 0);
+ llassert(mNumIndices >= 0);
- if (indices_offset >= (U32) mRequestedNumIndices ||
- indices_offset + count > (U32) mRequestedNumIndices)
+ if (indices_offset >= (U32) mNumIndices ||
+ indices_offset + count > (U32) mNumIndices)
{
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
@@ -336,23 +528,66 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl;
}
}
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (shader && shader->mFeatures.mIndexedTextureChannels > 1)
+ {
+ LLStrider<LLVector4a> v;
+ //hack to get non-const reference
+ LLVertexBuffer* vb = (LLVertexBuffer*) this;
+ vb->getVertexStrider(v);
+
+ for (U32 i = start; i < end; i++)
+ {
+ S32 idx = (S32) (v[i][3]+0.25f);
+ if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels)
+ {
+ llerrs << "Bad texture index found in vertex data stream." << llendl;
+ }
+ }
+ }
}
}
void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
{
validateRange(start, end, count, indices_offset);
+ mMappable = false;
+ gGL.syncMatrices();
- llassert(mRequestedNumVerts >= 0);
+ llassert(mNumVerts >= 0);
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
- if (mGLIndices != sGLRenderIndices)
+ if (mGLArray)
{
- llerrs << "Wrong index buffer bound." << llendl;
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
+ {
+ if (mGLIndices != sGLRenderIndices)
+ {
+ llerrs << "Wrong index buffer bound." << llendl;
+ }
+
+ if (mGLBuffer != sGLRenderBuffer)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
}
- if (mGLBuffer != sGLRenderBuffer)
+ if (gDebugGL && !mGLArray && useVBOs())
{
- llerrs << "Wrong vertex buffer bound." << llendl;
+ GLint elem = 0;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
+
+ if (elem != mGLIndices)
+ {
+ llerrs << "Wrong index buffer bound!" << llendl;
+ }
}
if (mode >= LLRender::NUM_MODES)
@@ -372,21 +607,35 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
{
- llassert(mRequestedNumIndices >= 0);
- if (indices_offset >= (U32) mRequestedNumIndices ||
- indices_offset + count > (U32) mRequestedNumIndices)
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+ mMappable = false;
+ gGL.syncMatrices();
+
+ llassert(mNumIndices >= 0);
+ if (indices_offset >= (U32) mNumIndices ||
+ indices_offset + count > (U32) mNumIndices)
{
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
- if (mGLIndices != sGLRenderIndices)
+ if (mGLArray)
{
- llerrs << "Wrong index buffer bound." << llendl;
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
}
-
- if (mGLBuffer != sGLRenderBuffer)
+ else
{
- llerrs << "Wrong vertex buffer bound." << llendl;
+ if (mGLIndices != sGLRenderIndices)
+ {
+ llerrs << "Wrong index buffer bound." << llendl;
+ }
+
+ if (mGLBuffer != sGLRenderBuffer)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
}
if (mode >= LLRender::NUM_MODES)
@@ -404,16 +653,30 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
{
- llassert(mRequestedNumVerts >= 0);
- if (first >= (U32) mRequestedNumVerts ||
- first + count > (U32) mRequestedNumVerts)
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+ mMappable = false;
+ gGL.syncMatrices();
+
+ llassert(mNumVerts >= 0);
+ if (first >= (U32) mNumVerts ||
+ first + count > (U32) mNumVerts)
{
llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl;
}
- if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
+ if (mGLArray)
+ {
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
{
- llerrs << "Wrong vertex buffer bound." << llendl;
+ if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
}
if (mode >= LLRender::NUM_MODES)
@@ -431,38 +694,37 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
//static
void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
{
- sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject ;
- if(sEnableVBOs)
- {
- //llassert_always(glBindBufferARB) ; //double check the extention for VBO is loaded.
+ sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject;
+ sDisableVBOMapping = sEnableVBOs && no_vbo_mapping;
- llinfos << "VBO is enabled." << llendl ;
- }
- else
- {
- llinfos << "VBO is disabled." << llendl ;
- }
-
- sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ;
-
- if(!sPrivatePoolp)
- {
- sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC) ;
+ if (!sPrivatePoolp)
+ {
+ sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC);
}
}
//static
void LLVertexBuffer::unbind()
{
+ if (sGLRenderArray)
+ {
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(0);
+#endif
+ sGLRenderArray = 0;
+ sGLRenderIndices = 0;
+ sIBOActive = false;
+ }
+
if (sVBOActive)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
- sVBOActive = FALSE;
+ sVBOActive = false;
}
if (sIBOActive)
{
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
- sIBOActive = FALSE;
+ sIBOActive = false;
}
sGLRenderBuffer = 0;
@@ -476,63 +738,88 @@ void LLVertexBuffer::cleanupClass()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS);
unbind();
- clientCopy(); // deletes GL buffers
+
+ sStreamIBOPool.cleanup();
+ sDynamicIBOPool.cleanup();
+ sStreamVBOPool.cleanup();
+ sDynamicVBOPool.cleanup();
if(sPrivatePoolp)
{
- LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ;
- sPrivatePoolp = NULL ;
+ LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp);
+ sPrivatePoolp = NULL;
}
}
-void LLVertexBuffer::clientCopy(F64 max_time)
+//----------------------------------------------------------------------------
+
+S32 LLVertexBuffer::determineUsage(S32 usage)
{
- if (!sDeleteList.empty())
+ S32 ret_usage = usage;
+
+ if (!sEnableVBOs)
+ {
+ ret_usage = 0;
+ }
+
+ if (ret_usage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
+ {
+ ret_usage = 0;
+ }
+
+ if (ret_usage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
{
- glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0]));
- sDeleteList.clear();
+ ret_usage = GL_STREAM_DRAW_ARB;
}
+
+ if (ret_usage == 0 && LLRender::sGLCoreProfile)
+ { //MUST use VBOs for all rendering
+ ret_usage = GL_STREAM_DRAW_ARB;
+ }
+
+ if (ret_usage && ret_usage != GL_STREAM_DRAW_ARB)
+ { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
+ if (sDisableVBOMapping)
+ { //always use stream draw if VBO mapping is disabled
+ ret_usage = GL_STREAM_DRAW_ARB;
+ }
+ else
+ {
+ ret_usage = GL_DYNAMIC_DRAW_ARB;
+ }
+ }
+
+ return ret_usage;
}
-//----------------------------------------------------------------------------
-
LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
LLRefCount(),
mNumVerts(0),
mNumIndices(0),
- mRequestedNumVerts(-1),
- mRequestedNumIndices(-1),
- mUsage(usage),
+ mAlignedOffset(0),
+ mAlignedIndexOffset(0),
+ mSize(0),
+ mIndicesSize(0),
+ mTypeMask(typemask),
+ mUsage(LLVertexBuffer::determineUsage(usage)),
mGLBuffer(0),
- mGLIndices(0),
+ mGLIndices(0),
+ mGLArray(0),
mMappedData(NULL),
- mMappedIndexData(NULL),
- mVertexLocked(FALSE),
- mIndexLocked(FALSE),
- mFinal(FALSE),
- mFilthy(FALSE),
- mEmpty(TRUE),
- mResized(FALSE),
- mDynamicSize(FALSE),
+ mMappedIndexData(NULL),
+ mMappedDataUsingVBOs(false),
+ mMappedIndexDataUsingVBOs(false),
+ mVertexLocked(false),
+ mIndexLocked(false),
+ mFinal(false),
+ mEmpty(true),
+ mMappable(false),
mFence(NULL)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR);
- mFence = NULL;
- if (!sEnableVBOs)
- {
- mUsage = 0 ;
- }
- if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
- {
- mUsage = 0;
- }
-
- if (mUsage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
- {
- mUsage = GL_STREAM_DRAW_ARB;
- }
+ mMappable = (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping);
//zero out offsets
for (U32 i = 0; i < TYPE_MAX; i++)
@@ -540,11 +827,6 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
mOffsets[i] = 0;
}
- mTypeMask = typemask;
- mSize = 0;
- mAlignedOffset = 0;
- mAlignedIndexOffset = 0;
-
sCount++;
}
@@ -552,12 +834,12 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)
{
S32 offset = 0;
- for (S32 i=0; i<TYPE_MAX; i++)
+ for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++)
{
U32 mask = 1<<i;
if (typemask & mask)
{
- if (offsets)
+ if (offsets && LLVertexBuffer::sTypeSize[i])
{
offsets[i] = offset;
offset += LLVertexBuffer::sTypeSize[i]*num_vertices;
@@ -566,6 +848,8 @@ S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_verti
}
}
+ offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12;
+
return offset+16;
}
@@ -573,7 +857,7 @@ S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_verti
S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
{
S32 size = 0;
- for (S32 i = 0; i < TYPE_MAX; i++)
+ for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++)
{
U32 mask = 1<<i;
if (typemask & mask)
@@ -597,6 +881,14 @@ LLVertexBuffer::~LLVertexBuffer()
LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR);
destroyGLBuffer();
destroyGLIndices();
+
+ if (mGLArray)
+ {
+#if GL_ARB_vertex_array_object
+ glDeleteVertexArrays(1, &mGLArray);
+#endif
+ }
+
sCount--;
if (mFence)
@@ -606,7 +898,7 @@ LLVertexBuffer::~LLVertexBuffer()
mFence = NULL;
- llassert_always(!mMappedData && !mMappedIndexData) ;
+ llassert_always(!mMappedData && !mMappedIndexData);
};
void LLVertexBuffer::placeFence() const
@@ -635,39 +927,35 @@ void LLVertexBuffer::waitFence() const
//----------------------------------------------------------------------------
-void LLVertexBuffer::genBuffer()
+void LLVertexBuffer::genBuffer(U32 size)
{
+ mSize = nhpo2(size);
+
if (mUsage == GL_STREAM_DRAW_ARB)
{
- mGLBuffer = sStreamVBOPool.allocate();
- }
- else if (mUsage == GL_DYNAMIC_DRAW_ARB)
- {
- mGLBuffer = sDynamicVBOPool.allocate();
+ mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize);
}
else
{
- BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
- glGenBuffersARB(1, (GLuint*)&mGLBuffer);
+ mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize);
}
+
sGLCount++;
}
-void LLVertexBuffer::genIndices()
+void LLVertexBuffer::genIndices(U32 size)
{
+ mIndicesSize = nhpo2(size);
+
if (mUsage == GL_STREAM_DRAW_ARB)
{
- mGLIndices = sStreamIBOPool.allocate();
- }
- else if (mUsage == GL_DYNAMIC_DRAW_ARB)
- {
- mGLIndices = sDynamicIBOPool.allocate();
+ mMappedIndexData = sStreamIBOPool.allocate(mGLIndices, mIndicesSize);
}
else
{
- BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
- glGenBuffersARB(1, (GLuint*)&mGLIndices);
+ mMappedIndexData = sDynamicIBOPool.allocate(mGLIndices, mIndicesSize);
}
+
sGLCount++;
}
@@ -675,16 +963,16 @@ void LLVertexBuffer::releaseBuffer()
{
if (mUsage == GL_STREAM_DRAW_ARB)
{
- sStreamVBOPool.release(mGLBuffer);
- }
- else if (mUsage == GL_DYNAMIC_DRAW_ARB)
- {
- sDynamicVBOPool.release(mGLBuffer);
+ sStreamVBOPool.release(mGLBuffer, mMappedData, mSize);
}
else
{
- sDeleteList.push_back(mGLBuffer);
+ sDynamicVBOPool.release(mGLBuffer, mMappedData, mSize);
}
+
+ mGLBuffer = 0;
+ mMappedData = NULL;
+
sGLCount--;
}
@@ -692,24 +980,23 @@ void LLVertexBuffer::releaseIndices()
{
if (mUsage == GL_STREAM_DRAW_ARB)
{
- sStreamIBOPool.release(mGLIndices);
- }
- else if (mUsage == GL_DYNAMIC_DRAW_ARB)
- {
- sDynamicIBOPool.release(mGLIndices);
+ sStreamIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize);
}
else
{
- sDeleteList.push_back(mGLIndices);
+ sDynamicIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize);
}
+
+ mGLIndices = 0;
+ mMappedIndexData = NULL;
+
sGLCount--;
}
-void LLVertexBuffer::createGLBuffer()
+void LLVertexBuffer::createGLBuffer(U32 size)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES);
- U32 size = getSize();
if (mGLBuffer)
{
destroyGLBuffer();
@@ -720,27 +1007,27 @@ void LLVertexBuffer::createGLBuffer()
return;
}
- mEmpty = TRUE;
+ mEmpty = true;
- if (useVBOs())
+ mMappedDataUsingVBOs = useVBOs();
+
+ if (mMappedDataUsingVBOs)
{
- mMappedData = NULL;
- genBuffer();
- mResized = TRUE;
+ genBuffer(size);
}
else
{
static int gl_buffer_idx = 0;
mGLBuffer = ++gl_buffer_idx;
mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
+ mSize = size;
}
}
-void LLVertexBuffer::createGLIndices()
+void LLVertexBuffer::createGLIndices(U32 size)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES);
- U32 size = getIndicesSize();
-
+
if (mGLIndices)
{
destroyGLIndices();
@@ -751,24 +1038,25 @@ void LLVertexBuffer::createGLIndices()
return;
}
- mEmpty = TRUE;
+ mEmpty = true;
//pad by 16 bytes for aligned copies
size += 16;
- if (useVBOs())
+ mMappedIndexDataUsingVBOs = useVBOs();
+
+ if (mMappedIndexDataUsingVBOs)
{
//pad by another 16 bytes for VBO pointer adjustment
size += 16;
- mMappedIndexData = NULL;
- genIndices();
- mResized = TRUE;
+ genIndices(size);
}
else
{
mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
static int gl_buffer_idx = 0;
mGLIndices = ++gl_buffer_idx;
+ mIndicesSize = size;
}
}
@@ -777,24 +1065,16 @@ void LLVertexBuffer::destroyGLBuffer()
LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER);
if (mGLBuffer)
{
- if (useVBOs())
+ if (mMappedDataUsingVBOs)
{
- freeClientBuffer() ;
-
- if (mMappedData || mMappedIndexData)
- {
- llerrs << "Vertex buffer destroyed while mapped!" << llendl;
- }
releaseBuffer();
}
else
{
- FREE_MEM(sPrivatePoolp, mMappedData) ;
+ FREE_MEM(sPrivatePoolp, (void*) mMappedData);
mMappedData = NULL;
- mEmpty = TRUE;
+ mEmpty = true;
}
-
- sAllocatedBytes -= getSize();
}
mGLBuffer = 0;
@@ -806,24 +1086,16 @@ void LLVertexBuffer::destroyGLIndices()
LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES);
if (mGLIndices)
{
- if (useVBOs())
+ if (mMappedIndexDataUsingVBOs)
{
- freeClientBuffer() ;
-
- if (mMappedData || mMappedIndexData)
- {
- llerrs << "Vertex buffer destroyed while mapped." << llendl;
- }
releaseIndices();
}
else
{
- FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
+ FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData);
mMappedIndexData = NULL;
- mEmpty = TRUE;
+ mEmpty = true;
}
-
- sAllocatedBytes -= getIndicesSize();
}
mGLIndices = 0;
@@ -842,23 +1114,14 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
nverts = 65535;
}
- mRequestedNumVerts = nverts;
+ U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
- if (!mDynamicSize)
+ if (needed_size > mSize || needed_size <= mSize/2)
{
- mNumVerts = nverts;
+ createGLBuffer(needed_size);
}
- else if (mUsage == GL_STATIC_DRAW_ARB ||
- nverts > mNumVerts ||
- nverts < mNumVerts/2)
- {
- if (mUsage != GL_STATIC_DRAW_ARB && nverts + nverts/4 <= 65535)
- {
- nverts += nverts/4;
- }
- mNumVerts = nverts;
- }
- mSize = calcOffsets(mTypeMask, mOffsets, mNumVerts);
+
+ mNumVerts = nverts;
}
void LLVertexBuffer::updateNumIndices(S32 nindices)
@@ -867,28 +1130,22 @@ void LLVertexBuffer::updateNumIndices(S32 nindices)
llassert(nindices >= 0);
- mRequestedNumIndices = nindices;
- if (!mDynamicSize)
+ U32 needed_size = sizeof(U16) * nindices;
+
+ if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2)
{
- mNumIndices = nindices;
+ createGLIndices(needed_size);
}
- else if (mUsage == GL_STATIC_DRAW_ARB ||
- nindices > mNumIndices ||
- nindices < mNumIndices/2)
- {
- if (mUsage != GL_STATIC_DRAW_ARB)
- {
- nindices += nindices/4;
- }
- mNumIndices = nindices;
- }
+ mNumIndices = nindices;
}
void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
-
+
+ stop_glerror();
+
if (nverts < 0 || nindices < 0 ||
nverts > 65536)
{
@@ -898,139 +1155,169 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
updateNumVerts(nverts);
updateNumIndices(nindices);
- if (mMappedData)
- {
- llerrs << "LLVertexBuffer::allocateBuffer() called redundantly." << llendl;
- }
if (create && (nverts || nindices))
{
- createGLBuffer();
- createGLIndices();
+ //actually allocate space for the vertex buffer if using VBO mapping
+ flush();
+
+ if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
+ {
+#if GL_ARB_vertex_array_object
+ glGenVertexArrays(1, &mGLArray);
+#endif
+ setupVertexArray();
+ }
}
-
- sAllocatedBytes += getSize() + getIndicesSize();
}
-void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
-{
- llassert(newnverts >= 0);
- llassert(newnindices >= 0);
-
- mRequestedNumVerts = newnverts;
- mRequestedNumIndices = newnindices;
+static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO");
- LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER);
- mDynamicSize = TRUE;
- if (mUsage == GL_STATIC_DRAW_ARB)
- { //always delete/allocate static buffers on resize
- destroyGLBuffer();
- destroyGLIndices();
- allocateBuffer(newnverts, newnindices, TRUE);
- mFinal = FALSE;
- }
- else if (newnverts > mNumVerts || newnindices > mNumIndices ||
- newnverts < mNumVerts/2 || newnindices < mNumIndices/2)
+void LLVertexBuffer::setupVertexArray()
+{
+ if (!mGLArray)
{
- sAllocatedBytes -= getSize() + getIndicesSize();
-
- updateNumVerts(newnverts);
- updateNumIndices(newnindices);
-
- S32 newsize = getSize();
- S32 new_index_size = getIndicesSize();
-
- sAllocatedBytes += newsize + new_index_size;
+ return;
+ }
- if (newsize)
+ LLFastTimer t(FTM_SETUP_VERTEX_ARRAY);
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(mGLArray);
+#endif
+ sGLRenderArray = mGLArray;
+
+ U32 attrib_size[] =
+ {
+ 3, //TYPE_VERTEX,
+ 3, //TYPE_NORMAL,
+ 2, //TYPE_TEXCOORD0,
+ 2, //TYPE_TEXCOORD1,
+ 2, //TYPE_TEXCOORD2,
+ 2, //TYPE_TEXCOORD3,
+ 4, //TYPE_COLOR,
+ 4, //TYPE_EMISSIVE,
+ 3, //TYPE_BINORMAL,
+ 1, //TYPE_WEIGHT,
+ 4, //TYPE_WEIGHT4,
+ 4, //TYPE_CLOTHWEIGHT,
+ 4, //TYPE_TEXTURE_INDEX
+ };
+
+ U32 attrib_type[] =
+ {
+ GL_FLOAT, //TYPE_VERTEX,
+ GL_FLOAT, //TYPE_NORMAL,
+ GL_FLOAT, //TYPE_TEXCOORD0,
+ GL_FLOAT, //TYPE_TEXCOORD1,
+ GL_FLOAT, //TYPE_TEXCOORD2,
+ GL_FLOAT, //TYPE_TEXCOORD3,
+ GL_UNSIGNED_BYTE, //TYPE_COLOR,
+ GL_UNSIGNED_BYTE, //TYPE_EMISSIVE,
+ GL_FLOAT, //TYPE_BINORMAL,
+ GL_FLOAT, //TYPE_WEIGHT,
+ GL_FLOAT, //TYPE_WEIGHT4,
+ GL_FLOAT, //TYPE_CLOTHWEIGHT,
+ GL_UNSIGNED_BYTE, //TYPE_TEXTURE_INDEX
+ };
+
+ bool attrib_integer[] =
+ {
+ false, //TYPE_VERTEX,
+ false, //TYPE_NORMAL,
+ false, //TYPE_TEXCOORD0,
+ false, //TYPE_TEXCOORD1,
+ false, //TYPE_TEXCOORD2,
+ false, //TYPE_TEXCOORD3,
+ false, //TYPE_COLOR,
+ false, //TYPE_EMISSIVE,
+ false, //TYPE_BINORMAL,
+ false, //TYPE_WEIGHT,
+ false, //TYPE_WEIGHT4,
+ false, //TYPE_CLOTHWEIGHT,
+ true, //TYPE_TEXTURE_INDEX
+ };
+
+ U32 attrib_normalized[] =
+ {
+ GL_FALSE, //TYPE_VERTEX,
+ GL_FALSE, //TYPE_NORMAL,
+ GL_FALSE, //TYPE_TEXCOORD0,
+ GL_FALSE, //TYPE_TEXCOORD1,
+ GL_FALSE, //TYPE_TEXCOORD2,
+ GL_FALSE, //TYPE_TEXCOORD3,
+ GL_TRUE, //TYPE_COLOR,
+ GL_TRUE, //TYPE_EMISSIVE,
+ GL_FALSE, //TYPE_BINORMAL,
+ GL_FALSE, //TYPE_WEIGHT,
+ GL_FALSE, //TYPE_WEIGHT4,
+ GL_FALSE, //TYPE_CLOTHWEIGHT,
+ GL_FALSE, //TYPE_TEXTURE_INDEX
+ };
+
+ bindGLBuffer(true);
+ bindGLIndices(true);
+
+ for (U32 i = 0; i < TYPE_MAX; ++i)
+ {
+ if (mTypeMask & (1 << i))
{
- if (!mGLBuffer)
- { //no buffer exists, create a new one
- createGLBuffer();
- }
- else
+ glEnableVertexAttribArrayARB(i);
+
+ if (attrib_integer[i])
{
- if (!useVBOs())
+#if !LL_DARWIN
+ //glVertexattribIPointer requires GLSL 1.30 or later
+ if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30)
{
- FREE_MEM(sPrivatePoolp, mMappedData);
- mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, newsize);
+ glVertexAttribIPointer(i, attrib_size[i], attrib_type[i], sTypeSize[i], (void*) mOffsets[i]);
}
- mResized = TRUE;
- }
- }
- else if (mGLBuffer)
- {
- destroyGLBuffer();
- }
-
- if (new_index_size)
- {
- if (!mGLIndices)
- {
- createGLIndices();
+#endif
}
else
{
- if (!useVBOs())
- {
- FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
- mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, new_index_size);
- }
- mResized = TRUE;
+ glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]);
}
}
- else if (mGLIndices)
+ else
{
- destroyGLIndices();
+ glDisableVertexAttribArrayARB(i);
}
}
- if (mResized && useVBOs())
- {
- freeClientBuffer() ;
- setBuffer(0);
- }
-}
+ //draw a dummy triangle to set index array pointer
+ //glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, NULL);
-BOOL LLVertexBuffer::useVBOs() const
-{
- //it's generally ineffective to use VBO for things that are streaming on apple
-
- if (!mUsage)
- {
- return FALSE;
- }
-
- return TRUE;
+ unbind();
}
-//----------------------------------------------------------------------------
-void LLVertexBuffer::freeClientBuffer()
+void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
{
- if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData))
- {
- FREE_MEM(sPrivatePoolp, mMappedData) ;
- FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
- mMappedData = NULL ;
- mMappedIndexData = NULL ;
- }
-}
+ llassert(newnverts >= 0);
+ llassert(newnindices >= 0);
-void LLVertexBuffer::allocateClientVertexBuffer()
-{
- if(!mMappedData)
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER);
+
+ updateNumVerts(newnverts);
+ updateNumIndices(newnindices);
+
+ if (useVBOs())
{
- mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, getSize());
+ flush();
+
+ if (mGLArray)
+ { //if size changed, offsets changed
+ setupVertexArray();
+ }
}
}
-void LLVertexBuffer::allocateClientIndexBuffer()
+bool LLVertexBuffer::useVBOs() const
{
- if(!mMappedIndexData)
- {
- mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, getIndicesSize());
- }
+ //it's generally ineffective to use VBO for things that are streaming on apple
+ return (mUsage != 0);
}
+//----------------------------------------------------------------------------
+
bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
{
S32 end = index+count;
@@ -1049,9 +1336,13 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
return true;
}
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range");
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map");
+
// Map for data access
-U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
+volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
{
+ bindGLBuffer(true);
LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
if (mFinal)
{
@@ -1064,7 +1355,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
if (useVBOs())
{
- if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
+ if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
{
if (count == -1)
{
@@ -1089,7 +1380,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
if (!mapped)
{
//not already mapped, map new region
- MappedRegion region(type, !sDisableVBOMapping && map_range ? -1 : index, count);
+ MappedRegion region(type, mMappable && map_range ? -1 : index, count);
mMappedVertexRegions.push_back(region);
}
}
@@ -1102,25 +1393,24 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
if (!mVertexLocked)
{
LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
- setBuffer(0, type);
- mVertexLocked = TRUE;
+ mVertexLocked = true;
sMappedCount++;
stop_glerror();
- if(sDisableVBOMapping)
+ if(!mMappable)
{
map_range = false;
- allocateClientVertexBuffer() ;
}
else
{
- U8* src = NULL;
+ volatile U8* src = NULL;
waitFence();
if (gGLManager.mHasMapBufferRange)
{
if (map_range)
{
#ifdef GL_ARB_map_buffer_range
+ LLFastTimer t(FTM_VBO_MAP_BUFFER_RANGE);
S32 offset = mOffsets[type] + sTypeSize[type]*index;
S32 length = (sTypeSize[type]*count+0xF) & ~0xF;
src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length,
@@ -1132,6 +1422,19 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
else
{
#ifdef GL_ARB_map_buffer_range
+
+ if (gDebugGL)
+ {
+ GLint size = 0;
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size);
+
+ if (size < mSize)
+ {
+ llerrs << "Invalid buffer size." << llendl;
+ }
+ }
+
+ LLFastTimer t(FTM_VBO_MAP_BUFFER);
src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize,
GL_MAP_WRITE_BIT |
GL_MAP_FLUSH_EXPLICIT_BIT);
@@ -1159,7 +1462,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
llassert(src != NULL);
- mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
+ mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src);
mAlignedOffset = mMappedData - src;
stop_glerror();
@@ -1169,17 +1472,17 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
{
log_glerror();
- //check the availability of memory
- LLMemory::logMemoryInfo(TRUE) ;
+ //check the availability of memory
+ LLMemory::logMemoryInfo(true);
- if(!sDisableVBOMapping)
+ if(mMappable)
{
//--------------------
//print out more debug info before crash
- llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ;
- GLint size ;
- glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ;
- llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ;
+ llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl;
+ GLint size;
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size);
+ llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl;
//--------------------
GLint buff;
@@ -1194,7 +1497,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
}
else
{
- llerrs << "memory allocation for vertex data failed." << llendl ;
+ llerrs << "memory allocation for vertex data failed." << llendl;
}
}
}
@@ -1204,7 +1507,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
map_range = false;
}
- if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping)
+ if (map_range && gGLManager.mHasMapBufferRange && mMappable)
{
return mMappedData;
}
@@ -1214,9 +1517,14 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
}
}
-U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
+
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX_RANGE("IBO Map Range");
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map");
+
+volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
+ bindGLIndices(true);
if (mFinal)
{
llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl;
@@ -1228,7 +1536,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
if (useVBOs())
{
- if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
+ if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
{
if (count == -1)
{
@@ -1250,7 +1558,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
if (!mapped)
{
//not already mapped, map new region
- MappedRegion region(TYPE_INDEX, !sDisableVBOMapping && map_range ? -1 : index, count);
+ MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count);
mMappedIndexRegions.push_back(region);
}
}
@@ -1264,25 +1572,35 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
{
LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
- setBuffer(0, TYPE_INDEX);
- mIndexLocked = TRUE;
+ mIndexLocked = true;
sMappedCount++;
stop_glerror();
- if(sDisableVBOMapping)
+ if (gDebugGL && useVBOs())
+ {
+ GLint elem = 0;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
+
+ if (elem != mGLIndices)
+ {
+ llerrs << "Wrong index buffer bound!" << llendl;
+ }
+ }
+
+ if(!mMappable)
{
map_range = false;
- allocateClientIndexBuffer() ;
}
else
{
- U8* src = NULL;
+ volatile U8* src = NULL;
waitFence();
if (gGLManager.mHasMapBufferRange)
{
if (map_range)
{
#ifdef GL_ARB_map_buffer_range
+ LLFastTimer t(FTM_VBO_MAP_INDEX_RANGE);
S32 offset = sizeof(U16)*index;
S32 length = sizeof(U16)*count;
src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length,
@@ -1294,6 +1612,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
else
{
#ifdef GL_ARB_map_buffer_range
+ LLFastTimer t(FTM_VBO_MAP_INDEX);
src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices,
GL_MAP_WRITE_BIT |
GL_MAP_FLUSH_EXPLICIT_BIT);
@@ -1315,6 +1634,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
}
else
{
+ LLFastTimer t(FTM_VBO_MAP_INDEX);
map_range = false;
src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
@@ -1331,9 +1651,9 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
if (!mMappedIndexData)
{
log_glerror();
- LLMemory::logMemoryInfo(TRUE) ;
+ LLMemory::logMemoryInfo(true);
- if(!sDisableVBOMapping)
+ if(mMappable)
{
GLint buff;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
@@ -1346,7 +1666,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
}
else
{
- llerrs << "memory allocation for Index data failed. " << llendl ;
+ llerrs << "memory allocation for Index data failed. " << llendl;
}
}
}
@@ -1355,7 +1675,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
map_range = false;
}
- if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping)
+ if (map_range && gGLManager.mHasMapBufferRange && mMappable)
{
return mMappedIndexData;
}
@@ -1365,21 +1685,30 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
}
}
-void LLVertexBuffer::unmapBuffer(S32 type)
+static LLFastTimer::DeclareTimer FTM_VBO_UNMAP("VBO Unmap");
+static LLFastTimer::DeclareTimer FTM_VBO_FLUSH_RANGE("Flush VBO Range");
+
+
+static LLFastTimer::DeclareTimer FTM_IBO_UNMAP("IBO Unmap");
+static LLFastTimer::DeclareTimer FTM_IBO_FLUSH_RANGE("Flush IBO Range");
+
+void LLVertexBuffer::unmapBuffer()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER);
- if (!useVBOs() || type == -2)
+ if (!useVBOs())
{
- return ; //nothing to unmap
+ return; //nothing to unmap
}
- bool updated_all = false ;
+ bool updated_all = false;
- if (mMappedData && mVertexLocked && type != TYPE_INDEX)
+ if (mMappedData && mVertexLocked)
{
- updated_all = (mIndexLocked && type < 0) ; //both vertex and index buffers done updating
+ LLFastTimer t(FTM_VBO_UNMAP);
+ bindGLBuffer(true);
+ updated_all = mIndexLocked; //both vertex and index buffers done updating
- if(sDisableVBOMapping)
+ if(!mMappable)
{
if (!mMappedVertexRegions.empty())
{
@@ -1389,7 +1718,7 @@ void LLVertexBuffer::unmapBuffer(S32 type)
const MappedRegion& region = mMappedVertexRegions[i];
S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
S32 length = sTypeSize[region.mType]*region.mCount;
- glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, mMappedData+offset);
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset);
stop_glerror();
}
@@ -1398,7 +1727,7 @@ void LLVertexBuffer::unmapBuffer(S32 type)
else
{
stop_glerror();
- glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), mMappedData);
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*) mMappedData);
stop_glerror();
}
}
@@ -1416,6 +1745,7 @@ void LLVertexBuffer::unmapBuffer(S32 type)
S32 length = sTypeSize[region.mType]*region.mCount;
if (gGLManager.mHasMapBufferRange)
{
+ LLFastTimer t(FTM_VBO_FLUSH_RANGE);
#ifdef GL_ARB_map_buffer_range
glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
#endif
@@ -1437,13 +1767,15 @@ void LLVertexBuffer::unmapBuffer(S32 type)
mMappedData = NULL;
}
- mVertexLocked = FALSE ;
+ mVertexLocked = false;
sMappedCount--;
}
- if (mMappedIndexData && mIndexLocked && (type < 0 || type == TYPE_INDEX))
+ if (mMappedIndexData && mIndexLocked)
{
- if(sDisableVBOMapping)
+ LLFastTimer t(FTM_IBO_UNMAP);
+ bindGLIndices();
+ if(!mMappable)
{
if (!mMappedIndexRegions.empty())
{
@@ -1452,7 +1784,7 @@ void LLVertexBuffer::unmapBuffer(S32 type)
const MappedRegion& region = mMappedIndexRegions[i];
S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
S32 length = sizeof(U16)*region.mCount;
- glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, mMappedIndexData+offset);
+ glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset);
stop_glerror();
}
@@ -1461,7 +1793,7 @@ void LLVertexBuffer::unmapBuffer(S32 type)
else
{
stop_glerror();
- glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), mMappedIndexData);
+ glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*) mMappedIndexData);
stop_glerror();
}
}
@@ -1478,6 +1810,7 @@ void LLVertexBuffer::unmapBuffer(S32 type)
S32 length = sizeof(U16)*region.mCount;
if (gGLManager.mHasMapBufferRange)
{
+ LLFastTimer t(FTM_IBO_FLUSH_RANGE);
#ifdef GL_ARB_map_buffer_range
glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
#endif
@@ -1498,30 +1831,16 @@ void LLVertexBuffer::unmapBuffer(S32 type)
glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
stop_glerror();
- mMappedIndexData = NULL ;
+ mMappedIndexData = NULL;
}
- mIndexLocked = FALSE ;
+ mIndexLocked = false;
sMappedCount--;
}
if(updated_all)
{
- if(mUsage == GL_STATIC_DRAW_ARB)
- {
- //static draw buffers can only be mapped a single time
- //throw out client data (we won't be using it again)
- mEmpty = TRUE;
- mFinal = TRUE;
- if(sDisableVBOMapping)
- {
- freeClientBuffer() ;
- }
- }
- else
- {
- mEmpty = FALSE;
- }
+ mEmpty = false;
}
}
@@ -1536,39 +1855,39 @@ template <class T,S32 type> struct VertexBufferStrider
{
if (type == LLVertexBuffer::TYPE_INDEX)
{
- U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
+ volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
if (ptr == NULL)
{
llwarns << "mapIndexBuffer failed!" << llendl;
- return FALSE;
+ return false;
}
strider = (T*)ptr;
strider.setStride(0);
- return TRUE;
+ return true;
}
else if (vbo.hasDataType(type))
{
S32 stride = LLVertexBuffer::sTypeSize[type];
- U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
+ volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
if (ptr == NULL)
{
llwarns << "mapVertexBuffer failed!" << llendl;
- return FALSE;
+ return false;
}
strider = (T*)ptr;
strider.setStride(stride);
- return TRUE;
+ return true;
}
else
{
llerrs << "VertexBufferStrider could not find valid vertex data." << llendl;
}
- return FALSE;
+ return false;
}
};
@@ -1576,6 +1895,10 @@ bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index,
{
return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
}
+bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
+}
bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range)
{
return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range);
@@ -1601,6 +1924,10 @@ bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S
{
return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range);
}
+bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range);
+}
bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range)
{
return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range);
@@ -1618,43 +1945,147 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 in
//----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array");
+bool LLVertexBuffer::bindGLArray()
+{
+ if (mGLArray && sGLRenderArray != mGLArray)
+ {
+ {
+ LLFastTimer t(FTM_BIND_GL_ARRAY);
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(mGLArray);
+#endif
+ sGLRenderArray = mGLArray;
+ }
+
+ //really shouldn't be necessary, but some drivers don't properly restore the
+ //state of GL_ELEMENT_ARRAY_BUFFER_BINDING
+ bindGLIndices();
+
+ return true;
+ }
+
+ return false;
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer");
+
+bool LLVertexBuffer::bindGLBuffer(bool force_bind)
+{
+ bindGLArray();
+
+ bool ret = false;
+
+ if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
+ {
+ LLFastTimer t(FTM_BIND_GL_BUFFER);
+ /*if (sMapped)
+ {
+ llerrs << "VBO bound while another VBO mapped!" << llendl;
+ }*/
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
+ sGLRenderBuffer = mGLBuffer;
+ sBindCount++;
+ sVBOActive = true;
+
+ if (mGLArray)
+ {
+ llassert(sGLRenderArray == mGLArray);
+ //mCachedRenderBuffer = mGLBuffer;
+ }
+
+ ret = true;
+ }
+
+ return ret;
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices");
+
+bool LLVertexBuffer::bindGLIndices(bool force_bind)
+{
+ bindGLArray();
+
+ bool ret = false;
+ if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))))
+ {
+ LLFastTimer t(FTM_BIND_GL_INDICES);
+ /*if (sMapped)
+ {
+ llerrs << "VBO bound while another VBO mapped!" << llendl;
+ }*/
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
+ sGLRenderIndices = mGLIndices;
+ stop_glerror();
+ sBindCount++;
+ sIBOActive = true;
+ ret = true;
+ }
+
+ return ret;
+}
+
+void LLVertexBuffer::flush()
+{
+ if (useVBOs())
+ {
+ unmapBuffer();
+ }
+}
+
// Set for rendering
-void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
+void LLVertexBuffer::setBuffer(U32 data_mask)
{
+ flush();
+
LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER);
//set up pointers if the data mask is different ...
- BOOL setup = (sLastMask != data_mask);
+ bool setup = (sLastMask != data_mask);
+
+ if (gDebugGL && data_mask != 0)
+ { //make sure data requirements are fulfilled
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ if (shader)
+ {
+ U32 required_mask = 0;
+ for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i)
+ {
+ if (shader->getAttribLocation(i) > -1)
+ {
+ U32 required = 1 << i;
+ if ((data_mask & required) == 0)
+ {
+ llwarns << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << llendl;
+ }
+
+ required_mask |= required;
+ }
+ }
+
+ if ((data_mask & required_mask) != required_mask)
+ {
+ llerrs << "Shader consumption mismatches data provision." << llendl;
+ }
+ }
+ }
if (useVBOs())
{
- if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))
+ if (mGLArray)
{
- /*if (sMapped)
- {
- llerrs << "VBO bound while another VBO mapped!" << llendl;
- }*/
- stop_glerror();
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
- stop_glerror();
- sBindCount++;
- sVBOActive = TRUE;
- setup = TRUE; // ... or the bound buffer changed
+ bindGLArray();
+ setup = false; //do NOT perform pointer setup if using VAO
}
- if (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))
+ else
{
- /*if (sMapped)
- {
- llerrs << "VBO bound while another VBO mapped!" << llendl;
- }*/
- stop_glerror();
- glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
- stop_glerror();
- sBindCount++;
- sIBOActive = TRUE;
+ const bool bindBuffer = bindGLBuffer();
+ const bool bindIndices = bindGLIndices();
+
+ setup = setup || bindBuffer || bindIndices;
}
-
- BOOL error = FALSE;
- if (gDebugGL)
+
+ bool error = false;
+ if (gDebugGL && !mGLArray)
{
GLint buff;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
@@ -1662,7 +2093,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
{
if (gDebugSession)
{
- error = TRUE;
+ error = true;
gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl;
}
else
@@ -1678,7 +2109,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
{
if (gDebugSession)
{
- error = TRUE;
+ error = true;
gFailLog << "Invalid GL index buffer bound: " << buff << std::endl;
}
else
@@ -1689,116 +2120,55 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
}
}
- if (mResized)
+
+ }
+ else
+ {
+ if (sGLRenderArray)
{
- if (gDebugGL)
- {
- GLint buff;
- glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
- if ((GLuint)buff != mGLBuffer)
- {
- if (gDebugSession)
- {
- error = TRUE;
- gFailLog << "Invalid GL vertex buffer bound: " << std::endl;
- }
- else
- {
- llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
- }
- }
-
- if (mGLIndices != 0)
- {
- glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
- if ((GLuint)buff != mGLIndices)
- {
- if (gDebugSession)
- {
- error = TRUE;
- gFailLog << "Invalid GL index buffer bound: "<< std::endl;
- }
- else
- {
- llerrs << "Invalid GL index buffer bound: " << buff << llendl;
- }
- }
- }
- }
-
- if (mGLBuffer)
- {
- stop_glerror();
- glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), NULL, mUsage);
- stop_glerror();
- }
- if (mGLIndices)
- {
- stop_glerror();
- glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), NULL, mUsage);
- stop_glerror();
- }
-
- mEmpty = TRUE;
- mResized = FALSE;
-
- if (data_mask != 0)
- {
- if (gDebugSession)
- {
- error = TRUE;
- gFailLog << "Buffer set for rendering before being filled after resize." << std::endl;
- }
- else
- {
- llerrs << "Buffer set for rendering before being filled after resize." << llendl;
- }
- }
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(0);
+#endif
+ sGLRenderArray = 0;
+ sGLRenderIndices = 0;
+ sIBOActive = false;
}
- if (error)
- {
- ll_fail("LLVertexBuffer::mapBuffer failed");
- }
- unmapBuffer(type);
- }
- else
- {
if (mGLBuffer)
{
if (sVBOActive)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
sBindCount++;
- sVBOActive = FALSE;
- setup = TRUE; // ... or a VBO is deactivated
+ sVBOActive = false;
+ setup = true; // ... or a VBO is deactivated
}
if (sGLRenderBuffer != mGLBuffer)
{
- setup = TRUE; // ... or a client memory pointer changed
+ sGLRenderBuffer = mGLBuffer;
+ setup = true; // ... or a client memory pointer changed
}
}
- if (mGLIndices && sIBOActive)
+ if (mGLIndices)
{
- /*if (sMapped)
+ if (sIBOActive)
{
- llerrs << "VBO unbound while potentially mapped!" << llendl;
- }*/
- glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
- sBindCount++;
- sIBOActive = FALSE;
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ sBindCount++;
+ sIBOActive = false;
+ }
+
+ sGLRenderIndices = mGLIndices;
}
}
- setupClientArrays(data_mask);
-
- if (mGLIndices)
+ if (!mGLArray)
{
- sGLRenderIndices = mGLIndices;
+ setupClientArrays(data_mask);
}
+
if (mGLBuffer)
{
- sGLRenderBuffer = mGLBuffer;
if (data_mask && setup)
{
setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
@@ -1808,80 +2178,153 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
}
// virtual (default)
-void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
+void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER);
stop_glerror();
- U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
+ volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
- if ((data_mask & mTypeMask) != data_mask)
+ /*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::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
- }
- if (data_mask & MAP_TEXCOORD3)
- {
- glClientActiveTextureARB(GL_TEXTURE3_ARB);
- glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[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::sTypeSize[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::sTypeSize[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::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
- }
- if (data_mask & MAP_TEXCOORD0)
- {
- glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
- }
- if (data_mask & MAP_COLOR)
- {
- glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
- }
-
- if (data_mask & MAP_WEIGHT)
- {
- glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT]));
- }
-
- if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1)
- {
- glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4]));
- }
+ }*/
- if (data_mask & MAP_CLOTHWEIGHT)
+ if (LLGLSLShader::sNoFixedFunction)
{
- glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
- }
- if (data_mask & MAP_VERTEX)
+ if (data_mask & MAP_NORMAL)
+ {
+ S32 loc = TYPE_NORMAL;
+ void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD3)
+ {
+ S32 loc = TYPE_TEXCOORD3;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD2)
+ {
+ S32 loc = TYPE_TEXCOORD2;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD1)
+ {
+ S32 loc = TYPE_TEXCOORD1;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
+ }
+ if (data_mask & MAP_BINORMAL)
+ {
+ S32 loc = TYPE_BINORMAL;
+ void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]);
+ glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD0)
+ {
+ S32 loc = TYPE_TEXCOORD0;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
+ }
+ if (data_mask & MAP_COLOR)
+ {
+ S32 loc = TYPE_COLOR;
+ void* ptr = (void*)(base + mOffsets[TYPE_COLOR]);
+ glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
+ }
+ if (data_mask & MAP_EMISSIVE)
+ {
+ S32 loc = TYPE_EMISSIVE;
+ void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
+ glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+ }
+ if (data_mask & MAP_WEIGHT)
+ {
+ S32 loc = TYPE_WEIGHT;
+ void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
+ glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
+ }
+ if (data_mask & MAP_WEIGHT4)
+ {
+ S32 loc = TYPE_WEIGHT4;
+ void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
+ glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
+ }
+ if (data_mask & MAP_CLOTHWEIGHT)
+ {
+ S32 loc = TYPE_CLOTHWEIGHT;
+ void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
+ glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
+ }
+ if (data_mask & MAP_TEXTURE_INDEX &&
+ (gGLManager.mGLSLVersionMajor >= 2 || gGLManager.mGLSLVersionMinor >= 30)) //indexed texture rendering requires GLSL 1.30 or later
+ {
+#if !LL_DARWIN
+ S32 loc = TYPE_TEXTURE_INDEX;
+ void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
+ glVertexAttribIPointer(loc, 4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+#endif
+ }
+ if (data_mask & MAP_VERTEX)
+ {
+ S32 loc = TYPE_VERTEX;
+ void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
+ glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+ }
+ }
+ else
{
- if (data_mask & MAP_TEXTURE_INDEX)
+ if (data_mask & MAP_NORMAL)
{
- glVertexPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
}
- else
+ if (data_mask & MAP_TEXCOORD3)
{
- glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ glClientActiveTextureARB(GL_TEXTURE3_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[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::sTypeSize[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::sTypeSize[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::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD0)
+ {
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ }
+ if (data_mask & MAP_COLOR)
+ {
+ glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+ }
+ if (data_mask & MAP_VERTEX)
+ {
+ glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ }
}
llglassertok();
}
+LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count)
+: mType(type), mIndex(index), mCount(count)
+{
+ llassert(mType == LLVertexBuffer::TYPE_INDEX ||
+ mType < LLVertexBuffer::TYPE_TEXTURE_INDEX);
+}
+
+
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 578cec3885..d859199663 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -38,6 +38,8 @@
#include <vector>
#include <list>
+#define LL_MAX_VERTEX_ATTRIB_LOCATION 64
+
//============================================================================
// NOTES
// Threading:
@@ -49,25 +51,37 @@
//============================================================================
// gl name pools for dynamic and streaming buffers
-
-class LLVBOPool : public LLGLNamePool
+class LLVBOPool
{
-protected:
- virtual GLuint allocateName()
- {
- GLuint name;
- stop_glerror();
- glGenBuffersARB(1, &name);
- stop_glerror();
- return name;
- }
+public:
+ static U32 sBytesPooled;
+
+ LLVBOPool(U32 vboUsage, U32 vboType)
+ : mUsage(vboUsage)
+ , mType(vboType)
+ {}
+
+ const U32 mUsage;
+ const U32 mType;
- virtual void releaseName(GLuint name)
+ //size MUST be a power of 2
+ volatile U8* allocate(U32& name, U32 size);
+
+ //size MUST be the size provided to allocate that returned the given name
+ void release(U32 name, volatile U8* buffer, U32 size);
+
+ //destroy all records in mFreeList
+ void cleanup();
+
+ class Record
{
- stop_glerror();
- glDeleteBuffersARB(1, &name);
- stop_glerror();
- }
+ public:
+ U32 mGLName;
+ volatile U8* mClientData;
+ };
+
+ typedef std::list<Record> record_list_t;
+ std::vector<record_list_t> mFreeList;
};
class LLGLFence
@@ -79,7 +93,7 @@ public:
//============================================================================
// base class
-class LLPrivateMemoryPool ;
+class LLPrivateMemoryPool;
class LLVertexBuffer : public LLRefCount
{
public:
@@ -90,12 +104,11 @@ public:
S32 mIndex;
S32 mCount;
- MappedRegion(S32 type, S32 index, S32 count)
- : mType(type), mIndex(index), mCount(count)
- { }
+ MappedRegion(S32 type, S32 index, S32 count);
};
LLVertexBuffer(const LLVertexBuffer& rhs)
+ : mUsage(rhs.mUsage)
{
*this = rhs;
}
@@ -111,18 +124,17 @@ public:
static LLVBOPool sStreamIBOPool;
static LLVBOPool sDynamicIBOPool;
- static S32 sWeight4Loc;
-
- static BOOL sUseStreamDraw;
- static BOOL sPreferStreamDraw;
+ static bool sUseStreamDraw;
+ static bool sUseVAO;
+ static bool sPreferStreamDraw;
static void initClass(bool use_vbo, bool no_vbo_mapping);
static void cleanupClass();
static void setupClientArrays(U32 data_mask);
static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
+ static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
- static void clientCopy(F64 max_time = 0.005); //copy data from client to GL
- static void unbind(); //unbind any bound vertex buffer
+ static void unbind(); //unbind any bound vertex buffer
//get the size of a vertex with the given typemask
static S32 calcVertexSize(const U32& typemask);
@@ -133,24 +145,29 @@ public:
static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices);
+ //WARNING -- when updating these enums you MUST
+ // 1 - update LLVertexBuffer::sTypeSize
+ // 2 - add a strider accessor
+ // 3 - modify LLVertexBuffer::setupVertexBuffer
+ // 4 - modify LLVertexBuffer::setupClientArray
+ // 5 - modify LLViewerShaderMgr::mReservedAttribs
+ // 6 - update LLVertexBuffer::setupVertexArray
enum {
- TYPE_VERTEX,
+ TYPE_VERTEX = 0,
TYPE_NORMAL,
TYPE_TEXCOORD0,
TYPE_TEXCOORD1,
TYPE_TEXCOORD2,
TYPE_TEXCOORD3,
TYPE_COLOR,
- // These use VertexAttribPointer and should possibly be made generic
+ TYPE_EMISSIVE,
TYPE_BINORMAL,
TYPE_WEIGHT,
TYPE_WEIGHT4,
TYPE_CLOTHWEIGHT,
- TYPE_MAX,
- TYPE_INDEX,
-
- //no actual additional data, but indicates position.w is texture index
TYPE_TEXTURE_INDEX,
+ TYPE_MAX,
+ TYPE_INDEX,
};
enum {
MAP_VERTEX = (1<<TYPE_VERTEX),
@@ -160,6 +177,7 @@ public:
MAP_TEXCOORD2 = (1<<TYPE_TEXCOORD2),
MAP_TEXCOORD3 = (1<<TYPE_TEXCOORD3),
MAP_COLOR = (1<<TYPE_COLOR),
+ MAP_EMISSIVE = (1<<TYPE_EMISSIVE),
// These use VertexAttribPointer and should possibly be made generic
MAP_BINORMAL = (1<<TYPE_BINORMAL),
MAP_WEIGHT = (1<<TYPE_WEIGHT),
@@ -173,33 +191,35 @@ protected:
virtual ~LLVertexBuffer(); // use unref()
- virtual void setupVertexBuffer(U32 data_mask) const; // pure virtual, called from mapBuffer()
+ virtual void setupVertexBuffer(U32 data_mask); // pure virtual, called from mapBuffer()
+ void setupVertexArray();
- void genBuffer();
- void genIndices();
+ void genBuffer(U32 size);
+ void genIndices(U32 size);
+ bool bindGLBuffer(bool force_bind = false);
+ bool bindGLIndices(bool force_bind = false);
+ bool bindGLArray();
void releaseBuffer();
void releaseIndices();
- void createGLBuffer();
- void createGLIndices();
+ void createGLBuffer(U32 size);
+ void createGLIndices(U32 size);
void destroyGLBuffer();
void destroyGLIndices();
void updateNumVerts(S32 nverts);
void updateNumIndices(S32 nindices);
- virtual BOOL useVBOs() const;
- void unmapBuffer(S32 type);
- void freeClientBuffer() ;
- void allocateClientVertexBuffer() ;
- void allocateClientIndexBuffer() ;
-
+ bool useVBOs() const;
+ void unmapBuffer();
+
public:
LLVertexBuffer(U32 typemask, S32 usage);
// map for data access
- U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
- U8* mapIndexBuffer(S32 index, S32 count, bool map_range);
+ volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
+ volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range);
// set for rendering
- virtual void setBuffer(U32 data_mask, S32 type = -1); // calls setupVertexBuffer() if data_mask is not 0
+ virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0
+ void flush(); //flush pending data to GL memory
// allocate buffer
void allocateBuffer(S32 nverts, S32 nindices, bool create);
virtual void resizeBuffer(S32 newnverts, S32 newnindices);
@@ -212,33 +232,35 @@ public:
// setVertsNorms(verts, norms);
// vb->unmapBuffer();
bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool getVertexStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getIndexStrider(LLStrider<U16>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- BOOL isEmpty() const { return mEmpty; }
- BOOL isLocked() const { return mVertexLocked || mIndexLocked; }
+
+ bool isEmpty() const { return mEmpty; }
+ bool isLocked() const { return mVertexLocked || mIndexLocked; }
S32 getNumVerts() const { return mNumVerts; }
S32 getNumIndices() const { return mNumIndices; }
- S32 getRequestedVerts() const { return mRequestedNumVerts; }
- S32 getRequestedIndices() const { return mRequestedNumIndices; }
-
- U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
- U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
+
+ volatile U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
+ volatile U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
U32 getTypeMask() const { return mTypeMask; }
bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); }
S32 getSize() const;
- S32 getIndicesSize() const { return mNumIndices * sizeof(U16); }
- U8* getMappedData() const { return mMappedData; }
- U8* getMappedIndices() const { return mMappedIndexData; }
+ S32 getIndicesSize() const { return mIndicesSize; }
+ volatile U8* getMappedData() const { return mMappedData; }
+ volatile U8* getMappedIndices() const { return mMappedIndexData; }
S32 getOffset(S32 type) const { return mOffsets[type]; }
S32 getUsage() const { return mUsage; }
+ bool isWriteable() const { return (mMappable || mUsage == GL_STREAM_DRAW_ARB) ? true : false; }
void draw(U32 mode, U32 count, U32 indices_offset) const;
void drawArrays(U32 mode, U32 offset, U32 count) const;
@@ -252,25 +274,31 @@ public:
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 mSize;
+ S32 mIndicesSize;
U32 mTypeMask;
- S32 mUsage; // GL usage
+
+ const S32 mUsage; // GL usage
+
U32 mGLBuffer; // GL VBO handle
U32 mGLIndices; // GL IBO handle
- U8* mMappedData; // pointer to currently mapped data (NULL if unmapped)
- U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped)
- BOOL mVertexLocked; // if TRUE, vertex buffer is being or has been written to in client memory
- BOOL mIndexLocked; // if TRUE, index buffer is being or has been written to in client memory
- BOOL mFinal; // if TRUE, buffer can not be mapped again
- BOOL mFilthy; // if TRUE, entire buffer must be copied (used to prevent redundant dirty flags)
- BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded.
- 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)
+ U32 mGLArray; // GL VAO handle
+
+ volatile U8* mMappedData; // pointer to currently mapped data (NULL if unmapped)
+ volatile U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped)
+
+ U32 mMappedDataUsingVBOs : 1;
+ U32 mMappedIndexDataUsingVBOs : 1;
+ U32 mVertexLocked : 1; // if true, vertex buffer is being or has been written to in client memory
+ U32 mIndexLocked : 1; // if true, index buffer is being or has been written to in client memory
+ U32 mFinal : 1; // if true, buffer can not be mapped again
+ U32 mEmpty : 1; // if true, client buffer is empty (or NULL). Old values have been discarded.
+
+ mutable bool mMappable; // if true, use memory mapping to upload data (otherwise doublebuffer and use glBufferSubData)
+
S32 mOffsets[TYPE_MAX];
std::vector<MappedRegion> mMappedVertexRegions;
@@ -281,26 +309,27 @@ protected:
void placeFence() const;
void waitFence() const;
+ static S32 determineUsage(S32 usage);
private:
- static LLPrivateMemoryPool* sPrivatePoolp ;
+ static LLPrivateMemoryPool* sPrivatePoolp;
public:
static S32 sCount;
static S32 sGLCount;
static S32 sMappedCount;
- static BOOL sMapped;
- static std::vector<U32> sDeleteList;
+ static bool sMapped;
typedef std::list<LLVertexBuffer*> buffer_list_t;
- static BOOL sDisableVBOMapping; //disable glMapBufferARB
- static BOOL sEnableVBOs;
+ static bool sDisableVBOMapping; //disable glMapBufferARB
+ static bool sEnableVBOs;
static S32 sTypeSize[TYPE_MAX];
static U32 sGLMode[LLRender::NUM_MODES];
static U32 sGLRenderBuffer;
+ static U32 sGLRenderArray;
static U32 sGLRenderIndices;
- static BOOL sVBOActive;
- static BOOL sIBOActive;
+ static bool sVBOActive;
+ static bool sIBOActive;
static U32 sLastMask;
static U32 sAllocatedBytes;
static U32 sBindCount;