summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/CMakeLists.txt2
-rw-r--r--indra/llrender/llcubemap.cpp39
-rw-r--r--indra/llrender/llfontfreetype.cpp7
-rw-r--r--indra/llrender/llfontgl.cpp103
-rw-r--r--indra/llrender/llfontgl.h7
-rw-r--r--indra/llrender/llgl.cpp576
-rw-r--r--indra/llrender/llgl.h48
-rw-r--r--indra/llrender/llglheaders.h107
-rw-r--r--indra/llrender/llglslshader.cpp114
-rw-r--r--indra/llrender/llglslshader.h24
-rw-r--r--indra/llrender/llglstates.h5
-rw-r--r--indra/llrender/llimagegl.cpp436
-rw-r--r--indra/llrender/llimagegl.h61
-rw-r--r--indra/llrender/llpostprocess.cpp22
-rw-r--r--indra/llrender/llrender.cpp888
-rw-r--r--indra/llrender/llrender.h66
-rw-r--r--indra/llrender/llrendernavprim.cpp59
-rw-r--r--indra/llrender/llrendernavprim.h49
-rw-r--r--indra/llrender/llrendersphere.cpp98
-rw-r--r--indra/llrender/llrendersphere.h5
-rw-r--r--indra/llrender/llrendertarget.cpp191
-rw-r--r--indra/llrender/llrendertarget.h25
-rw-r--r--indra/llrender/llshadermgr.cpp601
-rw-r--r--indra/llrender/llshadermgr.h133
-rw-r--r--indra/llrender/llvertexbuffer.cpp2084
-rw-r--r--indra/llrender/llvertexbuffer.h211
26 files changed, 4333 insertions, 1628 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index 5c13df9f81..516af93316 100644
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -36,6 +36,7 @@ set(llrender_SOURCE_FILES
llglslshader.cpp
llimagegl.cpp
llpostprocess.cpp
+ llrendernavprim.cpp
llrendersphere.cpp
llshadermgr.cpp
lltexture.cpp
@@ -59,6 +60,7 @@ set(llrender_HEADER_FILES
llimagegl.h
llpostprocess.h
llrender.h
+ llrendernavprim.h
llrendersphere.h
llshadermgr.h
lltexture.h
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index fb22d7f1f5..362452d837 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"
@@ -80,7 +81,7 @@ void LLCubeMap::initGL()
{
U32 texname = 0;
- LLImageGL::generateTextures(1, &texname);
+ LLImageGL::generateTextures(LLTexUnit::TT_CUBE_MAP, GL_RGB8, 1, &texname);
for (int i = 0; i < 6; i++)
{
@@ -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)
{
@@ -259,47 +260,47 @@ void LLCubeMap::setMatrix(S32 stage)
if (mMatrixStage < 0) return;
- if (stage > 0)
+ //if (stage > 0)
{
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)
+ /*if (stage > 0)
{
gGL.getTexUnit(0)->activate();
- }
+ }*/
}
void LLCubeMap::restoreMatrix()
{
if (mMatrixStage < 0) return;
- if (mMatrixStage > 0)
+ //if (mMatrixStage > 0)
{
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)
+ /*if (mMatrixStage > 0)
{
gGL.getTexUnit(0)->activate();
- }
+ }*/
}
void LLCubeMap::setReflection (void)
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 180ae4dfa6..4dc2fcd714 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,18 +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 'in-world'
+ // and is correctly occluded.
+ gGL.translatef(0.f,0.f,sCurDepth);
S32 chars_drawn = 0;
S32 i;
@@ -212,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.
@@ -247,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();
@@ -301,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);
@@ -319,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)
{
@@ -375,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();
}
@@ -429,19 +422,19 @@ 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
+F32 LLFontGL::getAscenderHeight() const
{
- return (F32)llround(mFontFreetype->getLineHeight() / sScaleY);
+ return mFontFreetype->getAscenderHeight() / sScaleY;
}
-F32 LLFontGL::getAscenderHeight() const
+F32 LLFontGL::getDescenderHeight() const
{
- return (F32)llround(mFontFreetype->getAscenderHeight() / sScaleY);
+ return mFontFreetype->getDescenderHeight() / sScaleY;
}
-F32 LLFontGL::getDescenderHeight() const
+S32 LLFontGL::getLineHeight() const
{
- return (F32)llround(mFontFreetype->getDescenderHeight() / sScaleY);
+ return llceil(mFontFreetype->getAscenderHeight() / sScaleY) + llceil(mFontFreetype->getDescenderHeight() / sScaleY);
}
S32 LLFontGL::getWidth(const std::string& utf8text) const
@@ -630,7 +623,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;
}
@@ -701,7 +694,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)
@@ -784,7 +777,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);
@@ -1131,22 +1124,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..5ed5d2c4eb 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -115,9 +115,9 @@ 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 +188,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 c224ab0e9b..0b56b3889c 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -48,6 +48,7 @@
#include "llstacktrace.h"
#include "llglheaders.h"
+#include "llglslshader.h"
#ifdef _DEBUG
//#define GL_STATE_VERIFY
@@ -66,6 +67,42 @@ 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;
+ if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+ {
+ llerrs << "Halting on GL Error" << llendl;
+ }
+}
+#endif
+
+void parse_glsl_version(S32& major, S32& minor);
+
void ll_init_fail_log(std::string filename)
{
gFailLog.open(filename.c_str());
@@ -109,6 +146,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;
@@ -127,10 +169,28 @@ PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL;
PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL;
-// GL_ARB_map_buffer_range
-PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
-PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
+//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;
+
+// GL_ARB_sync
+PFNGLFENCESYNCPROC glFenceSync = NULL;
+PFNGLISSYNCPROC glIsSync = NULL;
+PFNGLDELETESYNCPROC glDeleteSync = NULL;
+PFNGLCLIENTWAITSYNCPROC glClientWaitSync = NULL;
+PFNGLWAITSYNCPROC glWaitSync = NULL;
+PFNGLGETINTEGER64VPROC glGetInteger64v = NULL;
+PFNGLGETSYNCIVPROC glGetSynciv = NULL;
+
+// GL_APPLE_flush_buffer_range
+PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE = NULL;
+PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE = NULL;
// vertex object prototypes
PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI = NULL;
@@ -184,10 +244,22 @@ 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;
+
+//transform feedback (4.0 core)
+PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = NULL;
+PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = NULL;
+PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = NULL;
+PFNGLBINDBUFFERRANGEPROC glBindBufferRange = 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;
@@ -235,6 +307,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
@@ -334,9 +411,11 @@ LLGLManager::LLGLManager() :
mHasFramebufferObject(FALSE),
mMaxSamples(0),
mHasBlendFuncSeparate(FALSE),
-
+ mHasSync(FALSE),
mHasVertexBufferObject(FALSE),
+ mHasVertexArrayObject(FALSE),
mHasMapBufferRange(FALSE),
+ mHasFlushBufferRange(FALSE),
mHasPBuffer(FALSE),
mHasShaderObjects(FALSE),
mHasVertexShader(FALSE),
@@ -348,6 +427,7 @@ LLGLManager::LLGLManager() :
mHasDrawBuffers(FALSE),
mHasTextureRectangle(FALSE),
mHasTextureMultisample(FALSE),
+ mHasTransformFeedback(FALSE),
mMaxSampleMaskWords(0),
mMaxColorTextureSamples(0),
mMaxDepthTextureSamples(0),
@@ -356,6 +436,7 @@ LLGLManager::LLGLManager() :
mHasAnisotropic(FALSE),
mHasARBEnvCombine(FALSE),
mHasCubeMap(FALSE),
+ mHasDebugOutput(FALSE),
mIsATI(FALSE),
mIsNVIDIA(FALSE),
@@ -376,7 +457,8 @@ LLGLManager::LLGLManager() :
mDriverVersionMinor(0),
mDriverVersionRelease(0),
mGLVersion(1.0f),
-
+ mGLSLVersionMajor(0),
+ mGLSLVersionMinor(0),
mVRAM(0),
mGLMaxVertexRange(0),
mGLMaxIndexRange(0)
@@ -395,6 +477,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");
@@ -424,12 +515,44 @@ 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)
+ {
+ glGetStringi = (PFNGLGETSTRINGIPROC) GLH_EXT_GET_PROC_ADDRESS("glGetStringi");
+ }
+
+ //reload extensions string (may have changed after using wglCreateContextAttrib)
+ if (glGetStringi)
{
- LL_WARNS("RenderInit") << "Frame buffer has less than 8 bits of alpha. Avatar texture compositing will fail." << LL_ENDL;
+ 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.
@@ -442,9 +565,33 @@ bool LLGLManager::initGL()
parse_gl_version( &mDriverVersionMajor,
&mDriverVersionMinor,
&mDriverVersionRelease,
- &mDriverVersionVendorString );
+ &mDriverVersionVendorString,
+ &mGLVersionString);
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
+ }
+
+ if (mGLVersion >= 2.1f && LLImageGL::sCompressTextures)
+ { //use texture compression
+ glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
+ }
+ else
+ { //GL version is < 3.0, always disable texture compression
+ LLImageGL::sCompressTextures = false;
+ }
// Trailing space necessary to keep "nVidia Corpor_ati_on" cards
// from being recognized as ATI.
@@ -466,11 +613,8 @@ bool LLGLManager::initGL()
#endif // LL_WINDOWS
#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
- // release 7277 is a point at which we verify that ATI OpenGL
- // drivers get pretty stable with SL, ~Catalyst 8.2,
- // for both Win32 and Linux.
- if (mDriverVersionRelease < 7277 &&
- mDriverVersionRelease != 0) // 0 == Undetectable driver version - these get to pretend to be new ATI drivers, though that decision may be revisited.
+ // count any pre OpenGL 3.0 implementation as an old driver
+ if (mGLVersion < 3.f)
{
mATIOldDriver = TRUE;
}
@@ -517,8 +661,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
@@ -534,7 +682,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);
@@ -553,12 +721,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)
{
@@ -568,6 +731,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
@@ -575,14 +753,26 @@ bool LLGLManager::initGL()
}
#endif
+ if (mIsIntel && mGLVersion <= 3.f)
+ { //never try to use framebuffer objects on older intel drivers (crashy)
+ mHasFramebufferObject = FALSE;
+ }
+
if (mHasFramebufferObject)
{
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
}
+
+ stop_glerror();
setToDebugGPU();
+ stop_glerror();
+
initGLStates();
+
+ stop_glerror();
+
return true;
}
@@ -686,14 +876,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)
@@ -760,11 +942,10 @@ 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);
- mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap");
mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color");
mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic");
glh_init_extensions("GL_ARB_texture_cube_map");
@@ -774,7 +955,10 @@ 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);
mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
#ifdef GL_ARB_framebuffer_object
@@ -786,17 +970,21 @@ void LLGLManager::initExtensions()
ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
#endif
+ mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f;
+
mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts);
+ mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
+ mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE;
#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
@@ -969,6 +1157,23 @@ 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");
+ glIsSync = (PFNGLISSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glIsSync");
+ glDeleteSync = (PFNGLDELETESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteSync");
+ glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glClientWaitSync");
+ glWaitSync = (PFNGLWAITSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glWaitSync");
+ glGetInteger64v = (PFNGLGETINTEGER64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInteger64v");
+ glGetSynciv = (PFNGLGETSYNCIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetSynciv");
+ }
if (mHasMapBufferRange)
{
glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glMapBufferRange");
@@ -1012,7 +1217,21 @@ void LLGLManager::initExtensions()
glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample");
glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv");
glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski");
- }
+ }
+ if (mHasTransformFeedback)
+ {
+ glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glBeginTransformFeedback");
+ glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback");
+ glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings");
+ glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange");
+ }
+ 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");
@@ -1131,6 +1350,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");
@@ -1167,7 +1387,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()
@@ -1204,10 +1424,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();
@@ -1300,11 +1516,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
@@ -1354,6 +1565,8 @@ void LLGLState::checkStates(const std::string& msg)
glGetIntegerv(GL_BLEND_SRC, &src);
glGetIntegerv(GL_BLEND_DST, &dst);
+ stop_glerror();
+
BOOL error = FALSE;
if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA)
@@ -1374,7 +1587,9 @@ void LLGLState::checkStates(const std::string& msg)
{
LLGLenum state = iter->first;
LLGLboolean cur_state = iter->second;
+ stop_glerror();
LLGLboolean gl_state = glIsEnabled(state);
+ stop_glerror();
if(cur_state != gl_state)
{
dumpStates();
@@ -1399,11 +1614,11 @@ void LLGLState::checkStates(const std::string& msg)
void LLGLState::checkTextureChannels(const std::string& msg)
{
+#if 0
if (!gDebugGL)
{
return;
}
-
stop_glerror();
GLint activeTexture;
@@ -1569,11 +1784,12 @@ void LLGLState::checkTextureChannels(const std::string& msg)
LL_GL_ERRS << "GL texture state corruption detected. " << msg << LL_ENDL;
}
}
+#endif
}
void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
{
- if (!gDebugGL)
+ if (!gDebugGL || LLGLSLShader::sNoFixedFunction)
{
return;
}
@@ -1594,7 +1810,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;
@@ -1603,7 +1819,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[] =
{
@@ -1630,7 +1846,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]))
{
@@ -1685,7 +1901,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
}
}
- if (glIsEnabled(GL_TEXTURE_2D))
+ /*if (glIsEnabled(GL_TEXTURE_2D))
{
if (!(data_mask & 0x0008))
{
@@ -1708,12 +1924,12 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
gFailLog << "GL does not have GL_TEXTURE_2D enabled on channel 1." << std::endl;
}
}
- }
+ }*/
glClientActiveTextureARB(GL_TEXTURE0_ARB);
gGL.getTexUnit(0)->activate();
- if (gGLManager.mHasVertexShader)
+ if (gGLManager.mHasVertexShader && LLGLSLShader::sNoFixedFunction)
{ //make sure vertex attribs are all disabled
GLint count;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &count);
@@ -1751,8 +1967,28 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
LLGLState::LLGLState(LLGLenum state, S32 enabled) :
mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
{
+ if (LLGLSLShader::sNoFixedFunction)
+ { //always ignore state that's deprecated post GL 3.0
+ switch (state)
+ {
+ case GL_ALPHA_TEST:
+ 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:
+ case GL_POLYGON_STIPPLE:
+ mState = 0;
+ break;
+ }
+ }
+
stop_glerror();
- if (state)
+ if (mState)
{
mWasEnabled = sStateMap[state];
llassert(mWasEnabled == glIsEnabled(state));
@@ -1834,80 +2070,7 @@ 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 )
+void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string )
{
// GL_VERSION returns a null-terminated string with the format:
// <major>.<minor>[.<release>] [<vendor specific>]
@@ -1923,6 +2086,8 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor
return;
}
+ version_string->assign(version);
+
std::string ver_copy( version );
S32 len = (S32)strlen( version ); /* Flawfinder: ignore */
S32 i = 0;
@@ -1987,6 +2152,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;
@@ -2019,20 +2233,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);
}
}
@@ -2110,8 +2324,7 @@ void LLGLNamePool::release(GLuint name)
void LLGLNamePool::upkeepPools()
{
LLMemType mt(LLMemType::MTYPE_UPKEEP_POOLS);
- tracker_t::LLInstanceTrackerScopedGuard guard;
- for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)
+ for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
{
LLGLNamePool & pool = *iter;
pool.upkeep();
@@ -2121,8 +2334,7 @@ void LLGLNamePool::upkeepPools()
//static
void LLGLNamePool::cleanupPools()
{
- tracker_t::LLInstanceTrackerScopedGuard guard;
- for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)
+ for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
{
LLGLNamePool & pool = *iter;
pool.cleanup();
@@ -2224,16 +2436,78 @@ 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);
}
+
+
+LLGLSyncFence::LLGLSyncFence()
+{
+#ifdef GL_ARB_sync
+ mSync = 0;
+#endif
+}
+
+LLGLSyncFence::~LLGLSyncFence()
+{
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ glDeleteSync(mSync);
+ }
+#endif
+}
+
+void LLGLSyncFence::placeFence()
+{
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ glDeleteSync(mSync);
+ }
+ mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+#endif
+}
+
+bool LLGLSyncFence::isCompleted()
+{
+ bool ret = true;
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ GLenum status = glClientWaitSync(mSync, 0, 1);
+ if (status == GL_TIMEOUT_EXPIRED)
+ {
+ ret = false;
+ }
+ }
+#endif
+ return ret;
+}
+
+void LLGLSyncFence::wait()
+{
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
+ { //track the number of times we've waited here
+ static S32 waits = 0;
+ waits++;
+ }
+ }
+#endif
+}
+
+
+
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index d1bee00161..964495a3ab 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -88,7 +88,10 @@ public:
// ARB Extensions
BOOL mHasVertexBufferObject;
+ BOOL mHasVertexArrayObject;
+ BOOL mHasSync;
BOOL mHasMapBufferRange;
+ BOOL mHasFlushBufferRange;
BOOL mHasPBuffer;
BOOL mHasShaderObjects;
BOOL mHasVertexShader;
@@ -101,6 +104,7 @@ public:
BOOL mHasDepthClamp;
BOOL mHasTextureRectangle;
BOOL mHasTextureMultisample;
+ BOOL mHasTransformFeedback;
S32 mMaxSampleMaskWords;
S32 mMaxColorTextureSamples;
S32 mMaxDepthTextureSamples;
@@ -110,6 +114,7 @@ public:
BOOL mHasAnisotropic;
BOOL mHasARBEnvCombine;
BOOL mHasCubeMap;
+ BOOL mHasDebugOutput;
// Vendor-specific extensions
BOOL mIsATI;
@@ -134,7 +139,10 @@ public:
S32 mDriverVersionMinor;
S32 mDriverVersionRelease;
F32 mGLVersion; // e.g = 1.4
+ S32 mGLSLVersionMajor;
+ S32 mGLSLVersionMinor;
std::string mDriverVersionVendorString;
+ std::string mGLVersionString;
S32 mVRAM; // VRAM in MB
S32 mGLMaxVertexRange;
@@ -146,7 +154,6 @@ public:
void printGLInfoString();
void getGLInfo(LLSD& info);
- U32 getNumFBOFSAASamples(U32 desired_samples = 32);
// In ALL CAPS
std::string mGLVendor;
std::string mGLVendorShort;
@@ -250,7 +257,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;
@@ -412,21 +419,38 @@ public:
virtual void updateGL() = 0;
};
+const U32 FENCE_WAIT_TIME_NANOSECONDS = 1000; //1 ms
+
+class LLGLFence
+{
+public:
+ virtual void placeFence() = 0;
+ virtual bool isCompleted() = 0;
+ virtual void wait() = 0;
+};
+
+class LLGLSyncFence : public LLGLFence
+{
+public:
+#ifdef GL_ARB_sync
+ GLsync mSync;
+#endif
+
+ LLGLSyncFence();
+ virtual ~LLGLSyncFence();
+
+ void placeFence();
+ bool isCompleted();
+ void wait();
+};
+
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 );
+
+void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string );
extern BOOL gClothRipple;
extern BOOL gHeadlessClient;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index f35f329f00..a0727b8686 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -68,6 +68,25 @@ 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;
+extern PFNGLDELETESYNCPROC glDeleteSync;
+extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
+extern PFNGLWAITSYNCPROC glWaitSync;
+extern PFNGLGETINTEGER64VPROC glGetInteger64v;
+extern PFNGLGETSYNCIVPROC glGetSynciv;
+
+// GL_APPLE_flush_buffer_range
+extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE;
+extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
+
// GL_ARB_map_buffer_range
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
@@ -180,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;
@@ -297,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;
@@ -310,6 +336,19 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
+// GL_ARB_sync
+extern PFNGLFENCESYNCPROC glFenceSync;
+extern PFNGLISSYNCPROC glIsSync;
+extern PFNGLDELETESYNCPROC glDeleteSync;
+extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
+extern PFNGLWAITSYNCPROC glWaitSync;
+extern PFNGLGETINTEGER64VPROC glGetInteger64v;
+extern PFNGLGETSYNCIVPROC glGetSynciv;
+
+// GL_APPLE_flush_buffer_range
+extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE;
+extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
+
// GL_ARB_map_buffer_range
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
@@ -422,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;
@@ -488,6 +528,13 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
+//transform feedback (4.0 core)
+extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
+extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
+extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
+extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
+
+
#elif LL_WINDOWS
//----------------------------------------------------------------------------
// LL_WINDOWS
@@ -505,6 +552,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;
@@ -519,6 +569,25 @@ 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;
+extern PFNGLDELETESYNCPROC glDeleteSync;
+extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
+extern PFNGLWAITSYNCPROC glWaitSync;
+extern PFNGLGETINTEGER64VPROC glGetInteger64v;
+extern PFNGLGETSYNCIVPROC glGetSynciv;
+
+// GL_APPLE_flush_buffer_range
+extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE;
+extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
+
// GL_ARB_map_buffer_range
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
@@ -633,6 +702,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;
@@ -696,6 +766,18 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
+//transform feedback (4.0 core)
+extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
+extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
+extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
+extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
+
+//GL_ARB_debug_output
+extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
+extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
+extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
+extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB;
+
#elif LL_DARWIN
//----------------------------------------------------------------------------
// LL_DARWIN
@@ -860,6 +942,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 ad2c662dfc..7cbf39096e 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"
@@ -49,6 +50,13 @@ using std::make_pair;
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
+LLGLSLShader gUIProgram;
+LLGLSLShader gSolidColorProgram;
BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
{
@@ -56,9 +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)
+ : 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)
{
}
@@ -68,6 +90,7 @@ hasGamma(false), hasLighting(false), calculatesAtmospherics(false), mIndexedText
LLGLSLShader::LLGLSLShader()
: mProgramObject(0), mActiveTextureChannels(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT), mUniformsDirty(FALSE)
{
+
}
void LLGLSLShader::unload()
@@ -86,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);
@@ -101,19 +129,23 @@ void LLGLSLShader::unload()
}
BOOL LLGLSLShader::createShader(vector<string> * attributes,
- vector<string> * uniforms)
+ vector<string> * uniforms,
+ U32 varying_count,
+ const char** varyings)
{
+ //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++ )
@@ -136,11 +168,19 @@ 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);
}
+#ifdef GL_INTERLEAVED_ATTRIBS
+ if (varying_count > 0 && varyings)
+ {
+ glTransformFeedbackVaryings(mProgramObject, varying_count, varyings, GL_INTERLEAVED_ATTRIBS);
+ }
+#endif
+
// Map attributes and uniforms
if (success)
{
@@ -228,6 +268,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();
@@ -301,7 +348,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;
@@ -315,7 +362,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;
@@ -376,10 +423,13 @@ BOOL LLGLSLShader::link(BOOL suppress_errors)
void LLGLSLShader::bind()
{
+ gGL.flush();
if (gGLManager.mHasShaderObjects)
{
+ LLVertexBuffer::unbind();
glUseProgramObjectARB(mProgramObject);
sCurBoundShader = mProgramObject;
+ sCurBoundShaderPtr = this;
if (mUniformsDirty)
{
LLShaderMgr::instance()->updateShaderUniforms(this);
@@ -390,6 +440,7 @@ void LLGLSLShader::bind()
void LLGLSLShader::unbind()
{
+ gGL.flush();
if (gGLManager.mHasShaderObjects)
{
stop_glerror();
@@ -401,16 +452,23 @@ void LLGLSLShader::unbind()
stop_glerror();
}
}
+ LLVertexBuffer::unbind();
glUseProgramObjectARB(0);
sCurBoundShader = 0;
+ sCurBoundShaderPtr = NULL;
stop_glerror();
}
}
void LLGLSLShader::bindNoShader(void)
{
- glUseProgramObjectARB(0);
- sCurBoundShader = 0;
+ LLVertexBuffer::unbind();
+ if (gGLManager.mHasShaderObjects)
+ {
+ glUseProgramObjectARB(0);
+ sCurBoundShader = 0;
+ sCurBoundShaderPtr = NULL;
+ }
}
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode)
@@ -756,13 +814,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;
}
@@ -918,7 +980,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;
}
}
@@ -972,3 +1036,9 @@ void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v)
glVertexAttrib4fvARB(mAttribute[index], v);
}
}
+
+void LLGLSLShader::setMinimumAlpha(F32 minimum)
+{
+ gGL.flush();
+ uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum);
+}
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 4922eb6d67..5c68cb46eb 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;
@@ -47,6 +49,7 @@ public:
bool hasGamma;
S32 mIndexedTextureChannels;
bool disableTextureIndex;
+ bool hasAlphaMask;
// char numLights;
@@ -67,10 +70,15 @@ public:
LLGLSLShader();
static GLhandleARB sCurBoundShader;
+ static LLGLSLShader* sCurBoundShaderPtr;
+ static S32 sIndexedTextureChannels;
+ static bool sNoFixedFunction;
void unload();
BOOL createShader(std::vector<std::string> * attributes,
- std::vector<std::string> * uniforms);
+ std::vector<std::string> * uniforms,
+ U32 varying_count = 0,
+ const char** varyings = NULL);
BOOL attachObject(std::string object);
void attachObject(GLhandleARB object);
void attachObjects(GLhandleARB* objects = NULL, S32 count = 0);
@@ -104,14 +112,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 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
@@ -126,6 +137,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
@@ -141,4 +155,10 @@ public:
std::string mName;
};
+//UI shader (declared here so llui_libtest will link properly)
+extern LLGLSLShader gUIProgram;
+//output vec4(color.rgb,color.a*tex0[tc0].a)
+extern LLGLSLShader gSolidColorProgram;
+
+
#endif
diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h
index e26aead676..0e2c3bcb44 100644
--- a/indra/llrender/llglstates.h
+++ b/indra/llrender/llglstates.h
@@ -59,7 +59,6 @@ protected:
LLGLEnable mColorMaterial;
LLGLDisable mAlphaTest, mBlend, mCullFace, mDither, mFog,
mLineSmooth, mLineStipple, mNormalize, mPolygonSmooth,
- mTextureGenQ, mTextureGenR, mTextureGenS, mTextureGenT,
mGLMultisample;
public:
LLGLSDefault()
@@ -76,10 +75,6 @@ public:
mLineStipple(GL_LINE_STIPPLE),
mNormalize(GL_NORMALIZE),
mPolygonSmooth(GL_POLYGON_SMOOTH),
- mTextureGenQ(GL_TEXTURE_GEN_Q),
- mTextureGenR(GL_TEXTURE_GEN_R),
- mTextureGenS(GL_TEXTURE_GEN_S),
- mTextureGenT(GL_TEXTURE_GEN_T),
mGLMultisample(GL_MULTISAMPLE_ARB)
{ }
};
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 60a5962234..a842211764 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -36,12 +36,17 @@
#include "llmath.h"
#include "llgl.h"
+#include "llglslshader.h"
#include "llrender.h"
+
//----------------------------------------------------------------------------
const F32 MIN_TEXTURE_LIFETIME = 10.f;
+//which power of 2 is i?
+//assumes i is a power of 2 > 0
+U32 wpo2(U32 i);
+
//statics
-LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 };
U32 LLImageGL::sUniqueCount = 0;
U32 LLImageGL::sBindCount = 0;
@@ -49,12 +54,14 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes = 0;
S32 LLImageGL::sBoundTextureMemoryInBytes = 0;
S32 LLImageGL::sCurBoundTextureMemory = 0;
S32 LLImageGL::sCount = 0;
-std::list<U32> LLImageGL::sDeadTextureList;
+LLImageGL::dead_texturelist_t LLImageGL::sDeadTextureList[LLTexUnit::TT_NONE];
+U32 LLImageGL::sCurTexName = 1;
BOOL LLImageGL::sGlobalUseAnisotropic = FALSE;
F32 LLImageGL::sLastFrameTime = 0.f;
BOOL LLImageGL::sAllowReadBackRaw = FALSE ;
LLImageGL* LLImageGL::sDefaultGLTexture = NULL ;
+bool LLImageGL::sCompressTextures = false;
std::set<LLImageGL*> LLImageGL::sImageList;
@@ -63,19 +70,10 @@ std::set<LLImageGL*> LLImageGL::sImageList;
//****************************************************************************************************
//-----------------------
//debug use
-BOOL gAuditTexture = FALSE ;
-#define MAX_TEXTURE_LOG_SIZE 22 //2048 * 2048
-std::vector<S32> LLImageGL::sTextureLoadedCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
-std::vector<S32> LLImageGL::sTextureBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
-std::vector<S32> LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
S32 LLImageGL::sCurTexSizeBar = -1 ;
S32 LLImageGL::sCurTexPickSize = -1 ;
-LLPointer<LLImageGL> LLImageGL::sHighlightTexturep = NULL;
-S32 LLImageGL::sMaxCatagories = 1 ;
+S32 LLImageGL::sMaxCategories = 1 ;
-std::vector<S32> LLImageGL::sTextureMemByCategory;
-std::vector<S32> LLImageGL::sTextureMemByCategoryBound ;
-std::vector<S32> LLImageGL::sTextureCurMemByCategoryBound ;
//------------------------
//****************************************************************************************************
//End for texture auditing use only
@@ -173,49 +171,11 @@ BOOL is_little_endian()
//static
void LLImageGL::initClass(S32 num_catagories)
{
- sMaxCatagories = num_catagories ;
-
- sTextureMemByCategory.resize(sMaxCatagories);
- sTextureMemByCategoryBound.resize(sMaxCatagories) ;
- sTextureCurMemByCategoryBound.resize(sMaxCatagories) ;
}
//static
void LLImageGL::cleanupClass()
{
- sTextureMemByCategory.clear() ;
- sTextureMemByCategoryBound.clear() ;
- sTextureCurMemByCategoryBound.clear() ;
-}
-
-//static
-void LLImageGL::setHighlightTexture(S32 category)
-{
- const S32 dim = 128;
- sHighlightTexturep = new LLImageGL() ;
- LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3);
- U8* data = image_raw->getData();
- for (S32 i = 0; i<dim; i++)
- {
- for (S32 j = 0; j<dim; j++)
- {
- const S32 border = 2;
- if (i<border || j<border || i>=(dim-border) || j>=(dim-border))
- {
- *data++ = 0xff;
- *data++ = 0xff;
- *data++ = 0xff;
- }
- else
- {
- *data++ = 0xff;
- *data++ = 0xff;
- *data++ = 0x00;
- }
- }
- }
- sHighlightTexturep->createGLTexture(0, image_raw, 0, TRUE, category);
- image_raw = NULL;
}
//static
@@ -277,37 +237,19 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
//----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_STATS("Image Stats");
// static
void LLImageGL::updateStats(F32 current_time)
{
+ LLFastTimer t(FTM_IMAGE_UPDATE_STATS);
sLastFrameTime = current_time;
sBoundTextureMemoryInBytes = sCurBoundTextureMemory;
sCurBoundTextureMemory = 0;
-
- if(gAuditTexture)
- {
- for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++)
- {
- sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ;
- sTextureCurBoundCounter[i] = 0 ;
- }
- for(U32 i = 0 ; i < sTextureCurMemByCategoryBound.size() ; i++)
- {
- sTextureMemByCategoryBound[i] = sTextureCurMemByCategoryBound[i] ;
- sTextureCurMemByCategoryBound[i] = 0 ;
- }
- }
}
//static
S32 LLImageGL::updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category)
{
- if(gAuditTexture && ncomponents > 0 && category > -1)
- {
- sTextureCurBoundCounter[getTextureCounterIndex(mem / ncomponents)]++ ;
- sTextureCurMemByCategoryBound[category] += mem ;
- }
-
LLImageGL::sCurBoundTextureMemory += mem ;
return LLImageGL::sCurBoundTextureMemory;
}
@@ -475,10 +417,13 @@ void LLImageGL::init(BOOL usemipmaps)
mDiscardLevelInAtlas = -1 ;
mTexelsInAtlas = 0 ;
mTexelsInGLTexture = 0 ;
+
+ mAllowCompression = true;
mTarget = GL_TEXTURE_2D;
mBindTarget = LLTexUnit::TT_TEXTURE;
mHasMipMaps = false;
+ mMipLevels = -1;
mIsResident = 0;
@@ -669,8 +614,24 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
is_compressed = true;
}
+
+
+ if (mUseMipMaps)
+ {
+ //set has mip maps to true before binding image so tex parameters get set properly
+ gGL.getTexUnit(0)->unbind(mBindTarget);
+ mHasMipMaps = true;
+ mTexOptionsDirty = true;
+ setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
+ }
+ else
+ {
+ mHasMipMaps = false;
+ }
+
llverify(gGL.getTexUnit(0)->bind(this));
+
if (mUseMipMaps)
{
if (data_hasmips)
@@ -683,6 +644,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
S32 w = getWidth(d);
S32 h = getHeight(d);
S32 gl_level = d-mCurrentDiscardLevel;
+
+ mMipLevels = llmax(mMipLevels, gl_level);
+
if (d > mCurrentDiscardLevel)
{
data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment
@@ -703,7 +667,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
stop_glerror();
}
- LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in);
+ LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in, mAllowCompression);
if (gl_level == 0)
{
analyzeAlpha(data_in, w, h);
@@ -725,7 +689,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
{
if (mAutoGenMips)
{
- glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
stop_glerror();
{
// LLFastTimer t2(FTM_TEMP4);
@@ -739,10 +702,15 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
S32 w = getWidth(mCurrentDiscardLevel);
S32 h = getHeight(mCurrentDiscardLevel);
+ mMipLevels = wpo2(llmax(w, h));
+
+ //use legacy mipmap generation mode
+ glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE);
+
LLImageGL::setManualImage(mTarget, 0, mFormatInternal,
w, h,
mFormatPrimary, mFormatType,
- data_in);
+ data_in, mAllowCompression);
analyzeAlpha(data_in, w, h);
stop_glerror();
@@ -758,7 +726,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
else
{
// Create mips by hand
- // about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800
// ~4x faster than gluBuild2DMipmaps
S32 width = getWidth(mCurrentDiscardLevel);
S32 height = getHeight(mCurrentDiscardLevel);
@@ -768,6 +735,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
const U8* cur_mip_data = 0;
S32 prev_mip_size = 0;
S32 cur_mip_size = 0;
+
+ mMipLevels = nummips;
+
for (int m=0; m<nummips; m++)
{
if (m==0)
@@ -795,7 +765,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
stop_glerror();
}
- LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data);
+ LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression);
if (m == 0)
{
analyzeAlpha(data_in, w, h);
@@ -832,10 +802,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
{
llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl;
}
- mHasMipMaps = true;
}
else
{
+ mMipLevels = 0;
S32 w = getWidth();
S32 h = getHeight();
if (is_compressed)
@@ -853,7 +823,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
}
LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h,
- mFormatPrimary, mFormatType, (GLvoid *)data_in);
+ mFormatPrimary, mFormatType, (GLvoid *)data_in, mAllowCompression);
analyzeAlpha(data_in, w, h);
updatePickMask(w, h, data_in);
@@ -867,7 +837,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
}
}
- mHasMipMaps = false;
}
stop_glerror();
mGLTextureCreated = true;
@@ -875,6 +844,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 +873,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;
}
}
@@ -1077,30 +1049,169 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
}
// static
-void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
+void LLImageGL::generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures)
{
- glGenTextures(numTextures, (GLuint*)textures);
+ bool empty = true;
+
+ dead_texturelist_t::iterator iter = sDeadTextureList[type].find(format);
+
+ if (iter != sDeadTextureList[type].end())
+ {
+ empty = iter->second.empty();
+ }
+
+ for (S32 i = 0; i < numTextures; ++i)
+ {
+ if (!empty)
+ {
+ textures[i] = iter->second.front();
+ iter->second.pop_front();
+ empty = iter->second.empty();
+ }
+ else
+ {
+ textures[i] = sCurTexName++;
+ }
+ }
}
// static
-void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate)
+void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate)
{
- for (S32 i = 0; i < numTextures; i++)
+ if (gGLManager.mInited)
{
- sDeadTextureList.push_back(textures[i]);
- }
+ if (format == 0 || type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1)
+ { //unknown internal format or unknown number of mip levels, not safe to reuse
+ glDeleteTextures(numTextures, textures);
+ }
+ else
+ {
+ for (S32 i = 0; i < numTextures; ++i)
+ { //remove texture from VRAM by setting its size to zero
+ for (S32 j = 0; j <= mip_levels; j++)
+ {
+ gGL.getTexUnit(0)->bindManual(type, textures[i]);
+
+ glTexImage2D(LLTexUnit::getInternalType(type), j, format, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ }
- if (immediate)
+ llassert(std::find(sDeadTextureList[type][format].begin(),
+ sDeadTextureList[type][format].end(), textures[i]) ==
+ sDeadTextureList[type][format].end());
+
+ sDeadTextureList[type][format].push_back(textures[i]);
+ }
+ }
+ }
+
+ /*if (immediate)
{
LLImageGL::deleteDeadTextures();
- }
+ }*/
}
// static
-void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels)
+void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression)
{
- 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;
+ }
+ }
+
+ if (LLImageGL::sCompressTextures && allow_compression)
+ {
+ switch (intformat)
+ {
+ case GL_RGB:
+ case GL_RGB8:
+ intformat = GL_COMPRESSED_RGB;
+ break;
+ case GL_RGBA:
+ case GL_RGBA8:
+ intformat = GL_COMPRESSED_RGBA;
+ break;
+ case GL_LUMINANCE:
+ case GL_LUMINANCE8:
+ intformat = GL_COMPRESSED_LUMINANCE;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ case GL_LUMINANCE8_ALPHA8:
+ intformat = GL_COMPRESSED_LUMINANCE_ALPHA;
+ break;
+ case GL_ALPHA:
+ case GL_ALPHA8:
+ intformat = GL_COMPRESSED_ALPHA;
+ break;
+ default:
+ llwarns << "Could not compress format: " << std::hex << intformat << llendl;
+ break;
+ }
+ }
+
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
@@ -1121,10 +1232,11 @@ BOOL LLImageGL::createGLTexture()
if(mTexName)
{
- glDeleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ;
+ LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, (reinterpret_cast<GLuint*>(&mTexName))) ;
}
- glGenTextures(1, (GLuint*)&mTexName);
+
+ LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName);
stop_glerror();
if (!mTexName)
{
@@ -1167,29 +1279,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;
}
@@ -1204,7 +1316,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
return TRUE ;
}
- setCategory(category) ;
+ setCategory(category);
const U8* rawdata = imageraw->getData();
return createGLTexture(discard_level, rawdata, FALSE, usename);
}
@@ -1212,6 +1324,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)
{
@@ -1236,12 +1349,15 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
}
else
{
- LLImageGL::generateTextures(1, &mTexName);
+ LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName);
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)
@@ -1278,12 +1394,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
{
sGlobalTextureMemoryInBytes -= mTextureMemory;
- if(gAuditTexture)
- {
- decTextureCounter(mTextureMemory, mComponents, mCategory) ;
- }
-
- LLImageGL::deleteTextures(1, &old_name);
+ LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &old_name);
stop_glerror();
}
@@ -1292,10 +1403,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
sGlobalTextureMemoryInBytes += mTextureMemory;
mTexelsInGLTexture = getWidth() * getHeight() ;
- if(gAuditTexture)
- {
- incTextureCounter(mTextureMemory, mComponents, mCategory) ;
- }
// mark this as bound at this point, so we don't throw it out immediately
mLastBindTime = sLastFrameTime;
return TRUE;
@@ -1414,7 +1521,9 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
void LLImageGL::deleteDeadTextures()
{
- while (!sDeadTextureList.empty())
+ bool reset = false;
+
+ /*while (!sDeadTextureList.empty())
{
GLuint tex = sDeadTextureList.front();
sDeadTextureList.pop_front();
@@ -1422,15 +1531,25 @@ void LLImageGL::deleteDeadTextures()
{
LLTexUnit* tex_unit = gGL.getTexUnit(i);
- if (tex_unit->getCurrTexture() == tex)
+ if (tex_unit && tex_unit->getCurrTexture() == tex)
{
tex_unit->unbind(tex_unit->getCurrType());
stop_glerror();
+
+ if (i > 0)
+ {
+ reset = true;
+ }
}
}
glDeleteTextures(1, &tex);
stop_glerror();
+ }*/
+
+ if (reset)
+ {
+ gGL.getTexUnit(0)->activate();
}
}
@@ -1440,22 +1559,29 @@ void LLImageGL::destroyGLTexture()
{
if(mTextureMemory)
{
- if(gAuditTexture)
- {
- decTextureCounter(mTextureMemory, mComponents, mCategory) ;
- }
sGlobalTextureMemoryInBytes -= mTextureMemory;
mTextureMemory = 0;
}
- LLImageGL::deleteTextures(1, &mTexName);
- mTexName = 0;
+ LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &mTexName);
mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
+ mTexName = 0;
mGLTextureCreated = FALSE ;
- }
+ }
}
-
+//force to invalidate the gl texture, most likely a sculpty texture
+void LLImageGL::forceToInvalidateGLTexture()
+{
+ if (mTexName != 0)
+ {
+ destroyGLTexture();
+ }
+ else
+ {
+ mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
+ }
+}
//----------------------------------------------------------------------------
@@ -1742,7 +1868,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];
}
@@ -1757,7 +1883,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
{
@@ -1873,68 +1999,6 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
return res;
}
-void LLImageGL::setCategory(S32 category)
-{
- if(!gAuditTexture)
- {
- return ;
- }
- if(mCategory != category)
- {
- if(mCategory > -1)
- {
- sTextureMemByCategory[mCategory] -= mTextureMemory ;
- }
- if(category > -1 && category < sMaxCatagories)
- {
- sTextureMemByCategory[category] += mTextureMemory ;
- mCategory = category;
- }
- else
- {
- mCategory = -1 ;
- }
- }
-}
-
-//for debug use
-//val is a "power of two" number
-S32 LLImageGL::getTextureCounterIndex(U32 val)
-{
- //index range is [0, MAX_TEXTURE_LOG_SIZE].
- if(val < 2)
- {
- return 0 ;
- }
- else if(val >= (1 << MAX_TEXTURE_LOG_SIZE))
- {
- return MAX_TEXTURE_LOG_SIZE ;
- }
- else
- {
- S32 ret = 0 ;
- while(val >>= 1)
- {
- ++ret;
- }
- return ret ;
- }
-}
-
-//static
-void LLImageGL::incTextureCounter(U32 val, S32 ncomponents, S32 category)
-{
- sTextureLoadedCounter[getTextureCounterIndex(val)]++ ;
- sTextureMemByCategory[category] += (S32)val * ncomponents ;
-}
-
-//static
-void LLImageGL::decTextureCounter(U32 val, S32 ncomponents, S32 category)
-{
- sTextureLoadedCounter[getTextureCounterIndex(val)]-- ;
- sTextureMemByCategory[category] += (S32)val * ncomponents ;
-}
-
void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size)
{
sCurTexSizeBar = index ;
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 2cfb15b0d9..e118c28c1b 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -45,8 +45,16 @@ class LLImageGL : public LLRefCount
{
friend class LLTexUnit;
public:
- static std::list<U32> sDeadTextureList;
+ static U32 sCurTexName;
+ //previously used but now available texture names
+ // sDeadTextureList[<usage>][<internal format>]
+ typedef std::map<U32, std::list<U32> > dead_texturelist_t;
+ static dead_texturelist_t sDeadTextureList[LLTexUnit::TT_NONE];
+
+ // These 2 functions replace glGenTextures() and glDeleteTextures()
+ static void generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures);
+ static void deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate = false);
static void deleteDeadTextures();
// Size calculation
@@ -94,16 +102,13 @@ public:
void setSize(S32 width, S32 height, S32 ncomponents);
void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;}
+ void setAllowCompression(bool allow) { mAllowCompression = allow; }
- // These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D()
- // for tracking purposes and will be deprecated in the future
- static void generateTextures(S32 numTextures, U32 *textures);
- static void deleteTextures(S32 numTextures, U32 *textures, bool immediate = false);
- static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels);
+ static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true);
BOOL createGLTexture() ;
- BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE,
- S32 category = sMaxCatagories - 1);
+ BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE,
+ S32 category = sMaxCategories-1);
BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0);
void setImage(const LLImageRaw* imageraw);
void setImage(const U8* data_in, BOOL data_hasmips = FALSE);
@@ -114,6 +119,7 @@ public:
// Read back a raw image for this discard level, if it exists
BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;
void destroyGLTexture();
+ void forceToInvalidateGLTexture();
void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
void setComponents(S8 ncomponents) { mComponents = ncomponents; }
@@ -209,11 +215,14 @@ private:
U32 mTexelsInAtlas ;
U32 mTexelsInGLTexture;
+ bool mAllowCompression;
+
protected:
LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps)
LLTexUnit::eTextureType mBindTarget; // Normally TT_TEXTURE, sometimes something else (ex. cube maps)
bool mHasMipMaps;
-
+ S32 mMipLevels;
+
LLGLboolean mIsResident;
S8 mComponents;
@@ -234,8 +243,6 @@ public:
static S32 sCount;
static F32 sLastFrameTime;
-
- static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID
// Global memory statistics
static S32 sGlobalTextureMemoryInBytes; // Tracks main memory texmem
@@ -246,7 +253,7 @@ public:
static BOOL sGlobalUseAnisotropic;
static LLImageGL* sDefaultGLTexture ;
static BOOL sAutomatedTest;
-
+ static bool sCompressTextures; //use GL texture compression
#if DEBUG_MISS
BOOL mMissed; // Missed on last bind?
BOOL getMissed() const { return mMissed; };
@@ -257,9 +264,10 @@ public:
public:
static void initClass(S32 num_catagories) ;
static void cleanupClass() ;
-private:
- static S32 sMaxCatagories ;
+private:
+ static S32 sMaxCategories;
+
//the flag to allow to call readBackRaw(...).
//can be removed if we do not use that function at all.
static BOOL sAllowReadBackRaw ;
@@ -269,39 +277,22 @@ private:
//****************************************************************************************************
private:
S32 mCategory ;
-public:
- void setCategory(S32 category) ;
- S32 getCategory()const {return mCategory ;}
-
+public:
+ void setCategory(S32 category) {mCategory = category;}
+ S32 getCategory()const {return mCategory;}
+
//for debug use: show texture size distribution
//----------------------------------------
- static LLPointer<LLImageGL> sHighlightTexturep; //default texture to replace normal textures
- static std::vector<S32> sTextureLoadedCounter ;
- static std::vector<S32> sTextureBoundCounter ;
- static std::vector<S32> sTextureCurBoundCounter ;
static S32 sCurTexSizeBar ;
static S32 sCurTexPickSize ;
- static void setHighlightTexture(S32 category) ;
- static S32 getTextureCounterIndex(U32 val) ;
- static void incTextureCounter(U32 val, S32 ncomponents, S32 category) ;
- static void decTextureCounter(U32 val, S32 ncomponents, S32 category) ;
static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ;
static void resetCurTexSizebar();
- //----------------------------------------
- //for debug use: show texture category distribution
- //----------------------------------------
-
- static std::vector<S32> sTextureMemByCategory;
- static std::vector<S32> sTextureMemByCategoryBound ;
- static std::vector<S32> sTextureCurMemByCategoryBound ;
- //----------------------------------------
//****************************************************************************************************
//End of definitions for texture auditing use only
//****************************************************************************************************
};
-extern BOOL gAuditTexture;
#endif // LL_LLIMAGEGL_H
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 1d82dda30f..4597d06260 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -1,4 +1,4 @@
-/**
+ /**
* @file llrender.cpp
* @brief LLRender implementation
*
@@ -34,18 +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;
@@ -126,7 +129,8 @@ void LLTexUnit::refreshState(void)
// Per apple spec, don't call glEnable/glDisable when index exceeds max texture units
// http://www.mailinglistarchive.com/html/mac-opengl@lists.apple.com/2008-07/msg00653.html
//
- bool enableDisable = (mIndex < gGLManager.mNumTextureUnits) && mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE;
+ bool enableDisable = !LLGLSLShader::sNoFixedFunction &&
+ (mIndex < gGLManager.mNumTextureUnits) && mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE;
if (mCurrTexType != TT_NONE)
{
@@ -176,18 +180,24 @@ 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;
gGL.flush();
- if (type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
+ if (!LLGLSLShader::sNoFixedFunction &&
+ type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
mIndex < gGLManager.mNumTextureUnits)
{
+ stop_glerror();
glEnable(sGLTextureType[type]);
+ stop_glerror();
}
}
}
@@ -201,7 +211,8 @@ void LLTexUnit::disable(void)
activate();
unbind(mCurrTexType);
gGL.flush();
- if (mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
+ if (!LLGLSLShader::sNoFixedFunction &&
+ mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
mIndex < gGLManager.mNumTextureUnits)
{
glDisable(sGLTextureType[mCurrTexType]);
@@ -235,14 +246,6 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
}
//in audit, replace the selected texture by the default one.
- if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0)
- {
- if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize)
- {
- gl_tex->updateBindStats(gl_tex->mTextureMemory);
- return bind(LLImageGL::sHighlightTexturep.get());
- }
- }
if ((mCurrTexture != gl_tex->getTexName()) || forceBind)
{
activate();
@@ -282,26 +285,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;
}
@@ -396,14 +408,23 @@ void LLTexUnit::unbind(eTextureType type)
if (mIndex < 0) return;
+ //always flush and activate for consistency
+ // some code paths assume unbind always flushes and sets the active texture
+ gGL.flush();
+ activate();
+
// Disabled caching of binding state.
if (mCurrTexType == type)
{
- gGL.flush();
-
- activate();
mCurrTexture = 0;
- glBindTexture(sGLTextureType[type], 0);
+ if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE)
+ {
+ glBindTexture(sGLTextureType[type], sWhiteTexture);
+ }
+ else
+ {
+ glBindTexture(sGLTextureType[type], 0);
+ }
stop_glerror();
}
}
@@ -445,11 +466,25 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
}
else if (option >= TFO_BILINEAR)
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ if (mHasMipMaps)
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ }
+ else
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
}
else
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ if (mHasMipMaps)
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ }
+ else
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
}
if (gGLManager.mHasAnisotropic)
@@ -474,6 +509,11 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
void LLTexUnit::setTextureBlendType(eTextureBlendType type)
{
+ if (LLGLSLShader::sNoFixedFunction)
+ { //texture blend type means nothing when using shaders
+ return;
+ }
+
if (mIndex < 0) return;
// Do nothing if it's already correctly set.
@@ -594,6 +634,11 @@ GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha)
void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha)
{
+ if (LLGLSLShader::sNoFixedFunction)
+ { //register combiners do nothing when not using fixed function
+ return;
+ }
+
if (mIndex < 0) return;
activate();
@@ -603,7 +648,7 @@ void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eT
gGL.flush();
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
}
-
+
// We want an early out, because this function does a LOT of stuff.
if ( ( (isAlpha && (mCurrAlphaOp == op) && (mCurrAlphaSrc1 == src1) && (mCurrAlphaSrc2 == src2))
|| (!isAlpha && (mCurrColorOp == op) && (mCurrColorSrc1 == src1) && (mCurrColorSrc2 == src2)) ) && !gGL.mDirty)
@@ -793,14 +838,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;
}
}
@@ -809,7 +856,10 @@ void LLLightState::disable()
{
if (mEnabled)
{
- glDisable(GL_LIGHT0+mIndex);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glDisable(GL_LIGHT0+mIndex);
+ }
mEnabled = false;
}
}
@@ -818,8 +868,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);
+ }
}
}
@@ -827,8 +881,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);
+ }
}
}
@@ -836,16 +894,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)
@@ -853,7 +929,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);
+ }
}
}
@@ -861,8 +941,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);
+ }
}
}
@@ -870,8 +954,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);
+ }
}
}
@@ -879,8 +967,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);
+ }
}
}
@@ -888,31 +980,43 @@ 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)
-{
- mBuffer = new LLVertexBuffer(immediate_mask, 0);
- mBuffer->allocateBuffer(4096, 0, TRUE);
- mBuffer->getVertexStrider(mVerticesp);
- mBuffer->getTexCoord0Strider(mTexcoordsp);
- mBuffer->getColorStrider(mColorsp);
-
+{
mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS);
for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++)
{
@@ -936,6 +1040,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()
@@ -943,6 +1058,18 @@ LLRender::~LLRender()
shutdown();
}
+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()
{
for (U32 i = 0; i < mTexUnits.size(); i++)
@@ -958,6 +1085,7 @@ void LLRender::shutdown()
delete mLightState[i];
}
mLightState.clear();
+ mBuffer = NULL ;
}
void LLRender::refreshState(void)
@@ -980,28 +1108,366 @@ 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;
+}
+
+U32 LLRender::getMatrixMode()
+{
+ if (mMatrixMode >= MM_TEXTURE0 && mMatrixMode <= MM_TEXTURE3)
+ { //always return MM_TEXTURE if current matrix mode points at any texture matrix
+ return MM_TEXTURE;
+ }
+
+ return mMatrixMode;
+}
+
+
+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)
@@ -1147,6 +1613,11 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
{
flush();
+ if (LLGLSLShader::sNoFixedFunction)
+ { //glAlphaFunc is deprecated in OpenGL 3.3
+ return;
+ }
+
if (mCurrAlphaFunc != func ||
mCurrAlphaFuncVal != value)
{
@@ -1161,6 +1632,30 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
glAlphaFunc(sGLCompareFunc[func], value);
}
}
+
+ if (gDebugGL)
+ { //make sure cached state is correct
+ GLint cur_func = 0;
+ glGetIntegerv(GL_ALPHA_TEST_FUNC, &cur_func);
+
+ if (func == CF_DEFAULT)
+ {
+ func = CF_GREATER;
+ }
+
+ if (cur_func != sGLCompareFunc[func])
+ {
+ llerrs << "Alpha test function corrupted!" << llendl;
+ }
+
+ F32 ref = 0.f;
+ glGetFloatv(GL_ALPHA_TEST_REF, &ref);
+
+ if (ref != value)
+ {
+ llerrs << "Alpha test value corrupted!" << llendl;
+ }
+ }
}
void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)
@@ -1228,6 +1723,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)
@@ -1253,6 +1761,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 ||
@@ -1340,7 +1853,7 @@ void LLRender::flush()
if (gDebugGL)
{
- if (mMode == LLRender::QUADS)
+ if (mMode == LLRender::QUADS && !sGLCoreProfile)
{
if (mCount%4 != 0)
{
@@ -1365,12 +1878,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;
}
}
@@ -1378,6 +1913,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;
@@ -1394,10 +1940,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)
@@ -1408,13 +1973,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];
@@ -1428,13 +2030,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];
@@ -1449,13 +2088,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];
@@ -1530,6 +2207,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 41e7b35341..78a310e525 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,10 +50,14 @@ class LLImageGL;
class LLRenderTarget;
class LLTexture ;
+#define LL_MATRIX_STACK_DEPTH 32
+
class LLTexUnit
{
friend class LLRender;
public:
+ static U32 sWhiteTexture;
+
typedef enum
{
TT_TEXTURE = 0, // Standard 2D Texture
@@ -233,6 +239,8 @@ public:
void setSpotDirection(const LLVector3& direction);
protected:
+ friend class LLRender;
+
S32 mIndex;
bool mEnabled;
LLColor4 mDiffuse;
@@ -306,8 +314,21 @@ 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() ;
void shutdown();
// Refreshes renderer state to the cached values
@@ -316,8 +337,22 @@ 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);
+ U32 getMatrixMode();
+
+ 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);
@@ -348,6 +383,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);
@@ -365,7 +406,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; }
@@ -386,9 +428,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;
@@ -416,10 +470,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/llrendernavprim.cpp b/indra/llrender/llrendernavprim.cpp
new file mode 100644
index 0000000000..ca72964832
--- /dev/null
+++ b/indra/llrender/llrendernavprim.cpp
@@ -0,0 +1,59 @@
+/**
+* @file llrendernavprim.cpp
+* @brief Implementation of llrendernavprim
+* @author Prep@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+
+#include "linden_common.h"
+
+#include "llrendernavprim.h"
+
+#include "llrender.h"
+#include "llvertexbuffer.h"
+#include "v4coloru.h"
+#include "v3math.h"
+
+//=============================================================================
+LLRenderNavPrim gRenderNav;
+//=============================================================================
+void LLRenderNavPrim::renderLLTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, const LLColor4U& color ) const
+{
+ LLColor4 cV(color);
+ gGL.color4fv( cV.mV );
+ gGL.begin(LLRender::TRIANGLES);
+ {
+ gGL.vertex3fv( a.mV );
+ gGL.vertex3fv( b.mV );
+ gGL.vertex3fv( c.mV );
+ }
+ gGL.end();
+}
+//=============================================================================
+void LLRenderNavPrim::renderNavMeshVB( U32 mode, LLVertexBuffer* pVBO, int vertCnt )
+{
+ pVBO->setBuffer( LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_NORMAL );
+ pVBO->drawArrays( mode, 0, vertCnt );
+}
+//=============================================================================
diff --git a/indra/llrender/llrendernavprim.h b/indra/llrender/llrendernavprim.h
new file mode 100644
index 0000000000..a3a5dfec3a
--- /dev/null
+++ b/indra/llrender/llrendernavprim.h
@@ -0,0 +1,49 @@
+/**
+* @file llrendernavprim.h
+* @brief Header file for llrendernavprim
+* @author Prep@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+#ifndef LL_LLRENDERNAVPRIM_H
+#define LL_LLRENDERNAVPRIM_H
+
+#include "stdtypes.h"
+
+class LLColor4U;
+class LLVector3;
+class LLVertexBuffer;
+
+
+class LLRenderNavPrim
+{
+public:
+ //Draw simple tri
+ void renderLLTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, const LLColor4U& color ) const;
+ //Draw the contents of vertex buffer
+ void renderNavMeshVB( U32 mode, LLVertexBuffer* pVBO, int vertCnt );
+private:
+};
+
+extern LLRenderNavPrim gRenderNav;
+
+#endif // LL_LLRENDERNAVPRIM_H
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 b6463309e1..cc5c232380 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()
{
@@ -56,14 +55,12 @@ bool LLRenderTarget::sUseFBO = false;
LLRenderTarget::LLRenderTarget() :
mResX(0),
mResY(0),
- mTex(0),
mFBO(0),
mDepth(0),
mStencil(0),
mUseDepth(false),
mRenderDepth(false),
- mUsage(LLTexUnit::TT_TEXTURE),
- mSamples(0)
+ mUsage(LLTexUnit::TT_TEXTURE)
{
}
@@ -72,11 +69,47 @@ LLRenderTarget::~LLRenderTarget()
release();
}
-void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples)
+void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt)
+{
+ //for accounting, get the number of pixels added/subtracted
+ S32 pix_diff = (resx*resy)-(mResX*mResY);
+
+ mResX = resx;
+ mResY = resy;
+
+ for (U32 i = 0; i < mTex.size(); ++i)
+ { //resize color attachments
+ gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
+ sBytesAllocated += pix_diff*4;
+ }
+
+ if (mDepth)
+ { //resize depth attachment
+ if (mStencil)
+ {
+ //use render buffers where stencil buffers are in play
+ glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ }
+ else
+ {
+ gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
+ U32 internal_type = LLTexUnit::getInternalType(mUsage);
+ LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
+ }
+
+ sBytesAllocated += pix_diff*4;
+ }
+}
+
+
+bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples)
{
stop_glerror();
-
release();
+ stop_glerror();
mResX = resx;
mResY = resy;
@@ -84,28 +117,16 @@ void 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)
{
if (depth)
{
- stop_glerror();
- allocateDepth();
- stop_glerror();
+ if (!allocateDepth())
+ {
+ llwarns << "Failed to allocate depth buffer for render target." << llendl;
+ return false;
+ }
}
glGenFramebuffers(1, (GLuint *) &mFBO);
@@ -131,14 +152,14 @@ void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
stop_glerror();
}
- addColorAttachment(color_fmt);
+ return addColorAttachment(color_fmt);
}
-void LLRenderTarget::addColorAttachment(U32 color_fmt)
+bool LLRenderTarget::addColorAttachment(U32 color_fmt)
{
if (color_fmt == 0)
{
- return;
+ return true;
}
U32 offset = mTex.size();
@@ -149,51 +170,48 @@ void LLRenderTarget::addColorAttachment(U32 color_fmt)
}
U32 tex;
- LLImageGL::generateTextures(1, &tex);
+ LLImageGL::generateTextures(mUsage, color_fmt, 1, &tex);
gGL.getTexUnit(0)->bindManual(mUsage, tex);
stop_glerror();
-#ifdef GL_ARB_texture_multisample
- if (mSamples > 1)
- {
- glTexImage2DMultisample(LLTexUnit::getInternalType(mUsage), mSamples, color_fmt, mResX, mResY, GL_TRUE);
- }
- else
-#else
- llassert_always(mSamples <= 1);
-#endif
{
- LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ clear_glerror();
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
+ if (glGetError() != GL_NO_ERROR)
+ {
+ llwarns << "Could not allocate color buffer for render target." << llendl;
+ return false;
+ }
}
+ 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)
@@ -210,6 +228,7 @@ void LLRenderTarget::addColorAttachment(U32 color_fmt)
}
mTex.push_back(tex);
+ mInternalFormat.push_back(color_fmt);
if (gDebugGL)
{ //bind and unbind to validate target
@@ -217,37 +236,42 @@ void LLRenderTarget::addColorAttachment(U32 color_fmt)
flush();
}
+ return true;
}
-void LLRenderTarget::allocateDepth()
+bool LLRenderTarget::allocateDepth()
{
if (mStencil)
{
//use render buffers where stencil buffers are in play
glGenRenderbuffers(1, (GLuint *) &mDepth);
glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
+ stop_glerror();
+ clear_glerror();
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
else
{
- LLImageGL::generateTextures(1, &mDepth);
+ LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth);
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
- if (mSamples == 0)
- {
- U32 internal_type = LLTexUnit::getInternalType(mUsage);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
- }
-#ifdef GL_ARB_texture_multisample
- else
- {
- 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, false);
+ 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;
+ return false;
+ }
+
+ return true;
}
void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
@@ -306,18 +330,20 @@ void LLRenderTarget::release()
}
else
{
- LLImageGL::deleteTextures(1, &mDepth, true);
+ LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true);
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
@@ -335,8 +361,10 @@ void LLRenderTarget::release()
if (mTex.size() > 0)
{
- LLImageGL::deleteTextures(mTex.size(), &mTex[0], true);
+ sBytesAllocated -= mResX*mResY*4*mTex.size();
+ LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true);
mTex.clear();
+ mInternalFormat.clear();
}
mResX = mResY = 0;
@@ -466,7 +494,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 094b58b562..e1a51304f1 100644
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -57,39 +57,44 @@
*/
-class LLMultisampleBuffer;
-
class LLRenderTarget
{
public:
//whether or not to use FBO implementation
static bool sUseFBO;
+ static U32 sBytesAllocated;
LLRenderTarget();
- virtual ~LLRenderTarget();
+ ~LLRenderTarget();
//allocate resources for rendering
//must be called before use
//multiple calls will release previously allocated resources
- void allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = false, S32 samples = 0);
+ bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = false, S32 samples = 0);
+
+ //resize existing attachments to use new resolution and color format
+ // CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined
+ // DO NOT use for screen space buffers or for scratch space for an image that might be uploaded
+ // DO use for render targets that resize often and aren't likely to ruin someone's day if they break
+ void resize(U32 resx, U32 resy, U32 color_fmt);
//add color buffer attachment
//limit of 4 color attachments per render target
- virtual void addColorAttachment(U32 color_fmt);
+ bool addColorAttachment(U32 color_fmt);
//allocate a depth texture
- virtual void allocateDepth();
+ bool allocateDepth();
//share depth buffer with provided render target
- virtual void shareDepthBuffer(LLRenderTarget& target);
+ void shareDepthBuffer(LLRenderTarget& target);
//free any allocated resources
//safe to call redundantly
- virtual void release();
+ void release();
//bind target for rendering
//applies appropriate viewport
- virtual void bindTarget();
+ void bindTarget();
//unbind target for rendering
static void unbindTarget();
@@ -141,13 +146,13 @@ protected:
U32 mResX;
U32 mResY;
std::vector<U32> mTex;
+ std::vector<U32> mInternalFormat;
U32 mFBO;
U32 mDepth;
bool mStencil;
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 751b250d96..b6a9a6b653 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;
}
@@ -206,23 +229,42 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
if (features->hasLighting)
{
-
if (features->hasWaterFog)
{
if (features->disableTextureIndex)
{
- if (!shader->attachObject("lighting/lightWaterNonIndexedF.glsl"))
+ if (features->hasAlphaMask)
{
- return FALSE;
+ if (!shader->attachObject("lighting/lightWaterAlphaMaskNonIndexedF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!shader->attachObject("lighting/lightWaterNonIndexedF.glsl"))
+ {
+ return FALSE;
+ }
}
}
else
{
- if (!shader->attachObject("lighting/lightWaterF.glsl"))
+ if (features->hasAlphaMask)
{
- return FALSE;
+ if (!shader->attachObject("lighting/lightWaterAlphaMaskF.glsl"))
+ {
+ return FALSE;
+ }
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ else
+ {
+ if (!shader->attachObject("lighting/lightWaterF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -230,20 +272,40 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
if (features->disableTextureIndex)
{
- if (!shader->attachObject("lighting/lightNonIndexedF.glsl"))
+ if (features->hasAlphaMask)
{
- return FALSE;
+ if (!shader->attachObject("lighting/lightAlphaMaskNonIndexedF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!shader->attachObject("lighting/lightNonIndexedF.glsl"))
+ {
+ return FALSE;
+ }
}
}
else
{
- if (!shader->attachObject("lighting/lightF.glsl"))
+ if (features->hasAlphaMask)
{
- return FALSE;
+ if (!shader->attachObject("lighting/lightAlphaMaskF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!shader->attachObject("lighting/lightF.glsl"))
+ {
+ 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!!!
@@ -265,25 +327,39 @@ 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)
{
if (features->disableTextureIndex)
{
- if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedF.glsl"))
+ if (features->hasAlphaMask)
+ {
+ if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedF.glsl"))
{
return FALSE;
}
}
else
{
- if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl"))
+ if (features->hasAlphaMask)
+ {
+ if (!shader->attachObject("lighting/lightFullbrightWaterAlphaMaskF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl"))
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -302,7 +378,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -310,18 +386,39 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
if (features->disableTextureIndex)
{
- if (!shader->attachObject("lighting/lightFullbrightNonIndexedF.glsl"))
+
+ if (features->hasAlphaMask)
{
- return FALSE;
+ if (!shader->attachObject("lighting/lightFullbrightNonIndexedAlphaMaskF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!shader->attachObject("lighting/lightFullbrightNonIndexedF.glsl"))
+ {
+ return FALSE;
+ }
}
}
else
{
- if (!shader->attachObject("lighting/lightFullbrightF.glsl"))
+ if (features->hasAlphaMask)
{
- return FALSE;
+ if (!shader->attachObject("lighting/lightFullbrightAlphaMaskF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!shader->attachObject("lighting/lightFullbrightF.glsl"))
+ {
+ return FALSE;
+ }
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
}
@@ -345,7 +442,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -364,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;
}
@@ -403,10 +516,10 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns)
}
else
{
- LL_DEBUGS("ShaderLoading") << log << LL_ENDL;
+ LL_INFOS("ShaderLoading") << log << LL_ENDL;
}
}
-}
+ }
GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels)
{
@@ -457,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
@@ -497,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;
}
*/
@@ -523,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 int vary_texture_index;\n");
+ }
+
text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
text[count++] = strdup("{\n");
@@ -533,49 +714,45 @@ 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");
- 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);
- text[count++] = strdup(case_str.c_str());
+ else if (major_version > 1 || minor_version >= 30)
+ { //switches are supported in GLSL 1.30 and later
+ if (gGLManager.mIsNVIDIA)
+ { //switches are unreliable on some NVIDIA drivers
+ for (U32 i = 0; i < texture_index_channels; ++i)
+ {
+ std::string if_string = llformat("\t%sif (vary_texture_index == %d) { return texture2D(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i);
+ text[count++] = strdup(if_string.c_str());
+ }
+ text[count++] = strdup("\treturn vec4(1,0,1,1);\n");
+ text[count++] = strdup("}\n");
}
+ else
+ {
+ text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n");
+ text[count++] = strdup("\tswitch (vary_texture_index)\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);
+ 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("}\n");
+ text[count++] = strdup("\t}\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);
}
@@ -630,14 +807,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;
}
@@ -686,28 +873,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);
@@ -745,3 +946,187 @@ 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("box_center");
+ mReservedUniforms.push_back("box_size");
+
+
+ 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");
+ mReservedUniforms.push_back("shadow_target_width");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH+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..7a16b7c20f 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -36,9 +36,142 @@ 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,
+ BOX_CENTER,
+ BOX_SIZE,
+
+ 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,
+ DEFERRED_SHADOW_TARGET_WIDTH,
+
+ 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 4a0b964e61..28a14b23b9 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -25,7 +25,6 @@
*/
#include "linden_common.h"
-#include "llmemory.h"
#include <boost/static_assert.hpp>
#include "llsys.h"
@@ -35,36 +34,306 @@
#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;
+}
+
+//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;
+}
+
+
+const U32 LL_VBO_BLOCK_SIZE = 2048;
+const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024;
+
+U32 vbo_block_size(U32 size)
+{ //what block size will fit size?
+ U32 mod = size % LL_VBO_BLOCK_SIZE;
+ return mod == 0 ? size : size + (LL_VBO_BLOCK_SIZE-mod);
+}
+
+U32 vbo_block_index(U32 size)
+{
+ return vbo_block_size(size)/LL_VBO_BLOCK_SIZE;
+}
+
+const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE);
+
//============================================================================
//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;
+U32 LLVBOPool::sIndexBytesPooled = 0;
+U32 LLVBOPool::sCurGLName = 1;
+std::list<U32> LLVertexBuffer::sAvailableVAOName;
+U32 LLVertexBuffer::sCurVAOName = 1;
+
+U32 LLVertexBuffer::sAllocatedIndexBytes = 0;
+U32 LLVertexBuffer::sIndexCount = 0;
+
+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;
+U32 LLVertexBuffer::sVertexCount = 0;
+bool LLVertexBuffer::sMapped = false;
+bool LLVertexBuffer::sUseStreamDraw = true;
+bool LLVertexBuffer::sUseVAO = false;
+bool LLVertexBuffer::sPreferStreamDraw = false;
+
+
+U32 LLVBOPool::genBuffer()
+{
+ U32 ret = 0;
+
+ if (mGLNamePool.empty())
+ {
+ ret = sCurGLName++;
+ }
+ else
+ {
+ ret = mGLNamePool.front();
+ mGLNamePool.pop_front();
+ }
+
+ return ret;
+}
+
+void LLVBOPool::deleteBuffer(U32 name)
+{
+ if (gGLManager.mInited)
+ {
+ LLVertexBuffer::unbind();
+
+ glBindBufferARB(mType, name);
+ glBufferDataARB(mType, 0, NULL, mUsage);
+
+ llassert(std::find(mGLNamePool.begin(), mGLNamePool.end(), name) == mGLNamePool.end());
+
+ mGLNamePool.push_back(name);
+
+ glBindBufferARB(mType, 0);
+ }
+}
+
+
+LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
+: mUsage(vboUsage), mType(vboType)
+{
+ mMissCount.resize(LL_VBO_POOL_SEED_COUNT);
+ std::fill(mMissCount.begin(), mMissCount.end(), 0);
+}
+
+volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
+{
+ llassert(vbo_block_size(size) == size);
+
+ volatile U8* ret = NULL;
-std::vector<U32> LLVertexBuffer::sDeleteList;
+ U32 i = vbo_block_index(size);
+ if (mFreeList.size() <= i)
+ {
+ mFreeList.resize(i+1);
+ }
+
+ if (mFreeList[i].empty() || for_seed)
+ {
+ //make a new buffer
+ name = genBuffer();
+
+ glBindBufferARB(mType, name);
+ if (!for_seed && i < LL_VBO_POOL_SEED_COUNT)
+ { //record this miss
+ mMissCount[i]++;
+ }
+
+ if (mType == GL_ARRAY_BUFFER_ARB)
+ {
+ LLVertexBuffer::sAllocatedBytes += size;
+ }
+ else
+ {
+ LLVertexBuffer::sAllocatedIndexBytes += 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);
+
+ if (for_seed)
+ { //put into pool for future use
+ llassert(mFreeList.size() > i);
+
+ Record rec;
+ rec.mGLName = name;
+ rec.mClientData = ret;
+
+ if (mType == GL_ARRAY_BUFFER_ARB)
+ {
+ sBytesPooled += size;
+ }
+ else
+ {
+ sIndexBytesPooled += size;
+ }
+ mFreeList[i].push_back(rec);
+ }
+ }
+ else
+ {
+ name = mFreeList[i].front().mGLName;
+ ret = mFreeList[i].front().mClientData;
+
+ if (mType == GL_ARRAY_BUFFER_ARB)
+ {
+ sBytesPooled -= size;
+ }
+ else
+ {
+ sIndexBytesPooled -= size;
+ }
+
+ mFreeList[i].pop_front();
+ }
+
+ return ret;
+}
+
+void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
+{
+ llassert(vbo_block_size(size) == size);
+
+ deleteBuffer(name);
+ ll_aligned_free_16((U8*) buffer);
+
+ if (mType == GL_ARRAY_BUFFER_ARB)
+ {
+ LLVertexBuffer::sAllocatedBytes -= size;
+ }
+ else
+ {
+ LLVertexBuffer::sAllocatedIndexBytes -= size;
+ }
+}
+
+void LLVBOPool::seedPool()
+{
+ U32 dummy_name = 0;
+
+ if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT)
+ {
+ mFreeList.resize(LL_VBO_POOL_SEED_COUNT);
+ }
+
+ for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++)
+ {
+ if (mMissCount[i] > mFreeList[i].size())
+ {
+ U32 size = i*LL_VBO_BLOCK_SIZE;
+
+ S32 count = mMissCount[i] - mFreeList[i].size();
+ for (U32 j = 0; j < count; ++j)
+ {
+ allocate(dummy_name, size, true);
+ }
+ }
+ }
+}
+
+
+
+
+void LLVBOPool::cleanup()
+{
+ U32 size = LL_VBO_BLOCK_SIZE;
+
+ for (U32 i = 0; i < mFreeList.size(); ++i)
+ {
+ record_list_t& l = mFreeList[i];
+
+ while (!l.empty())
+ {
+ Record& r = l.front();
+
+ deleteBuffer(r.mGLName);
+
+ if (r.mClientData)
+ {
+ ll_aligned_free_16((void*) r.mClientData);
+ }
+
+ l.pop_front();
+
+ if (mType == GL_ARRAY_BUFFER_ARB)
+ {
+ sBytesPooled -= size;
+ LLVertexBuffer::sAllocatedBytes -= size;
+ }
+ else
+ {
+ sIndexBytesPooled -= size;
+ LLVertexBuffer::sAllocatedIndexBytes -= size;
+ }
+ }
+
+ size += LL_VBO_BLOCK_SIZE;
+ }
+
+ //reset miss counts
+ std::fill(mMissCount.begin(), mMissCount.end(), 0);
+}
+
+
+//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,
@@ -74,10 +343,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] =
@@ -93,145 +364,187 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
};
//static
-void LLVertexBuffer::setupClientArrays(U32 data_mask)
+U32 LLVertexBuffer::getVAOName()
{
- /*if (LLGLImmediate::sStarted)
+ U32 ret = 0;
+
+ if (!sAvailableVAOName.empty())
{
- llerrs << "Cannot use LLGLImmediate and LLVertexBuffer simultaneously!" << llendl;
- }*/
+ ret = sAvailableVAOName.front();
+ sAvailableVAOName.pop_front();
+ }
+ else
+ {
+#ifdef GL_ARB_vertex_array_object
+ glGenVertexArrays(1, &ret);
+#endif
+ }
+
+ return ret;
+}
+
+//static
+void LLVertexBuffer::releaseVAOName(U32 name)
+{
+ sAvailableVAOName.push_back(name);
+}
+
+
+//static
+void LLVertexBuffer::seedPools()
+{
+ sStreamVBOPool.seedPool();
+ sDynamicVBOPool.seedPool();
+ sStreamIBOPool.seedPool();
+ sDynamicIBOPool.seedPool();
+}
+//static
+void LLVertexBuffer::setupClientArrays(U32 data_mask)
+{
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;
}
}
@@ -239,31 +552,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(norm.size() >= pos.size());
+ llassert_always(norm.size() >= pos.size());
+ 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;
}
@@ -278,23 +650,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)
+ {
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
{
- llerrs << "Wrong index buffer bound." << llendl;
+ 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)
@@ -309,25 +724,40 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
idx);
stop_glerror();
+ placeFence();
}
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)
@@ -340,20 +770,35 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
((U16*) getIndicesPointer()) + indices_offset);
stop_glerror();
+ placeFence();
}
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)
{
- llerrs << "Wrong vertex buffer bound." << llendl;
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
+ {
+ if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
}
if (mode >= LLRender::NUM_MODES)
@@ -365,38 +810,43 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
stop_glerror();
glDrawArrays(sGLMode[mode], first, count);
stop_glerror();
+ placeFence();
}
//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 ;
+ if (!sPrivatePoolp)
+ {
+ sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC);
}
-
- sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ;
}
//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;
@@ -410,57 +860,88 @@ void LLVertexBuffer::cleanupClass()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS);
unbind();
- clientCopy(); // deletes GL buffers
+
+ sStreamIBOPool.cleanup();
+ sDynamicIBOPool.cleanup();
+ sStreamVBOPool.cleanup();
+ sDynamicVBOPool.cleanup();
- //llassert_always(!sCount) ;
+ if(sPrivatePoolp)
+ {
+ 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);
- 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++)
@@ -468,11 +949,6 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
mOffsets[i] = 0;
}
- mTypeMask = typemask;
- mSize = 0;
- mAlignedOffset = 0;
- mAlignedIndexOffset = 0;
-
sCount++;
}
@@ -480,12 +956,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;
@@ -494,6 +970,8 @@ S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_verti
}
}
+ offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12;
+
return offset+16;
}
@@ -501,7 +979,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)
@@ -525,46 +1003,84 @@ LLVertexBuffer::~LLVertexBuffer()
LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR);
destroyGLBuffer();
destroyGLIndices();
+
+ if (mGLArray)
+ {
+#if GL_ARB_vertex_array_object
+ releaseVAOName(mGLArray);
+#endif
+ }
+
sCount--;
- llassert_always(!mMappedData && !mMappedIndexData) ;
+ if (mFence)
+ {
+ delete mFence;
+ }
+
+ mFence = NULL;
+
+ sVertexCount -= mNumVerts;
+ sIndexCount -= mNumIndices;
+
+ llassert_always(!mMappedData && !mMappedIndexData);
};
+void LLVertexBuffer::placeFence() const
+{
+ /*if (!mFence && useVBOs())
+ {
+ if (gGLManager.mHasSync)
+ {
+ mFence = new LLGLSyncFence();
+ }
+ }
+
+ if (mFence)
+ {
+ mFence->placeFence();
+ }*/
+}
+
+void LLVertexBuffer::waitFence() const
+{
+ /*if (mFence)
+ {
+ mFence->wait();
+ }*/
+}
+
//----------------------------------------------------------------------------
-void LLVertexBuffer::genBuffer()
+void LLVertexBuffer::genBuffer(U32 size)
{
+ mSize = vbo_block_size(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 = vbo_block_size(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++;
}
@@ -572,16 +1088,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--;
}
@@ -589,24 +1105,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();
@@ -617,27 +1132,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*) ll_aligned_malloc_16(size);
+ 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();
@@ -648,24 +1163,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*) ll_aligned_malloc_16(size);
+ mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
static int gl_buffer_idx = 0;
mGLIndices = ++gl_buffer_idx;
+ mIndicesSize = size;
}
}
@@ -674,24 +1190,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
{
- ll_aligned_free_16(mMappedData);
+ FREE_MEM(sPrivatePoolp, (void*) mMappedData);
mMappedData = NULL;
- mEmpty = TRUE;
+ mEmpty = true;
}
-
- sAllocatedBytes -= getSize();
}
mGLBuffer = 0;
@@ -703,24 +1211,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
{
- ll_aligned_free_16(mMappedIndexData);
+ FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData);
mMappedIndexData = NULL;
- mEmpty = TRUE;
+ mEmpty = true;
}
-
- sAllocatedBytes -= getIndicesSize();
}
mGLIndices = 0;
@@ -733,29 +1233,22 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
llassert(nverts >= 0);
- if (nverts >= 65535)
+ if (nverts > 65536)
{
llwarns << "Vertex buffer overflow!" << llendl;
- nverts = 65535;
+ nverts = 65536;
}
- mRequestedNumVerts = nverts;
+ U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
- if (!mDynamicSize)
- {
- mNumVerts = nverts;
- }
- else if (mUsage == GL_STATIC_DRAW_ARB ||
- nverts > mNumVerts ||
- nverts < mNumVerts/2)
+ if (needed_size > mSize || needed_size <= mSize/2)
{
- if (mUsage != GL_STATIC_DRAW_ARB && nverts + nverts/4 <= 65535)
- {
- nverts += nverts/4;
- }
- mNumVerts = nverts;
+ createGLBuffer(needed_size);
}
- mSize = calcOffsets(mTypeMask, mOffsets, mNumVerts);
+
+ sVertexCount -= mNumVerts;
+ mNumVerts = nverts;
+ sVertexCount += mNumVerts;
}
void LLVertexBuffer::updateNumIndices(S32 nindices)
@@ -764,28 +1257,24 @@ 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;
- }
+ sIndexCount -= mNumIndices;
+ mNumIndices = nindices;
+ sIndexCount += mNumIndices;
}
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)
{
@@ -795,145 +1284,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
+ mGLArray = getVAOName();
+#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,
+ 1, //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_INT, //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)
{
- ll_aligned_free_16(mMappedData);
- mMappedData = (U8*) ll_aligned_malloc_16(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())
- {
- ll_aligned_free_16(mMappedIndexData);
- mMappedIndexData = (U8*) ll_aligned_malloc_16(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 LL_DARWIN
- if (!mUsage || mUsage == GL_STREAM_DRAW_ARB)
- {
- return FALSE;
- }
-#else
- if (!mUsage)
- {
- return FALSE;
- }
-#endif
- return TRUE;
+ unbind();
}
-//----------------------------------------------------------------------------
-void LLVertexBuffer::freeClientBuffer()
+void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
{
- if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData))
- {
- ll_aligned_free_16(mMappedData) ;
- ll_aligned_free_16(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*)ll_aligned_malloc_16(getSize());
+ flush();
+
+ if (mGLArray)
+ { //if size changed, offsets changed
+ setupVertexArray();
+ }
}
}
-void LLVertexBuffer::allocateClientIndexBuffer()
+bool LLVertexBuffer::useVBOs() const
{
- if(!mMappedIndexData)
- {
- mMappedIndexData = (U8*)ll_aligned_malloc_16(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;
@@ -952,9 +1465,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)
{
@@ -967,8 +1484,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
if (useVBOs())
{
-
- if (sDisableVBOMapping || gGLManager.mHasMapBufferRange)
+ if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
{
if (count == -1)
{
@@ -993,7 +1509,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);
}
}
@@ -1006,42 +1522,76 @@ 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;
-#ifdef GL_ARB_map_buffer_range
+ 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, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
+ src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length,
+ GL_MAP_WRITE_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT |
+ GL_MAP_INVALIDATE_RANGE_BIT);
+#endif
}
else
{
- src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
+#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);
+#endif
+ }
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+ if (map_range)
+ {
+ glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
+ glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
+ src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+ else
+ {
+ src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
}
else
-#else
- llassert_always(!gGLManager.mHasMapBufferRange);
-#endif
{
map_range = false;
src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
- mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
+ llassert(src != NULL);
+
+ mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src);
mAlignedOffset = mMappedData - src;
stop_glerror();
@@ -1052,19 +1602,16 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
log_glerror();
//check the availability of memory
- U32 avail_phy_mem, avail_vir_mem;
- LLMemoryInfo::getAvailableMemoryKB(avail_phy_mem, avail_vir_mem) ;
- llinfos << "Available physical mwmory(KB): " << avail_phy_mem << llendl ;
- llinfos << "Available virtual memory(KB): " << avail_vir_mem << llendl;
-
- if(!sDisableVBOMapping)
+ LLMemory::logMemoryInfo(true);
+
+ 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;
@@ -1079,10 +1626,9 @@ 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;
}
}
- sMappedCount++;
}
}
else
@@ -1090,7 +1636,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
map_range = false;
}
- if (map_range && !sDisableVBOMapping)
+ if (map_range && gGLManager.mHasMapBufferRange && mMappable)
{
return mMappedData;
}
@@ -1100,9 +1646,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;
@@ -1114,7 +1665,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
if (useVBOs())
{
- if (sDisableVBOMapping || gGLManager.mHasMapBufferRange)
+ if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
{
if (count == -1)
{
@@ -1136,7 +1687,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);
}
}
@@ -1150,41 +1701,76 @@ 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;
-#ifdef GL_ARB_map_buffer_range
+ 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, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
+ src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length,
+ GL_MAP_WRITE_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT |
+ GL_MAP_INVALIDATE_RANGE_BIT);
+#endif
}
else
{
- src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
+#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);
+#endif
+ }
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+ if (map_range)
+ {
+ glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
+ glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
+ src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+ else
+ {
+ src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
}
else
-#else
- llassert_always(!gGLManager.mHasMapBufferRange);
-#endif
{
+ LLFastTimer t(FTM_VBO_MAP_INDEX);
map_range = false;
src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
+ llassert(src != NULL);
+
+
mMappedIndexData = src; //LL_NEXT_ALIGNED_ADDRESS<U8>(src);
mAlignedIndexOffset = mMappedIndexData - src;
stop_glerror();
@@ -1194,8 +1780,9 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
if (!mMappedIndexData)
{
log_glerror();
+ LLMemory::logMemoryInfo(true);
- if(!sDisableVBOMapping)
+ if(mMappable)
{
GLint buff;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
@@ -1208,18 +1795,16 @@ 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;
}
}
-
- sMappedCount++;
}
else
{
map_range = false;
}
- if (map_range && !sDisableVBOMapping)
+ if (map_range && gGLManager.mHasMapBufferRange && mMappable)
{
return mMappedIndexData;
}
@@ -1229,21 +1814,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())
{
@@ -1253,7 +1847,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();
}
@@ -1262,14 +1856,13 @@ 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();
}
}
else
{
-#ifdef GL_ARB_map_buffer_range
- if (gGLManager.mHasMapBufferRange)
+ if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
{
if (!mMappedVertexRegions.empty())
{
@@ -1279,16 +1872,23 @@ 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;
- glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
+ if (gGLManager.mHasMapBufferRange)
+ {
+ LLFastTimer t(FTM_VBO_FLUSH_RANGE);
+#ifdef GL_ARB_map_buffer_range
+ glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
+#endif
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+ glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length);
+ }
stop_glerror();
}
mMappedVertexRegions.clear();
}
}
-#else
- llassert_always(!gGLManager.mHasMapBufferRange);
-#endif
stop_glerror();
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
stop_glerror();
@@ -1296,13 +1896,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())
{
@@ -1311,7 +1913,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();
}
@@ -1320,14 +1922,13 @@ 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();
}
}
else
{
-#ifdef GL_ARB_map_buffer_range
- if (gGLManager.mHasMapBufferRange)
+ if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
{
if (!mMappedIndexRegions.empty())
{
@@ -1336,44 +1937,39 @@ 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;
- glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
+ if (gGLManager.mHasMapBufferRange)
+ {
+ LLFastTimer t(FTM_IBO_FLUSH_RANGE);
+#ifdef GL_ARB_map_buffer_range
+ glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
+#endif
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+#ifdef GL_APPLE_flush_buffer_range
+ glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
+#endif
+ }
stop_glerror();
}
mMappedIndexRegions.clear();
}
}
-#else
- llassert_always(!gGLManager.mHasMapBufferRange);
-#endif
stop_glerror();
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;
}
}
@@ -1388,39 +1984,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;
}
};
@@ -1428,6 +2024,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);
@@ -1453,6 +2053,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);
@@ -1470,43 +2074,157 @@ 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();
+ }
+}
+
+// bind for transform feedback (quick 'n dirty)
+void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count)
+{
+#ifdef GL_TRANSFORM_FEEDBACK_BUFFER
+ U32 offset = mOffsets[type] + sTypeSize[type]*index;
+ U32 size= (sTypeSize[type]*count);
+ glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size);
+#endif
+}
+
// 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);
@@ -1514,7 +2232,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
@@ -1530,7 +2248,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
@@ -1541,116 +2259,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)
@@ -1660,80 +2317,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 (gDebugGL && ((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, 1, GL_UNSIGNED_INT, 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 aa5df305a6..11fa4ab6a0 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,31 +51,53 @@
//============================================================================
// 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;
+ static U32 sIndexBytesPooled;
+
+ static U32 sCurGLName;
+
+ LLVBOPool(U32 vboUsage, U32 vboType);
+
+ const U32 mUsage;
+ const U32 mType;
+
+ //size MUST be a power of 2
+ volatile U8* allocate(U32& name, U32 size, bool for_seed = false);
+
+ //size MUST be the size provided to allocate that returned the given name
+ void release(U32 name, volatile U8* buffer, U32 size);
+
+ //batch allocate buffers to be provided to the application on demand
+ void seedPool();
+
+ //destroy all records in mFreeList
+ void cleanup();
+
+ U32 genBuffer();
+ void deleteBuffer(U32 name);
- virtual void releaseName(GLuint name)
+ class Record
{
- stop_glerror();
- glDeleteBuffersARB(1, &name);
- stop_glerror();
- }
+ public:
+ U32 mGLName;
+ volatile U8* mClientData;
+ };
+
+ std::list<U32> mGLNamePool;
+
+ typedef std::list<Record> record_list_t;
+ std::vector<record_list_t> mFreeList;
+ std::vector<U32> mMissCount;
+
};
//============================================================================
// base class
-
+class LLPrivateMemoryPool;
class LLVertexBuffer : public LLRefCount
{
public:
@@ -84,12 +108,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;
}
@@ -105,18 +128,26 @@ public:
static LLVBOPool sStreamIBOPool;
static LLVBOPool sDynamicIBOPool;
- static S32 sWeight4Loc;
+ static std::list<U32> sAvailableVAOName;
+ static U32 sCurVAOName;
+
+ static bool sUseStreamDraw;
+ static bool sUseVAO;
+ static bool sPreferStreamDraw;
- static BOOL sUseStreamDraw;
- static BOOL sPreferStreamDraw;
+ static void seedPools();
+
+ static U32 getVAOName();
+ static void releaseVAOName(U32 name);
static void initClass(bool use_vbo, bool no_vbo_mapping);
static void cleanupClass();
static void setupClientArrays(U32 data_mask);
+ static void pushPositions(U32 mode, const LLVector4a* pos, U32 count);
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);
@@ -127,24 +158,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),
@@ -154,6 +190,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),
@@ -167,33 +204,36 @@ 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() ;
-
+ 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);
+
+ void bindForFeedback(U32 channel, U32 type, U32 index, U32 count);
// 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);
@@ -206,33 +246,37 @@ 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 getTextureIndexStrider(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 useVBOs() const;
+ 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;
@@ -246,48 +290,67 @@ 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;
std::vector<MappedRegion> mMappedIndexRegions;
+ mutable LLGLFence* mFence;
+
+ void placeFence() const;
+ void waitFence() const;
+
+ static S32 determineUsage(S32 usage);
+
+private:
+ 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 sAllocatedIndexBytes;
+ static U32 sVertexCount;
+ static U32 sIndexCount;
static U32 sBindCount;
static U32 sSetCount;
};