diff options
Diffstat (limited to 'indra/llrender')
-rw-r--r-- | indra/llrender/llfontgl.cpp | 73 | ||||
-rw-r--r-- | indra/llrender/llimagegl.cpp | 16 | ||||
-rw-r--r-- | indra/llrender/llimagegl.h | 3 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.cpp | 185 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.h | 116 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 538 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.h | 67 |
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; }; |