summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
authorBrad Kittenbrink <brad@lindenlab.com>2008-02-27 18:58:14 +0000
committerBrad Kittenbrink <brad@lindenlab.com>2008-02-27 18:58:14 +0000
commit6d52efe452aa8469e0343da1c7d108f3f52ab651 (patch)
treea87be48e9840d7fc1f7ee514d7c7f994e71fdb3c /indra/llrender
parent6027ad2630b8650cabcf00628ee9b0d25bedd67f (diff)
Merge of windlight into release (QAR-286). This includes all changes in
windlight14 which have passed QA (up through r79932). svn merge -r 80831:80833 svn+ssh://svn.lindenlab.com/svn/linden/branches/merge_windlight14_r80620
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/llfontgl.cpp73
-rw-r--r--indra/llrender/llimagegl.cpp16
-rw-r--r--indra/llrender/llimagegl.h3
-rw-r--r--indra/llrender/llrendertarget.cpp185
-rw-r--r--indra/llrender/llrendertarget.h116
-rw-r--r--indra/llrender/llvertexbuffer.cpp538
-rw-r--r--indra/llrender/llvertexbuffer.h67
7 files changed, 683 insertions, 315 deletions
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index dd67dbc379..2e767ebb9c 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -36,6 +36,7 @@
#include "llfont.h"
#include "llfontgl.h"
#include "llgl.h"
+#include "llglimmediate.h"
#include "v4color.h"
#include "llstl.h"
@@ -556,8 +557,8 @@ S32 LLFontGL::render(const LLWString &wstr,
BOOL use_embedded,
BOOL use_ellipses) const
{
- LLGLEnable texture_2d(GL_TEXTURE_2D);
-
+ LLGLEnable tex(GL_TEXTURE_2D);
+
if (wstr.empty())
{
return 0;
@@ -593,9 +594,9 @@ S32 LLFontGL::render(const LLWString &wstr,
}
}
- glPushMatrix();
+ gGL.pushMatrix();
glLoadIdentity();
- glTranslatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
+ gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
//glScalef(sScaleX, sScaleY, 1.0f);
// avoid half pixels
@@ -604,20 +605,20 @@ S32 LLFontGL::render(const LLWString &wstr,
//F32 half_pixel_distance = llabs(fmodf(sCurOrigin.mX * sScaleX, 1.f) - 0.5f);
//if (half_pixel_distance < PIXEL_BORDER_THRESHOLD)
//{
- glTranslatef(PIXEL_CORRECTION_DISTANCE*sScaleX, 0.f, 0.f);
+ gGL.translatef(PIXEL_CORRECTION_DISTANCE*sScaleX, 0.f, 0.f);
//}
// this code would just snap to pixel grid, although it seems to introduce more jitter
//F32 pixel_offset_x = llround(sCurOrigin.mX * sScaleX) - (sCurOrigin.mX * sScaleX);
//F32 pixel_offset_y = llround(sCurOrigin.mY * sScaleY) - (sCurOrigin.mY * sScaleY);
- //glTranslatef(-pixel_offset_x, -pixel_offset_y, 0.f);
+ //gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f);
// scale back to native pixel size
//glScalef(1.f / sScaleX, 1.f / sScaleY, 1.f);
//glScaled(1.0 / (F64) sScaleX, 1.0 / (F64) sScaleY, 1.0f);
LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS);
- glColor4fv( color.mV );
+ gGL.color4fv( color.mV );
S32 chars_drawn = 0;
S32 i;
@@ -638,7 +639,7 @@ S32 LLFontGL::render(const LLWString &wstr,
mImageGLp->bind(0);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Not guaranteed to be set correctly
+ gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Not guaranteed to be set correctly
cur_x = ((F32)x * sScaleX);
cur_y = ((F32)y * sScaleY);
@@ -743,9 +744,9 @@ S32 LLFontGL::render(const LLWString &wstr,
if (!label.empty())
{
- glPushMatrix();
+ gGL.pushMatrix();
//glLoadIdentity();
- //glTranslatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
+ //gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
//glScalef(sScaleX, sScaleY, 1.f);
gExtCharFont->render(label, 0,
/*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX),
@@ -753,10 +754,10 @@ S32 LLFontGL::render(const LLWString &wstr,
color,
halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL,
TRUE );
- glPopMatrix();
+ gGL.popMatrix();
}
- glColor4fv(color.mV);
+ gGL.color4fv(color.mV);
chars_drawn++;
cur_x += ext_advance;
@@ -836,10 +837,10 @@ S32 LLFontGL::render(const LLWString &wstr,
if (style & UNDERLINE)
{
LLGLSNoTexture no_texture;
- glBegin(GL_LINES);
- glVertex2f(start_x, cur_y - (mDescender));
- glVertex2f(cur_x, cur_y - (mDescender));
- glEnd();
+ gGL.begin(GL_LINES);
+ gGL.vertex2f(start_x, cur_y - (mDescender));
+ gGL.vertex2f(cur_x, cur_y - (mDescender));
+ gGL.end();
}
// *FIX: get this working in all alignment cases, etc.
@@ -847,9 +848,9 @@ S32 LLFontGL::render(const LLWString &wstr,
{
// recursively render ellipses at end of string
// we've already reserved enough room
- glPushMatrix();
+ gGL.pushMatrix();
//glLoadIdentity();
- //glTranslatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
+ //gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
//glScalef(sScaleX, sScaleY, 1.f);
renderUTF8("...",
0,
@@ -860,10 +861,10 @@ S32 LLFontGL::render(const LLWString &wstr,
S32_MAX, max_pixels,
right_x,
FALSE);
- glPopMatrix();
+ gGL.popMatrix();
}
- glPopMatrix();
+ gGL.popMatrix();
return chars_drawn;
}
@@ -1309,20 +1310,20 @@ void LLFontGL::removeEmbeddedChar( llwchar wc )
void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const
{
- glTexCoord2f(uv_rect.mRight, uv_rect.mTop);
- glVertex2f(llfont_round_x(screen_rect.mRight),
+ gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
+ gGL.vertex2f(llfont_round_x(screen_rect.mRight),
llfont_round_y(screen_rect.mTop));
- glTexCoord2f(uv_rect.mLeft, uv_rect.mTop);
- glVertex2f(llfont_round_x(screen_rect.mLeft),
+ gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
+ gGL.vertex2f(llfont_round_x(screen_rect.mLeft),
llfont_round_y(screen_rect.mTop));
- glTexCoord2f(uv_rect.mLeft, uv_rect.mBottom);
- glVertex2f(llfont_round_x(screen_rect.mLeft + slant_amt),
+ gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
+ gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt),
llfont_round_y(screen_rect.mBottom));
- glTexCoord2f(uv_rect.mRight, uv_rect.mBottom);
- glVertex2f(llfont_round_x(screen_rect.mRight + slant_amt),
+ gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
+ gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt),
llfont_round_y(screen_rect.mBottom));
}
@@ -1331,13 +1332,13 @@ void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, con
F32 slant_offset;
slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f);
- glBegin(GL_QUADS);
+ gGL.begin(GL_QUADS);
{
//FIXME: bold and drop shadow are mutually exclusive only for convenience
//Allow both when we need them.
if (style & BOLD)
{
- glColor4fv(color.mV);
+ gGL.color4fv(color.mV);
for (S32 pass = 0; pass < 2; pass++)
{
LLRectf screen_rect_offset = screen_rect;
@@ -1350,7 +1351,7 @@ void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, con
{
LLColor4 shadow_color = LLFontGL::sShadowColor;
shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH;
- glColor4fv(shadow_color.mV);
+ gGL.color4fv(shadow_color.mV);
for (S32 pass = 0; pass < 5; pass++)
{
LLRectf screen_rect_offset = screen_rect;
@@ -1376,28 +1377,28 @@ void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, con
renderQuad(screen_rect_offset, uv_rect, slant_offset);
}
- glColor4fv(color.mV);
+ gGL.color4fv(color.mV);
renderQuad(screen_rect, uv_rect, slant_offset);
}
else if (style & DROP_SHADOW)
{
LLColor4 shadow_color = LLFontGL::sShadowColor;
shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength;
- glColor4fv(shadow_color.mV);
+ gGL.color4fv(shadow_color.mV);
LLRectf screen_rect_shadow = screen_rect;
screen_rect_shadow.translate(1.f, -1.f);
renderQuad(screen_rect_shadow, uv_rect, slant_offset);
- glColor4fv(color.mV);
+ gGL.color4fv(color.mV);
renderQuad(screen_rect, uv_rect, slant_offset);
}
else // normal rendering
{
- glColor4fv(color.mV);
+ gGL.color4fv(color.mV);
renderQuad(screen_rect, uv_rect, slant_offset);
}
}
- glEnd();
+ gGL.end();
}
// static
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 748e405065..2a8424a09b 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -41,6 +41,8 @@
#include "llmath.h"
#include "llgl.h"
+#include "llglimmediate.h"
+
//----------------------------------------------------------------------------
@@ -49,6 +51,8 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f;
//statics
LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 };
+U32 LLImageGL::sUniqueCount = 0;
+U32 LLImageGL::sBindCount = 0;
S32 LLImageGL::sGlobalTextureMemory = 0;
S32 LLImageGL::sBoundTextureMemory = 0;
S32 LLImageGL::sCurBoundTextureMemory = 0;
@@ -123,6 +127,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
// static
void LLImageGL::bindExternalTexture(LLGLuint gl_name, S32 stage, LLGLenum bind_target )
{
+ gGL.flush();
glActiveTextureARB(GL_TEXTURE0_ARB + stage);
glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
glBindTexture(bind_target, gl_name);
@@ -135,6 +140,7 @@ void LLImageGL::unbindTexture(S32 stage, LLGLenum bind_target)
// LLGLSLShader can return -1
if (stage >= 0)
{
+ gGL.flush();
glActiveTextureARB(GL_TEXTURE0_ARB + stage);
glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
glBindTexture(bind_target, 0);
@@ -148,6 +154,7 @@ void LLImageGL::unbindTexture(S32 stage)
// LLGLSLShader can return -1
if (stage >= 0)
{
+ gGL.flush();
glActiveTextureARB(GL_TEXTURE0_ARB + stage);
glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
glBindTexture(GL_TEXTURE_2D, 0);
@@ -411,6 +418,7 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const
llwarns << "Trying to bind a texture while GL is disabled!" << llendl;
}
+
glActiveTextureARB(GL_TEXTURE0_ARB + stage);
if (sCurrentBoundTextures[stage] && sCurrentBoundTextures[stage] == mTexName)
@@ -425,12 +433,15 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const
mMissed = ! getIsResident(TRUE);
#endif
+ gGL.flush();
glBindTexture(mBindTarget, mTexName);
sCurrentBoundTextures[stage] = mTexName;
+ sBindCount++;
if (mLastBindTime != sLastFrameTime)
{
// we haven't accounted for this texture yet this frame
+ sUniqueCount++;
updateBoundTexMem(mTextureMemory);
mLastBindTime = sLastFrameTime;
}
@@ -439,6 +450,7 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const
}
else
{
+ gGL.flush();
glBindTexture(mBindTarget, 0);
sCurrentBoundTextures[stage] = 0;
return FALSE;
@@ -665,7 +677,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
}
mHasMipMaps = FALSE;
}
- glFlush();
stop_glerror();
}
@@ -759,7 +770,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
stop_glerror();
}
- glFlush();
+
return TRUE;
}
@@ -1046,6 +1057,7 @@ void LLImageGL::destroyGLTexture()
{
unbindTexture(i, GL_TEXTURE_2D);
stop_glerror();
+ glActiveTextureARB(GL_TEXTURE0_ARB);
}
}
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index cbfa3c2202..20cf4ae10f 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -185,7 +185,8 @@ public:
static S32 sGlobalTextureMemory; // Tracks main memory texmem
static S32 sBoundTextureMemory; // Tracks bound texmem for last completed frame
static S32 sCurBoundTextureMemory; // Tracks bound texmem for current frame
-
+ static U32 sBindCount; // Tracks number of texture binds for current frame
+ static U32 sUniqueCount; // Tracks number of unique texture binds for current frame
static BOOL sGlobalUseAnisotropic;
#if DEBUG_MISS
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
new file mode 100644
index 0000000000..c082b93164
--- /dev/null
+++ b/indra/llrender/llrendertarget.cpp
@@ -0,0 +1,185 @@
+/**
+ * @file llrendertarget.cpp
+ * @brief LLRenderTarget implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llrendertarget.h"
+#include "llglimmediate.h"
+
+
+BOOL LLRenderTarget::sUseFBO = FALSE;
+
+LLRenderTarget::LLRenderTarget()
+{
+ mResX = mResY = mTex = mFBO = mDepth = 0;
+ mUseDepth = FALSE;
+ mUsage = GL_TEXTURE_2D;
+}
+
+LLRenderTarget::~LLRenderTarget()
+{
+ release();
+}
+
+void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, U32 usage, BOOL force_fbo)
+{
+ mResX = resx;
+ mResY = resy;
+
+ mUsage = usage;
+ mUseDepth = depth;
+ release();
+
+ glGenTextures(1, (GLuint *) &mTex);
+ glBindTexture(mUsage, mTex);
+ glTexImage2D(mUsage, 0, color_fmt, mResX, mResY, 0, color_fmt, GL_UNSIGNED_BYTE, NULL);
+
+ glTexParameteri(mUsage, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(mUsage, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ if (mUsage != GL_TEXTURE_RECTANGLE_ARB)
+ {
+ glTexParameteri(mUsage, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+ glTexParameteri(mUsage, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+ }
+ else
+ {
+ // ATI doesn't support mirrored repeat for rectangular textures.
+ glTexParameteri(mUsage, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(mUsage, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+
+ stop_glerror();
+
+ if (sUseFBO || force_fbo)
+ {
+ if (depth)
+ {
+ glGenRenderbuffersEXT(1, (GLuint *) &mDepth);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT,mResX,mResY);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+ }
+
+ glGenFramebuffersEXT(1, (GLuint *) &mFBO);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+
+ if (mDepth)
+ {
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, mDepth);
+ }
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ mUsage, mTex, 0);
+
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ }
+}
+
+void LLRenderTarget::release()
+{
+ if (mFBO)
+ {
+ glDeleteFramebuffersEXT(1, (GLuint *) &mFBO);
+ mFBO = 0;
+ }
+
+ if (mTex)
+ {
+ glDeleteTextures(1, (GLuint *) &mTex);
+ mTex = 0;
+ }
+
+ if (mDepth)
+ {
+ glDeleteRenderbuffersEXT(1, (GLuint *) &mDepth);
+ mDepth = 0;
+ }
+}
+
+void LLRenderTarget::bindTarget()
+{
+ if (mFBO)
+ {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+ }
+
+ glViewport(0, 0, mResX, mResY);
+}
+
+void LLRenderTarget::clear()
+{
+ U32 mask = GL_COLOR_BUFFER_BIT;
+ if (mUseDepth)
+ {
+ mask |= GL_DEPTH_BUFFER_BIT;
+ }
+ if (mFBO)
+ {
+ glClear(mask);
+ }
+ else
+ {
+ LLGLEnable scissor(GL_SCISSOR_TEST);
+ glScissor(0, 0, mResX, mResY);
+ glClear(mask);
+ }
+}
+
+void LLRenderTarget::bindTexture()
+{
+ glBindTexture(mUsage, mTex);
+}
+
+void LLRenderTarget::flush()
+{
+ gGL.flush();
+ if (!mFBO)
+ {
+ bindTexture();
+ glCopyTexSubImage2D(mUsage, 0, 0, 0, 0, 0, mResX, mResY);
+ }
+}
+
+BOOL LLRenderTarget::isComplete() const
+{
+ return (mTex || mDepth) ? TRUE : FALSE;
+}
+
+void LLRenderTarget::getViewport(S32* viewport)
+{
+ viewport[0] = 0;
+ viewport[1] = 0;
+ viewport[2] = mResX;
+ viewport[3] = mResY;
+}
+
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
new file mode 100644
index 0000000000..0c0eab2b10
--- /dev/null
+++ b/indra/llrender/llrendertarget.h
@@ -0,0 +1,116 @@
+/**
+ * @file llrendertarget.h
+ * @brief Off screen render target abstraction. Loose wrapper for GL_EXT_framebuffer_objects.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLRENDERTARGET_H
+#define LL_LLRENDERTARGET_H
+
+#include "llgl.h"
+
+/*
+ SAMPLE USAGE:
+
+ LLFBOTarget target;
+
+ ...
+
+ //allocate a 256x256 RGBA render target with depth buffer
+ target.allocate(256,256,GL_RGBA,TRUE);
+
+ //render to contents of offscreen buffer
+ target.bindTarget();
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ ... <issue drawing commands> ...
+ target.flush();
+
+ ...
+
+ //use target as a texture
+ target.bindTexture();
+ ... <issue drawing commands> ...
+
+*/
+
+
+class LLRenderTarget
+{
+public:
+ //whether or not to use FBO implementation
+ static BOOL sUseFBO;
+
+ 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, U32 usage = GL_TEXTURE_2D, BOOL force_fbo = FALSE);
+
+ //free any allocated resources
+ //safe to call redundantly
+ void release();
+
+ //bind target for rendering
+ //applies appropriate viewport
+ void bindTarget();
+
+ //clear render targer, clears depth buffer if present,
+ //uses scissor rect if in copy-to-texture mode
+ void clear();
+
+ //get applied viewport
+ void getViewport(S32* viewport);
+
+ //bind results of render for sampling
+ void bindTexture();
+
+ //flush rendering operations
+ //must be called when rendering is complete
+ //should be used 1:1 with bindTarget
+ // call bindTarget once, do all your rendering, call flush once
+ void flush();
+
+ //Returns TRUE if target is ready to be rendered into.
+ //That is, if the target has been allocated with at least
+ //one renderable attachment (i.e. color buffer, depth buffer).
+ BOOL isComplete() const;
+
+private:
+ U32 mResX;
+ U32 mResY;
+ U32 mTex;
+ U32 mFBO;
+ U32 mDepth;
+ BOOL mUseDepth;
+ U32 mUsage;
+};
+
+#endif
+
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 2a54fca250..9303e00228 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -31,6 +31,8 @@
#include "linden_common.h"
+#include <boost/static_assert.hpp>
+
#include "llvertexbuffer.h"
// #include "llrender.h"
#include "llglheaders.h"
@@ -40,8 +42,16 @@
//============================================================================
//static
+LLVBOPool LLVertexBuffer::sStreamVBOPool;
+LLVBOPool LLVertexBuffer::sDynamicVBOPool;
+LLVBOPool LLVertexBuffer::sStreamIBOPool;
+LLVBOPool LLVertexBuffer::sDynamicIBOPool;
+
+U32 LLVertexBuffer::sBindCount = 0;
+U32 LLVertexBuffer::sSetCount = 0;
S32 LLVertexBuffer::sCount = 0;
S32 LLVertexBuffer::sGLCount = 0;
+S32 LLVertexBuffer::sMappedCount = 0;
BOOL LLVertexBuffer::sEnableVBOs = TRUE;
U32 LLVertexBuffer::sGLRenderBuffer = 0;
U32 LLVertexBuffer::sGLRenderIndices = 0;
@@ -50,9 +60,9 @@ BOOL LLVertexBuffer::sVBOActive = FALSE;
BOOL LLVertexBuffer::sIBOActive = FALSE;
U32 LLVertexBuffer::sAllocatedBytes = 0;
BOOL LLVertexBuffer::sRenderActive = FALSE;
+BOOL LLVertexBuffer::sMapped = FALSE;
std::vector<U32> LLVertexBuffer::sDeleteList;
-LLVertexBuffer::buffer_list_t LLVertexBuffer::sLockedList;
S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
{
@@ -70,6 +80,10 @@ S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
void LLVertexBuffer::initClass(bool use_vbo)
{
sEnableVBOs = use_vbo;
+ LLGLNamePool::registerPool(&sDynamicVBOPool);
+ LLGLNamePool::registerPool(&sDynamicIBOPool);
+ LLGLNamePool::registerPool(&sStreamVBOPool);
+ LLGLNamePool::registerPool(&sStreamIBOPool);
}
//static
@@ -88,13 +102,13 @@ void LLVertexBuffer::unbind()
sGLRenderBuffer = 0;
sGLRenderIndices = 0;
+ sLastMask = 0;
}
//static
void LLVertexBuffer::cleanupClass()
{
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
- sLockedList.clear();
startRender();
stopRender();
clientCopy(); // deletes GL buffers
@@ -127,41 +141,8 @@ void LLVertexBuffer::clientCopy(F64 max_time)
{
if (!sDeleteList.empty())
{
- size_t num = sDeleteList.size();
glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0]));
sDeleteList.clear();
- sGLCount -= num;
- }
-
- if (sEnableVBOs)
- {
- LLTimer timer;
- BOOL reset = TRUE;
- buffer_list_t::iterator iter = sLockedList.begin();
- while(iter != sLockedList.end())
- {
- LLVertexBuffer* buffer = *iter;
- if (buffer->isLocked() && buffer->useVBOs())
- {
- buffer->setBuffer(0);
- }
- ++iter;
- if (reset)
- {
- reset = FALSE;
- timer.reset(); //skip first copy (don't count pipeline stall)
- }
- else
- {
- if (timer.getElapsedTimeF64() > max_time)
- {
- break;
- }
- }
-
- }
-
- sLockedList.erase(sLockedList.begin(), iter);
}
}
@@ -175,27 +156,40 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
mFinal(FALSE),
mFilthy(FALSE),
mEmpty(TRUE),
- mResized(FALSE)
+ mResized(FALSE),
+ mDynamicSize(FALSE)
{
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
if (!sEnableVBOs)
{
- mUsage = GL_STREAM_DRAW_ARB;
+ mUsage = 0 ;
}
+ S32 stride = calcStride(typemask, mOffsets);
+
+ mTypeMask = typemask;
+ mStride = stride;
+ sCount++;
+}
+
+//static
+S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets)
+{
S32 stride = 0;
for (S32 i=0; i<TYPE_MAX; i++)
{
U32 mask = 1<<i;
if (typemask & mask)
{
- mOffsets[i] = stride;
+ if (offsets)
+ {
+ offsets[i] = stride;
+ }
stride += sTypeOffsets[i];
}
}
- mTypeMask = typemask;
- mStride = stride;
- sCount++;
+
+ return stride;
}
// protected, use unref()
@@ -206,23 +200,80 @@ LLVertexBuffer::~LLVertexBuffer()
destroyGLBuffer();
destroyGLIndices();
sCount--;
-
- if (mLocked)
- {
- //pull off of locked list
- for (buffer_list_t::iterator i = sLockedList.begin(); i != sLockedList.end(); ++i)
- {
- if (*i == this)
- {
- sLockedList.erase(i);
- break;
- }
- }
- }
};
//----------------------------------------------------------------------------
+void LLVertexBuffer::genBuffer()
+{
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ mGLBuffer = sStreamVBOPool.allocate();
+ }
+ else if (mUsage == GL_DYNAMIC_DRAW_ARB)
+ {
+ mGLBuffer = sDynamicVBOPool.allocate();
+ }
+ else
+ {
+ BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
+ glGenBuffersARB(1, (GLuint*)&mGLBuffer);
+ }
+ sGLCount++;
+}
+
+void LLVertexBuffer::genIndices()
+{
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ mGLIndices = sStreamIBOPool.allocate();
+ }
+ else if (mUsage == GL_DYNAMIC_DRAW_ARB)
+ {
+ mGLIndices = sDynamicIBOPool.allocate();
+ }
+ else
+ {
+ BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
+ glGenBuffersARB(1, (GLuint*)&mGLIndices);
+ }
+ sGLCount++;
+}
+
+void LLVertexBuffer::releaseBuffer()
+{
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ sStreamVBOPool.release(mGLBuffer);
+ }
+ else if (mUsage == GL_DYNAMIC_DRAW_ARB)
+ {
+ sDynamicVBOPool.release(mGLBuffer);
+ }
+ else
+ {
+ sDeleteList.push_back(mGLBuffer);
+ }
+ sGLCount--;
+}
+
+void LLVertexBuffer::releaseIndices()
+{
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ sStreamIBOPool.release(mGLIndices);
+ }
+ else if (mUsage == GL_DYNAMIC_DRAW_ARB)
+ {
+ sDynamicIBOPool.release(mGLIndices);
+ }
+ else
+ {
+ sDeleteList.push_back(mGLIndices);
+ }
+ sGLCount--;
+}
+
void LLVertexBuffer::createGLBuffer()
{
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
@@ -238,20 +289,20 @@ void LLVertexBuffer::createGLBuffer()
return;
}
- mMappedData = new U8[size];
- memset(mMappedData, 0, size);
mEmpty = TRUE;
if (useVBOs())
{
- glGenBuffersARB(1, (GLuint*) &mGLBuffer);
+ mMappedData = NULL;
+ genBuffer();
mResized = TRUE;
- sGLCount++;
}
else
{
static int gl_buffer_idx = 0;
mGLBuffer = ++gl_buffer_idx;
+ mMappedData = new U8[size];
+ memset(mMappedData, 0, size);
}
}
@@ -270,18 +321,18 @@ void LLVertexBuffer::createGLIndices()
return;
}
- mMappedIndexData = new U8[size];
- memset(mMappedIndexData, 0, size);
mEmpty = TRUE;
if (useVBOs())
{
- glGenBuffersARB(1, (GLuint*) &mGLIndices);
+ mMappedIndexData = NULL;
+ genIndices();
mResized = TRUE;
- sGLCount++;
}
else
{
+ mMappedIndexData = new U8[size];
+ memset(mMappedIndexData, 0, size);
static int gl_buffer_idx = 0;
mGLIndices = ++gl_buffer_idx;
}
@@ -294,12 +345,19 @@ void LLVertexBuffer::destroyGLBuffer()
{
if (useVBOs())
{
- sDeleteList.push_back(mGLBuffer);
+ if (mMappedData || mMappedIndexData)
+ {
+ llerrs << "Vertex buffer destroyed while mapped!" << llendl;
+ }
+ releaseBuffer();
+ }
+ else
+ {
+ delete [] mMappedData;
+ mMappedData = NULL;
+ mEmpty = TRUE;
}
-
- delete [] mMappedData;
- mMappedData = NULL;
- mEmpty = TRUE;
+
sAllocatedBytes -= getSize();
}
@@ -313,12 +371,19 @@ void LLVertexBuffer::destroyGLIndices()
{
if (useVBOs())
{
- sDeleteList.push_back(mGLIndices);
+ if (mMappedData || mMappedIndexData)
+ {
+ llerrs << "Vertex buffer destroyed while mapped." << llendl;
+ }
+ releaseIndices();
+ }
+ else
+ {
+ delete [] mMappedIndexData;
+ mMappedIndexData = NULL;
+ mEmpty = TRUE;
}
-
- delete [] mMappedIndexData;
- mMappedIndexData = NULL;
- mEmpty = TRUE;
+
sAllocatedBytes -= getIndicesSize();
}
@@ -328,6 +393,15 @@ void LLVertexBuffer::destroyGLIndices()
void LLVertexBuffer::updateNumVerts(S32 nverts)
{
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
+
+ if (nverts >= 65535)
+ {
+ llwarns << "Vertex buffer overflow!" << llendl;
+ nverts = 65535;
+ }
+
+ mRequestedNumVerts = nverts;
+
if (!mDynamicSize)
{
mNumVerts = nverts;
@@ -336,18 +410,19 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
nverts > mNumVerts ||
nverts < mNumVerts/2)
{
- if (mUsage != GL_STATIC_DRAW_ARB)
+ if (mUsage != GL_STATIC_DRAW_ARB && nverts + nverts/4 <= 65535)
{
nverts += nverts/4;
}
-
mNumVerts = nverts;
}
+
}
void LLVertexBuffer::updateNumIndices(S32 nindices)
{
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
+ mRequestedNumIndices = nindices;
if (!mDynamicSize)
{
mNumIndices = nindices;
@@ -365,54 +440,6 @@ void LLVertexBuffer::updateNumIndices(S32 nindices)
}
}
-void LLVertexBuffer::makeStatic()
-{
- if (!sEnableVBOs)
- {
- return;
- }
-
- if (sRenderActive)
- {
- llerrs << "Make static called during render." << llendl;
- }
-
- if (mUsage != GL_STATIC_DRAW_ARB)
- {
- if (useVBOs())
- {
- if (mGLBuffer)
- {
- sDeleteList.push_back(mGLBuffer);
- }
- if (mGLIndices)
- {
- sDeleteList.push_back(mGLIndices);
- }
- }
-
- if (mGLBuffer)
- {
- sGLCount++;
- glGenBuffersARB(1, (GLuint*) &mGLBuffer);
- }
- if (mGLIndices)
- {
- sGLCount++;
- glGenBuffersARB(1, (GLuint*) &mGLIndices);
- }
-
- mUsage = GL_STATIC_DRAW_ARB;
- mResized = TRUE;
-
- if (!mLocked)
- {
- mLocked = TRUE;
- sLockedList.push_back(this);
- }
- }
-}
-
void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
{
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
@@ -435,6 +462,9 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
{
+ mRequestedNumVerts = newnverts;
+ mRequestedNumIndices = newnindices;
+
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
mDynamicSize = TRUE;
if (mUsage == GL_STATIC_DRAW_ARB)
@@ -469,22 +499,25 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
else
{
//delete old buffer, keep GL buffer for now
- U8* old = mMappedData;
- mMappedData = new U8[newsize];
- if (old)
- {
- memcpy(mMappedData, old, llmin(newsize, oldsize));
- if (newsize > oldsize)
+ if (!useVBOs())
+ {
+ U8* old = mMappedData;
+ mMappedData = new U8[newsize];
+ if (old)
+ {
+ memcpy(mMappedData, old, llmin(newsize, oldsize));
+ if (newsize > oldsize)
+ {
+ memset(mMappedData+oldsize, 0, newsize-oldsize);
+ }
+
+ delete [] old;
+ }
+ else
{
- memset(mMappedData+oldsize, 0, newsize-oldsize);
+ memset(mMappedData, 0, newsize);
+ mEmpty = TRUE;
}
-
- delete [] old;
- }
- else
- {
- memset(mMappedData, 0, newsize);
- mEmpty = TRUE;
}
mResized = TRUE;
}
@@ -502,22 +535,26 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
}
else
{
- //delete old buffer, keep GL buffer for now
- U8* old = mMappedIndexData;
- mMappedIndexData = new U8[new_index_size];
- if (old)
- {
- memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size));
- if (new_index_size > old_index_size)
+ if (!useVBOs())
+ {
+ //delete old buffer, keep GL buffer for now
+ U8* old = mMappedIndexData;
+ mMappedIndexData = new U8[new_index_size];
+
+ if (old)
+ {
+ memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size));
+ if (new_index_size > old_index_size)
+ {
+ memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size);
+ }
+ delete [] old;
+ }
+ else
{
- memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size);
+ memset(mMappedIndexData, 0, new_index_size);
+ mEmpty = TRUE;
}
- delete [] old;
- }
- else
- {
- memset(mMappedIndexData, 0, new_index_size);
- mEmpty = TRUE;
}
mResized = TRUE;
}
@@ -527,18 +564,29 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
destroyGLIndices();
}
}
+
+ if (mResized && useVBOs())
+ {
+ setBuffer(0);
+ }
}
BOOL LLVertexBuffer::useVBOs() const
{
- //it's generally ineffective to use VBO for things that are streaming
- //when we already have a client buffer around
- if (mUsage == GL_STREAM_DRAW_ARB)
+ //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;
}
-
- return sEnableVBOs && (!sRenderActive || !mLocked);
+#else
+ if (!mUsage)
+ {
+ return FALSE;
+ }
+#endif
+ return sEnableVBOs; // && (!sRenderActive || !mLocked);
}
//----------------------------------------------------------------------------
@@ -547,27 +595,27 @@ BOOL LLVertexBuffer::useVBOs() const
U8* LLVertexBuffer::mapBuffer(S32 access)
{
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
- if (sRenderActive)
- {
- llwarns << "Buffer mapped during render frame!" << llendl;
- }
- if (!mGLBuffer && !mGLIndices)
- {
- llerrs << "LLVertexBuffer::mapBuffer() called before createGLBuffer" << llendl;
- }
if (mFinal)
{
llerrs << "LLVertexBuffer::mapBuffer() called on a finalized buffer." << llendl;
}
- if (!mMappedData && !mMappedIndexData)
+ if (!useVBOs() && !mMappedData && !mMappedIndexData)
{
llerrs << "LLVertexBuffer::mapBuffer() called on unallocated buffer." << llendl;
}
-
+
if (!mLocked && useVBOs())
{
+ setBuffer(0);
mLocked = TRUE;
- sLockedList.push_back(this);
+ mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ /*if (sMapped)
+ {
+ llerrs << "Mapped two VBOs at the same time!" << llendl;
+ }
+ sMapped = TRUE;*/
+ sMappedCount++;
}
return mMappedData;
@@ -580,64 +628,19 @@ void LLVertexBuffer::unmapBuffer()
{
if (useVBOs() && mLocked)
{
- if (mGLBuffer)
- {
- if (mResized)
- {
- glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), mMappedData, mUsage);
- }
- else
- {
- if (mEmpty || mDirtyRegions.empty())
- {
- glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), mMappedData);
- }
- else
- {
- for (std::vector<DirtyRegion>::iterator i = mDirtyRegions.begin(); i != mDirtyRegions.end(); ++i)
- {
- DirtyRegion& region = *i;
- glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, region.mIndex*mStride, region.mCount*mStride, mMappedData + region.mIndex*mStride);
- }
- }
- }
- }
-
- if (mGLIndices)
+ glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+ glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+
+ /*if (!sMapped)
{
- if (mResized)
- {
- glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), mMappedIndexData, mUsage);
- }
- else
- {
- if (mEmpty || mDirtyRegions.empty())
- {
- glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), mMappedIndexData);
- }
- else
- {
- for (std::vector<DirtyRegion>::iterator i = mDirtyRegions.begin(); i != mDirtyRegions.end(); ++i)
- {
- DirtyRegion& region = *i;
- glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, region.mIndicesIndex*sizeof(U32),
- region.mIndicesCount*sizeof(U32), mMappedIndexData + region.mIndicesIndex*sizeof(U32));
- }
- }
- }
+ llerrs << "Redundantly unmapped VBO!" << llendl;
}
-
- mDirtyRegions.clear();
- mFilthy = FALSE;
- mResized = FALSE;
+ sMapped = FALSE;*/
+ sMappedCount--;
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)
- delete [] mMappedData;
- delete [] mMappedIndexData;
- mMappedIndexData = NULL;
- mMappedData = NULL;
mEmpty = TRUE;
mFinal = TRUE;
}
@@ -645,10 +648,11 @@ void LLVertexBuffer::unmapBuffer()
{
mEmpty = FALSE;
}
+
+ mMappedIndexData = NULL;
+ mMappedData = NULL;
mLocked = FALSE;
-
- glFlush();
}
}
}
@@ -690,9 +694,9 @@ bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index)
{
return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index);
}
-bool LLVertexBuffer::getIndexStrider(LLStrider<U32>& strider, S32 index)
+bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index)
{
- return VertexBufferStrider<U32,TYPE_INDEX>::get(*this, strider, index);
+ return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index);
}
bool LLVertexBuffer::getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index)
{
@@ -755,16 +759,46 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
{
if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))
{
+ /*if (sMapped)
+ {
+ llerrs << "VBO bound while another VBO mapped!" << llendl;
+ }*/
glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
+ sBindCount++;
sVBOActive = TRUE;
setup = TRUE; // ... or the bound buffer changed
}
if (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))
{
+ /*if (sMapped)
+ {
+ llerrs << "VBO bound while another VBO mapped!" << llendl;
+ }*/
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
+ sBindCount++;
sIBOActive = TRUE;
}
+ if (mResized)
+ {
+ if (mGLBuffer)
+ {
+ glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), NULL, mUsage);
+ }
+ if (mGLIndices)
+ {
+ glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), NULL, mUsage);
+ }
+
+ mEmpty = TRUE;
+ mResized = FALSE;
+
+ if (data_mask != 0)
+ {
+ llerrs << "Buffer set for rendering before being filled after resize." << llendl;
+ }
+ }
+
unmapBuffer();
}
else
@@ -774,6 +808,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
if (sEnableVBOs && sVBOActive)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ sBindCount++;
sVBOActive = FALSE;
setup = TRUE; // ... or a VBO is deactivated
}
@@ -784,7 +819,12 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
}
if (sEnableVBOs && mGLIndices && sIBOActive)
{
+ /*if (sMapped)
+ {
+ llerrs << "VBO unbound while potentially mapped!" << llendl;
+ }*/
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ sBindCount++;
sIBOActive = FALSE;
}
}
@@ -803,9 +843,11 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
llwarns << "Vertex buffer set for rendering outside of render frame." << llendl;
}
setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
- sLastMask = data_mask;
+ sSetCount++;
}
}
+
+ sLastMask = data_mask;
}
// virtual (default)
@@ -821,10 +863,6 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
}
- if (data_mask & MAP_VERTEX)
- {
- glVertexPointer(3,GL_FLOAT, stride, (void*)(base + 0));
- }
if (data_mask & MAP_NORMAL)
{
glNormalPointer(GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_NORMAL]));
@@ -855,49 +893,19 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
{
glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, stride, (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
}
+ if (data_mask & MAP_VERTEX)
+ {
+ glVertexPointer(3,GL_FLOAT, stride, (void*)(base + 0));
+ }
llglassertok();
}
void LLVertexBuffer::markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count)
{
- if (useVBOs() && !mFilthy)
- {
- if (!mDirtyRegions.empty())
- {
- DirtyRegion& region = *(mDirtyRegions.rbegin());
-
- if (region.mIndex+region.mCount > vert_index)
- {
- //this buffer has received multiple updates since the last copy, mark it filthy
- mFilthy = TRUE;
- mDirtyRegions.clear();
- return;
- }
-
- if (region.mIndex + region.mCount == vert_index &&
- region.mIndicesIndex + region.mIndicesCount == indices_index)
- {
- region.mCount += vert_count;
- region.mIndicesCount += indices_count;
- return;
- }
- }
-
- mDirtyRegions.push_back(DirtyRegion(vert_index,vert_count,indices_index,indices_count));
- }
-}
-
-void LLVertexBuffer::markClean()
-{
- if (!mResized && !mEmpty && !mFilthy)
+ // TODO: use GL_APPLE_flush_buffer_range here
+ /*if (useVBOs() && !mFilthy)
{
- buffer_list_t::reverse_iterator iter = sLockedList.rbegin();
- if (*iter == this)
- {
- mLocked = FALSE;
- sLockedList.pop_back();
- }
- }
+
+ }*/
}
-
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index cf36eb664c..e2a4196b0e 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -50,12 +50,38 @@
// be called as soon as getVertexPointer(), etc is called (which MUST ONLY be
// called from the main (i.e OpenGL) thread)
+
+//============================================================================
+// gl name pools for dynamic and streaming buffers
+
+class LLVBOPool : public LLGLNamePool
+{
+protected:
+ virtual GLuint allocateName()
+ {
+ GLuint name;
+ glGenBuffersARB(1, &name);
+ return name;
+ }
+
+ virtual void releaseName(GLuint name)
+ {
+ glDeleteBuffersARB(1, &name);
+ }
+};
+
+
//============================================================================
// base class
class LLVertexBuffer : public LLRefCount
{
public:
+ static LLVBOPool sStreamVBOPool;
+ static LLVBOPool sDynamicVBOPool;
+ static LLVBOPool sStreamIBOPool;
+ static LLVBOPool sDynamicIBOPool;
+
static void initClass(bool use_vbo);
static void cleanupClass();
static void startRender(); //between start and stop render, no client copies will occur
@@ -63,6 +89,12 @@ public:
static void clientCopy(F64 max_time = 0.005); //copy data from client to GL
static void unbind(); //unbind any bound vertex buffer
+ //get the size of a vertex with the given typemask
+ //if offsets is not NULL, its contents will be filled
+ //with the offset of each vertex component in the buffer,
+ // indexed by the following enum
+ static S32 calcStride(const U32& typemask, S32* offsets = NULL);
+
enum {
TYPE_VERTEX,
TYPE_NORMAL,
@@ -92,10 +124,16 @@ public:
};
protected:
+ friend class LLGLImmediate;
+
virtual ~LLVertexBuffer(); // use unref()
virtual void setupVertexBuffer(U32 data_mask) const; // pure virtual, called from mapBuffer()
-
+
+ void genBuffer();
+ void genIndices();
+ void releaseBuffer();
+ void releaseIndices();
void createGLBuffer();
void createGLIndices();
void destroyGLBuffer();
@@ -104,7 +142,7 @@ protected:
void updateNumIndices(S32 nindices);
virtual BOOL useVBOs() const;
void unmapBuffer();
-
+
public:
LLVertexBuffer(U32 typemask, S32 usage);
@@ -115,8 +153,7 @@ public:
// allocate buffer
void allocateBuffer(S32 nverts, S32 nindices, bool create);
virtual void resizeBuffer(S32 newnverts, S32 newnindices);
- void makeStatic();
-
+
// Only call each getVertexPointer, etc, once before calling unmapBuffer()
// call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer()
// example:
@@ -125,7 +162,7 @@ public:
// setVertsNorms(verts, norms);
// vb->unmapBuffer();
bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0);
- bool getIndexStrider(LLStrider<U32>& strider, S32 index=0);
+ bool getIndexStrider(LLStrider<U16>& strider, S32 index=0);
bool getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index=0);
bool getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index=0);
bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0);
@@ -138,13 +175,16 @@ public:
BOOL isLocked() const { return mLocked; }
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() ? NULL : mMappedIndexData; }
U8* getVerticesPointer() const { return useVBOs() ? NULL : mMappedData; }
S32 getStride() const { return mStride; }
S32 getTypeMask() const { return mTypeMask; }
BOOL hasDataType(S32 type) const { return ((1 << type) & getTypeMask()) ? TRUE : FALSE; }
S32 getSize() const { return mNumVerts*mStride; }
- S32 getIndicesSize() const { return mNumIndices * sizeof(U32); }
+ S32 getIndicesSize() const { return mNumIndices * sizeof(U16); }
U8* getMappedData() const { return mMappedData; }
U8* getMappedIndices() const { return mMappedIndexData; }
S32 getOffset(S32 type) const { return mOffsets[type]; }
@@ -153,11 +193,13 @@ public:
void setStride(S32 type, S32 new_stride);
void markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count);
- void markClean();
protected:
- S32 mNumVerts; // Number of vertices
- S32 mNumIndices; // Number of indices
+ S32 mNumVerts; // Number of vertices allocated
+ S32 mNumIndices; // Number of indices allocated
+ S32 mRequestedNumVerts; // Number of vertices requested
+ S32 mRequestedNumIndices; // Number of indices requested
+
S32 mStride;
U32 mTypeMask;
S32 mUsage; // GL usage
@@ -192,10 +234,11 @@ public:
static BOOL sRenderActive;
static S32 sCount;
static S32 sGLCount;
+ static S32 sMappedCount;
+ static BOOL sMapped;
static std::vector<U32> sDeleteList;
typedef std::list<LLVertexBuffer*> buffer_list_t;
- static buffer_list_t sLockedList;
-
+
static BOOL sEnableVBOs;
static S32 sTypeOffsets[TYPE_MAX];
static U32 sGLRenderBuffer;
@@ -204,6 +247,8 @@ public:
static BOOL sIBOActive;
static U32 sLastMask;
static U32 sAllocatedBytes;
+ static U32 sBindCount;
+ static U32 sSetCount;
};