summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
authorRunitaiLinden <davep@lindenlab.com>2023-01-19 09:13:45 -0600
committerGitHub <noreply@github.com>2023-01-19 09:13:45 -0600
commit7bd9d21e19b923096ba2b5ea3cbc8be3e13d7aa0 (patch)
treee96b35f6ae7a1377334e467fc324ec17ac6e49c3 /indra/llrender
parent1ff3b1ffa54db0f7aaca543e2565e1ac3087d1e0 (diff)
Optimizations, decruft, and intel compatibility pass (#53)
SL-18869, SL-18772 Overhaul VBO management, restore occlusion culling, intel compatibility pass, etc
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/llgl.cpp217
-rw-r--r--indra/llrender/llgl.h9
-rw-r--r--indra/llrender/llglslshader.cpp21
-rw-r--r--indra/llrender/llrender.cpp37
-rw-r--r--indra/llrender/llrender.h46
-rw-r--r--indra/llrender/llrendernavprim.cpp2
-rw-r--r--indra/llrender/llshadermgr.cpp29
-rw-r--r--indra/llrender/llvertexbuffer.cpp1442
-rw-r--r--indra/llrender/llvertexbuffer.h205
9 files changed, 562 insertions, 1446 deletions
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 67bd9e277e..9dfe5ef9ff 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2395,234 +2395,39 @@ void LLGLState::dumpStates()
}
}
-void LLGLState::checkStates(const std::string& msg)
+void LLGLState::checkStates(GLboolean writeAlpha)
{
if (!gDebugGL)
{
return;
}
- stop_glerror();
-
GLint src;
GLint dst;
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)
- {
- if (gDebugSession)
- {
- gFailLog << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << " " << msg << std::dec << std::endl;
- error = TRUE;
- }
- else
- {
- LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << " " << msg << std::dec << LL_ENDL;
- }
- }*/
+ llassert_always(src == GL_SRC_ALPHA);
+ llassert_always(dst == GL_ONE_MINUS_SRC_ALPHA);
+
+ GLboolean colorMask[4];
+ glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
+ llassert_always(colorMask[0]);
+ llassert_always(colorMask[1]);
+ llassert_always(colorMask[2]);
+ llassert_always(colorMask[3] == writeAlpha);
for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
iter != sStateMap.end(); ++iter)
{
LLGLenum state = iter->first;
LLGLboolean cur_state = iter->second;
- stop_glerror();
LLGLboolean gl_state = glIsEnabled(state);
- stop_glerror();
if(cur_state != gl_state)
{
dumpStates();
- if (gDebugSession)
- {
- gFailLog << llformat("LLGLState error. State: 0x%04x",state) << std::endl;
- error = TRUE;
- }
- else
- {
- LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL;
- }
- }
- }
-
- if (error)
- {
- ll_fail("LLGLState::checkStates failed.");
- }
- stop_glerror();
-}
-
-void LLGLState::checkTextureChannels(const std::string& msg)
-{
-#if 0
- if (!gDebugGL)
- {
- return;
- }
- stop_glerror();
-
- GLint activeTexture;
- glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
- stop_glerror();
-
- BOOL error = FALSE;
-
- if (activeTexture == GL_TEXTURE0)
- {
- GLint tex_env_mode = 0;
-
- glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &tex_env_mode);
- stop_glerror();
-
- if (tex_env_mode != GL_MODULATE)
- {
- error = TRUE;
- LL_WARNS("RenderState") << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << std::dec << LL_ENDL;
- if (gDebugSession)
- {
- gFailLog << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << std::dec << std::endl;
- }
+ LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL;
}
}
-
- static const char* label[] =
- {
- "GL_TEXTURE_2D",
- "GL_TEXTURE_COORD_ARRAY",
- "GL_TEXTURE_1D",
- "GL_TEXTURE_CUBE_MAP",
- "GL_TEXTURE_GEN_S",
- "GL_TEXTURE_GEN_T",
- "GL_TEXTURE_GEN_Q",
- "GL_TEXTURE_GEN_R",
- "GL_TEXTURE_RECTANGLE",
- "GL_TEXTURE_2D_MULTISAMPLE"
- };
-
- static GLint value[] =
- {
- GL_TEXTURE_2D,
- GL_TEXTURE_COORD_ARRAY,
- GL_TEXTURE_1D,
- GL_TEXTURE_CUBE_MAP,
- GL_TEXTURE_GEN_S,
- GL_TEXTURE_GEN_T,
- GL_TEXTURE_GEN_Q,
- GL_TEXTURE_GEN_R,
- GL_TEXTURE_RECTANGLE,
- GL_TEXTURE_2D_MULTISAMPLE
- };
-
- GLint stackDepth = 0;
-
- glh::matrix4f mat;
- glh::matrix4f identity;
- identity.identity();
-
- for (GLint i = 1; i < gGLManager.mNumTextureImageUnits; i++)
- {
- gGL.getTexUnit(i)->activate();
-
- if (i < gGLManager.mNumTextureUnits)
- {
- glClientActiveTexture(GL_TEXTURE0+i);
- stop_glerror();
- glGetIntegerv(GL_TEXTURE_STACK_DEPTH, &stackDepth);
- stop_glerror();
-
- if (stackDepth != 1)
- {
- error = TRUE;
- LL_WARNS("RenderState") << "Texture matrix stack corrupted." << LL_ENDL;
-
- if (gDebugSession)
- {
- gFailLog << "Texture matrix stack corrupted." << std::endl;
- }
- }
-
- glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) mat.m);
- stop_glerror();
-
- if (mat != identity)
- {
- error = TRUE;
- LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL;
- if (gDebugSession)
- {
- gFailLog << "Texture matrix in channel " << i << " corrupt." << std::endl;
- }
- }
-
- for (S32 j = (i == 0 ? 1 : 0);
- j < 9; j++)
- {
- if (glIsEnabled(value[j]))
- {
- error = TRUE;
- LL_WARNS("RenderState") << "Texture channel " << i << " still has " << label[j] << " enabled." << LL_ENDL;
- if (gDebugSession)
- {
- gFailLog << "Texture channel " << i << " still has " << label[j] << " enabled." << std::endl;
- }
- }
- stop_glerror();
- }
-
- glGetFloatv(GL_TEXTURE_MATRIX, mat.m);
- stop_glerror();
-
- if (mat != identity)
- {
- error = TRUE;
- LL_WARNS("RenderState") << "Texture matrix " << i << " is not identity." << LL_ENDL;
- if (gDebugSession)
- {
- gFailLog << "Texture matrix " << i << " is not identity." << std::endl;
- }
- }
- }
-
- {
- GLint tex = 0;
- stop_glerror();
- glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex);
- stop_glerror();
-
- if (tex != 0)
- {
- error = TRUE;
- LL_WARNS("RenderState") << "Texture channel " << i << " still has texture " << tex << " bound." << LL_ENDL;
-
- if (gDebugSession)
- {
- gFailLog << "Texture channel " << i << " still has texture " << tex << " bound." << std::endl;
- }
- }
- }
- }
-
- stop_glerror();
- gGL.getTexUnit(0)->activate();
- glClientActiveTexture(GL_TEXTURE0);
- stop_glerror();
-
- if (error)
- {
- if (gDebugSession)
- {
- ll_fail("LLGLState::checkTextureChannels failed.");
- }
- else
- {
- LL_GL_ERRS << "GL texture state corruption detected. " << msg << LL_ENDL;
- }
- }
-#endif
}
///////////////////////////////////////////////////////////////////////
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index e3c07604aa..eb0650d998 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -231,9 +231,12 @@ public:
static void resetTextureStates();
static void dumpStates();
- static void checkStates(const std::string& msg = "");
- static void checkTextureChannels(const std::string& msg = "");
-
+
+ // make sure GL blend function, GL states, and GL color mask match
+ // what we expect
+ // writeAlpha - whether or not writing to alpha channel is expected
+ static void checkStates(GLboolean writeAlpha = GL_TRUE);
+
protected:
static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap;
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index c5f4efd2c0..982b2a847a 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -154,15 +154,33 @@ void LLGLSLShader::finishProfile(bool emit_report)
std::sort(sorted.begin(), sorted.end(), LLGLSLShaderCompareTimeElapsed());
+ bool unbound = false;
for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
{
(*iter)->dumpStats();
+ if ((*iter)->mBinds == 0)
+ {
+ unbound = true;
+ }
}
LL_INFOS() << "-----------------------------------" << LL_ENDL;
LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed / 1000000.f) << LL_ENDL;
LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn / 1000000.f) << LL_ENDL;
LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn / 1000000.f) << LL_ENDL;
+ LL_INFOS() << "-----------------------------------" << LL_ENDL;
+
+ if (unbound)
+ {
+ LL_INFOS() << "The following shaders were unused: " << LL_ENDL;
+ for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
+ {
+ if ((*iter)->mBinds == 0)
+ {
+ LL_INFOS() << (*iter)->mName << LL_ENDL;
+ }
+ }
+ }
}
}
@@ -985,6 +1003,8 @@ void LLGLSLShader::bind()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+ llassert(mProgramObject != 0);
+
gGL.flush();
if (sCurBoundShader != mProgramObject) // Don't re-bind current shader
@@ -998,6 +1018,7 @@ void LLGLSLShader::bind()
sCurBoundShader = mProgramObject;
sCurBoundShaderPtr = this;
placeProfileQuery();
+ LLVertexBuffer::setupClientArrays(mAttributeMask);
}
if (mUniformsDirty)
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index bba6a46e43..a8db69a9a4 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -164,13 +164,10 @@ 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;
@@ -184,11 +181,7 @@ void LLTexUnit::disable(void)
if (mCurrTexType != TT_NONE)
{
- activate();
unbind(mCurrTexType);
- gGL.flush();
- setTextureColorSpace(TCS_LINEAR);
-
mCurrTexType = TT_NONE;
}
}
@@ -196,7 +189,7 @@ void LLTexUnit::disable(void)
void LLTexUnit::bindFast(LLTexture* texture)
{
LLImageGL* gl_tex = texture->getGLTexture();
-
+ texture->setActive();
glActiveTexture(GL_TEXTURE0 + mIndex);
gGL.mCurrTextureUnitIndex = mIndex;
mCurrTexture = gl_tex->getTexName();
@@ -889,12 +882,11 @@ void LLRender::init(bool needs_vertex_buffer)
// necessary for reflection maps
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
- if (sGLCoreProfile && !LLVertexBuffer::sUseVAO)
- { //bind a dummy vertex array object so we're core profile compliant
- U32 ret;
- glGenVertexArrays(1, &ret);
- glBindVertexArray(ret);
- }
+ { //bind a dummy vertex array object so we're core profile compliant
+ U32 ret;
+ glGenVertexArrays(1, &ret);
+ glBindVertexArray(ret);
+ }
if (needs_vertex_buffer)
{
@@ -906,8 +898,8 @@ void LLRender::initVertexBuffer()
{
llassert_always(mBuffer.isNull());
stop_glerror();
- mBuffer = new LLVertexBuffer(immediate_mask, 0);
- mBuffer->allocateBuffer(4096, 0, TRUE);
+ mBuffer = new LLVertexBuffer(immediate_mask);
+ mBuffer->allocateBuffer(4096, 0);
mBuffer->getVertexStrider(mVerticesp);
mBuffer->getTexCoord0Strider(mTexcoordsp);
mBuffer->getColorStrider(mColorsp);
@@ -1604,6 +1596,7 @@ void LLRender::flush()
if (mCount > 0)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+ llassert(LLGLSLShader::sCurBoundShaderPtr != nullptr);
if (!mUIOffset.empty())
{
sUICalls++;
@@ -1691,8 +1684,11 @@ void LLRender::flush()
else
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache miss");
- vb = new LLVertexBuffer(attribute_mask, GL_STATIC_DRAW);
- vb->allocateBuffer(count, 0, true);
+ vb = new LLVertexBuffer(attribute_mask);
+ vb->allocateBuffer(count, 0);
+
+ vb->setBuffer();
+
vb->setPositionData((LLVector4a*) mVerticesp.get());
if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0)
@@ -1733,7 +1729,7 @@ void LLRender::flush()
}
}
- vb->setBuffer(attribute_mask);
+ vb->setBuffer();
if (mMode == LLRender::QUADS && sGLCoreProfile)
{
@@ -2034,8 +2030,7 @@ void LLRender::texCoord2fv(const GLfloat* tc)
void LLRender::color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a)
{
- if (!LLGLSLShader::sCurBoundShaderPtr ||
- LLGLSLShader::sCurBoundShaderPtr->mAttributeMask & LLVertexBuffer::MAP_COLOR)
+ if (!LLGLSLShader::sCurBoundShaderPtr || LLGLSLShader::sCurBoundShaderPtr->mAttributeMask & LLVertexBuffer::MAP_COLOR)
{
mColorsp[mCount] = LLColor4U(r,g,b,a);
}
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 9fabeb1d7a..cbd3de5736 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -277,7 +277,7 @@ class LLRender
friend class LLTexUnit;
public:
- enum eTexIndex
+ enum eTexIndex : U8
{
DIFFUSE_MAP = 0,
ALTERNATE_DIFFUSE_MAP = 1,
@@ -286,14 +286,15 @@ public:
NUM_TEXTURE_CHANNELS = 3,
};
- enum eVolumeTexIndex
+ enum eVolumeTexIndex : U8
{
LIGHT_TEX = 0,
SCULPT_TEX,
NUM_VOLUME_TEXTURE_CHANNELS,
};
- typedef enum {
+ enum eGeomModes : U8
+ {
TRIANGLES = 0,
TRIANGLE_STRIP,
TRIANGLE_FAN,
@@ -303,9 +304,9 @@ public:
QUADS,
LINE_LOOP,
NUM_MODES
- } eGeomModes;
+ };
- typedef enum
+ enum eCompareFunc : U8
{
CF_NEVER = 0,
CF_ALWAYS,
@@ -316,9 +317,9 @@ public:
CF_GREATER_EQUAL,
CF_GREATER,
CF_DEFAULT
- } eCompareFunc;
+ };
- typedef enum
+ enum eBlendType : U8
{
BT_ALPHA = 0,
BT_ADD,
@@ -327,25 +328,26 @@ public:
BT_MULT_ALPHA,
BT_MULT_X2,
BT_REPLACE
- } eBlendType;
+ };
- typedef enum
+ // WARNING: this MUST match the LL_PART_BF enum in LLPartData, so set values explicitly in case someone
+ // decides to add more or reorder them
+ enum eBlendFactor : U8
{
BF_ONE = 0,
- BF_ZERO,
- BF_DEST_COLOR,
- BF_SOURCE_COLOR,
- BF_ONE_MINUS_DEST_COLOR,
- BF_ONE_MINUS_SOURCE_COLOR,
- BF_DEST_ALPHA,
- BF_SOURCE_ALPHA,
- BF_ONE_MINUS_DEST_ALPHA,
- BF_ONE_MINUS_SOURCE_ALPHA,
-
+ BF_ZERO = 1,
+ BF_DEST_COLOR = 2,
+ BF_SOURCE_COLOR = 3,
+ BF_ONE_MINUS_DEST_COLOR = 4,
+ BF_ONE_MINUS_SOURCE_COLOR = 5,
+ BF_DEST_ALPHA = 6,
+ BF_SOURCE_ALPHA = 7,
+ BF_ONE_MINUS_DEST_ALPHA = 8,
+ BF_ONE_MINUS_SOURCE_ALPHA = 9,
BF_UNDEF
- } eBlendFactor;
+ };
- typedef enum
+ enum eMatrixMode : U8
{
MM_MODELVIEW = 0,
MM_PROJECTION,
@@ -355,7 +357,7 @@ public:
MM_TEXTURE3,
NUM_MATRIX_MODES,
MM_TEXTURE
- } eMatrixMode;
+ };
LLRender();
~LLRender();
diff --git a/indra/llrender/llrendernavprim.cpp b/indra/llrender/llrendernavprim.cpp
index ca72964832..d610a44bc6 100644
--- a/indra/llrender/llrendernavprim.cpp
+++ b/indra/llrender/llrendernavprim.cpp
@@ -53,7 +53,7 @@ void LLRenderNavPrim::renderLLTri( const LLVector3& a, const LLVector3& b, const
//=============================================================================
void LLRenderNavPrim::renderNavMeshVB( U32 mode, LLVertexBuffer* pVBO, int vertCnt )
{
- pVBO->setBuffer( LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_NORMAL );
+ pVBO->setBuffer();
pVBO->drawArrays( mode, 0, vertCnt );
}
//=============================================================================
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index b189e5452c..ee8ac359c7 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -590,6 +590,7 @@ static std::string get_shader_log(GLuint ret)
static std::string get_program_log(GLuint ret)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
std::string res;
//get log length
@@ -1113,16 +1114,24 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
BOOL LLShaderMgr::linkProgramObject(GLuint obj, BOOL suppress_errors)
{
//check for errors
- glLinkProgram(obj);
- GLint success = GL_TRUE;
- glGetProgramiv(obj, GL_LINK_STATUS, &success);
- if (!suppress_errors && success == GL_FALSE)
- {
- //an error occured, print log
- LL_SHADER_LOADING_WARNS() << "GLSL Linker Error:" << LL_ENDL;
- dumpObjectLog(obj, TRUE, "linker");
- return success;
- }
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER("glLinkProgram");
+ glLinkProgram(obj);
+ }
+
+ GLint success = GL_TRUE;
+
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER("glsl check link status");
+ glGetProgramiv(obj, GL_LINK_STATUS, &success);
+ if (!suppress_errors && success == GL_FALSE)
+ {
+ //an error occured, print log
+ LL_SHADER_LOADING_WARNS() << "GLSL Linker Error:" << LL_ENDL;
+ dumpObjectLog(obj, TRUE, "linker");
+ return success;
+ }
+ }
std::string log = get_program_log(obj);
LLStringUtil::toLower(log);
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index bc33591ed7..f1d71ec94d 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -70,25 +70,6 @@ struct CompareMappedRegion
}
};
-
-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)
-{
- U32 blocks = vbo_block_size(size)/LL_VBO_BLOCK_SIZE; // block count reqd
- llassert(blocks > 0);
- return blocks - 1; // Adj index, i.e. single-block allocations are at index 0, etc
-}
-
-const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE) + 1;
-
#define ENABLE_GL_WORK_QUEUE 0
#if ENABLE_GL_WORK_QUEUE
@@ -294,6 +275,8 @@ static GLuint gen_buffer()
return sNamePool[--sIndex];
}
+#define ANALYZE_VBO_POOL 0
+
class LLVBOPool
{
public:
@@ -316,13 +299,42 @@ public:
Pool mVBOPool;
Pool mIBOPool;
- U32 mMissCount = 0;
+ U32 mTouchCount = 0;
+
+#if ANALYZE_VBO_POOL
+ U64 mDistributed = 0;
+ U64 mAllocated = 0;
+ U64 mReserved = 0;
+ U32 mMisses = 0;
+ U32 mHits = 0;
+#endif
+
+ // increase the size to some common value (e.g. a power of two) to increase hit rate
+ void adjustSize(U32& size)
+ {
+ // size = nhpo2(size); // (193/303)/580 MB (distributed/allocated)/reserved in VBO Pool. Overhead: 66 percent. Hit rate: 77 percent
+
+ //(245/276)/385 MB (distributed/allocated)/reserved in VBO Pool. Overhead: 57 percent. Hit rate: 69 percent
+ //(187/209)/397 MB (distributed/allocated)/reserved in VBO Pool. Overhead: 112 percent. Hit rate: 76 percent
+ U32 block_size = llmax(nhpo2(size) / 8, (U32) 16);
+ size += block_size - (size % block_size);
+ }
void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-
- size = nhpo2(size);
+ llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
+ llassert(name == 0); // non zero name indicates a gl name that wasn't freed
+ llassert(data == nullptr); // non null data indicates a buffer that wasn't freed
+ llassert(size >= 2); // any buffer size smaller than a single index is nonsensical
+
+#if ANALYZE_VBO_POOL
+ mDistributed += size;
+ adjustSize(size);
+ mAllocated += size;
+#else
+ adjustSize(size);
+#endif
auto& pool = type == GL_ELEMENT_ARRAY_BUFFER ? mIBOPool : mVBOPool;
@@ -332,13 +344,9 @@ public:
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vbo pool miss");
LL_PROFILE_GPU_ZONE("vbo alloc");
- ++mMissCount;
- if (mMissCount > 1024)
- { //clean cache on every 1024 misses
- mMissCount = 0;
- clean();
- }
-
+#if ANALYZE_VBO_POOL
+ mMisses++;
+#endif
name = gen_buffer();
glBindBuffer(type, name);
glBufferData(type, size, nullptr, GL_DYNAMIC_DRAW);
@@ -355,22 +363,47 @@ public:
}
else
{
+#if ANALYZE_VBO_POOL
+ mHits++;
+ llassert(mReserved >= size); // assert if accounting gets messed up
+ mReserved -= size;
+#endif
+
std::list<Entry>& entries = iter->second;
Entry& entry = entries.back();
name = entry.mGLName;
data = entry.mData;
-
+
entries.pop_back();
if (entries.empty())
{
pool.erase(iter);
}
}
+
+ clean();
}
void free(GLenum type, U32 size, GLuint name, U8* data)
{
- size = nhpo2(size);
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+ llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
+ llassert(size >= 2);
+ llassert(name != 0);
+ llassert(data != nullptr);
+
+ clean();
+
+#if ANALYZE_VBO_POOL
+ llassert(mDistributed >= size);
+ mDistributed -= size;
+ adjustSize(size);
+ llassert(mAllocated >= size);
+ mAllocated -= size;
+ mReserved += size;
+#else
+ adjustSize(size);
+#endif
auto& pool = type == GL_ELEMENT_ARRAY_BUFFER ? mIBOPool : mVBOPool;
@@ -386,10 +419,19 @@ public:
{
iter->second.push_front({ data, name, std::chrono::steady_clock::now() });
}
+
}
+ // clean periodically (clean gets called for every alloc/free)
void clean()
{
+ mTouchCount++;
+ if (mTouchCount < 1024) // clean every 1k touches
+ {
+ return;
+ }
+ mTouchCount = 0;
+
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
std::unordered_map<U32, std::list<Entry>>* pools[] = { &mVBOPool, &mIBOPool };
@@ -410,7 +452,12 @@ public:
auto& entry = entries.back();
ll_aligned_free_16(entry.mData);
glDeleteBuffers(1, &entry.mGLName);
+#if ANALYZE_VBO_POOL
+ llassert(mReserved >= iter->first);
+ mReserved -= iter->first;
+#endif
entries.pop_back();
+
}
if (entries.empty())
@@ -423,6 +470,16 @@ public:
}
}
}
+
+#if ANALYZE_VBO_POOL
+ LL_INFOS() << llformat("(%d/%d)/%d MB (distributed/allocated)/total in VBO Pool. Overhead: %d percent. Hit rate: %d percent",
+ mDistributed / 1000000,
+ mAllocated / 1000000,
+ (mAllocated + mReserved) / 1000000, // total bytes
+ ((mAllocated+mReserved-mDistributed)*100)/llmax(mDistributed, (U64) 1), // overhead percent
+ (mHits*100)/llmax(mMisses+mHits, (U32)1)) // hit rate percent
+ << LL_ENDL;
+#endif
}
void clear()
@@ -445,6 +502,10 @@ public:
}
}
+#if ANALYZE_VBO_POOL
+ mReserved = 0;
+#endif
+
mIBOPool.clear();
mVBOPool.clear();
}
@@ -457,35 +518,14 @@ static LLVBOPool* sVBOPool = nullptr;
//============================================================================
//
//static
-std::list<U32> LLVertexBuffer::sAvailableVAOName;
-U32 LLVertexBuffer::sCurVAOName = 1;
-
-U32 LLVertexBuffer::sAllocatedIndexBytes = 0;
-U32 LLVertexBuffer::sIndexCount = 0;
-
-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;
U32 LLVertexBuffer::sGLRenderBuffer = 0;
-U32 LLVertexBuffer::sGLRenderArray = 0;
U32 LLVertexBuffer::sGLRenderIndices = 0;
U32 LLVertexBuffer::sLastMask = 0;
-bool LLVertexBuffer::sVBOActive = false;
-bool LLVertexBuffer::sIBOActive = false;
-U32 LLVertexBuffer::sAllocatedBytes = 0;
U32 LLVertexBuffer::sVertexCount = 0;
-bool LLVertexBuffer::sMapped = false;
-bool LLVertexBuffer::sUseStreamDraw = true;
-bool LLVertexBuffer::sUseVAO = false;
-bool LLVertexBuffer::sPreferStreamDraw = false;
//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware
-const S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
+const U32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
{
sizeof(LLVector4), // TYPE_VERTEX,
sizeof(LLVector4), // TYPE_NORMAL,
@@ -534,62 +574,34 @@ const U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
};
//static
-U32 LLVertexBuffer::getVAOName()
-{
- U32 ret = 0;
-
- if (!sAvailableVAOName.empty())
- {
- 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)
+void LLVertexBuffer::setupClientArrays(U32 data_mask)
{
- sAvailableVAOName.push_back(name);
-}
+ if (sLastMask != data_mask)
+ {
+ for (U32 i = 0; i < TYPE_MAX; ++i)
+ {
+ S32 loc = i;
+ U32 mask = 1 << i;
-//static
-void LLVertexBuffer::setupClientArrays(U32 data_mask)
-{
- if (sLastMask != data_mask)
- {
+ if (sLastMask & (1 << i))
+ { //was enabled
+ if (!(data_mask & mask))
+ { //needs to be disabled
+ glDisableVertexAttribArray(loc);
+ }
+ }
+ else
+ { //was disabled
+ if (data_mask & mask)
+ { //needs to be enabled
+ glEnableVertexAttribArray(loc);
+ }
+ }
+ }
+ }
- 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
- glDisableVertexAttribArray(loc);
- }
- }
- else
- { //was disabled
- if (data_mask & mask)
- { //needs to be enabled
- glEnableVertexAttribArray(loc);
- }
- }
- }
-
- sLastMask = data_mask;
- }
+ sLastMask = data_mask;
}
//static
@@ -606,7 +618,7 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
}
//static
-void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
+void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, U32 num_indices, const U16* indicesp)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
@@ -644,8 +656,13 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
gGL.flush();
}
-void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
+bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
{
+ if (!gDebugGL)
+ {
+ return true;
+ }
+
llassert(start < (U32)mNumVerts);
llassert(end < (U32)mNumVerts);
@@ -663,9 +680,8 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
LL_ERRS() << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << LL_ENDL;
}
- if (gDebugGL && !useVBOs())
{
- U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+ U16* idx = (U16*) mMappedIndexData+indices_offset;
for (U32 i = 0; i < count; ++i)
{
llassert(idx[i] >= start);
@@ -681,22 +697,20 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
if (shader && shader->mFeatures.mIndexedTextureChannels > 1)
{
- LLStrider<LLVector4a> v;
- //hack to get non-const reference
- LLVertexBuffer* vb = (LLVertexBuffer*) this;
- vb->getVertexStrider(v);
-
+ LLVector4a* v = (LLVector4a*) mMappedData;
+
for (U32 i = start; i < end; i++)
{
- S32 idx = (S32) (v[i][3]+0.25f);
- llassert(idx >= 0);
- if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels)
+ U32 idx = (U32) (v[i][3]+0.25f);
+ if (idx >= shader->mFeatures.mIndexedTextureChannels)
{
LL_ERRS() << "Bad texture index found in vertex data stream." << LL_ENDL;
}
}
}
}
+
+ return true;
}
#ifdef LL_PROFILER_ENABLE_RENDER_DOC
@@ -707,124 +721,35 @@ void LLVertexBuffer::setLabel(const char* label) {
void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
{
- validateRange(start, end, count, indices_offset);
- gGL.syncMatrices();
-
- llassert(mNumVerts >= 0);
- llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
-
- if (mGLIndices != sGLRenderIndices)
- {
- LL_ERRS() << "Wrong index buffer bound." << LL_ENDL;
- }
-
- if (mGLBuffer != sGLRenderBuffer)
- {
- LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
- }
-
- if (gDebugGL && useVBOs())
- {
- GLint elem = 0;
- glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
-
- if (elem != mGLIndices)
- {
- LL_ERRS() << "Wrong index buffer bound!" << LL_ENDL;
- }
- }
-
- if (mode >= LLRender::NUM_MODES)
- {
- LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
- return;
- }
-
- U16* idx = ((U16*) getIndicesPointer())+indices_offset;
-
- glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
- idx);
-}
-
-void LLVertexBuffer::drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
-{
+ llassert(validateRange(start, end, count, indices_offset));
+ llassert(mGLBuffer == sGLRenderBuffer);
+ llassert(mGLIndices == sGLRenderIndices);
gGL.syncMatrices();
- U16* idx = ((U16*)getIndicesPointer()) + indices_offset;
-
- glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
- idx);
+ glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
+ (GLvoid*) (indices_offset * sizeof(U16)));
}
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
{
- llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
- gGL.syncMatrices();
-
- llassert(mNumIndices >= 0);
- if (indices_offset >= (U32) mNumIndices ||
- indices_offset + count > (U32) mNumIndices)
- {
- LL_ERRS() << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << LL_ENDL;
- }
-
-
- if (mGLIndices != sGLRenderIndices)
- {
- LL_ERRS() << "Wrong index buffer bound." << LL_ENDL;
- }
-
- if (mGLBuffer != sGLRenderBuffer)
- {
- LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
- }
-
- if (mode >= LLRender::NUM_MODES)
- {
- LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
- return;
- }
-
- glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
- ((U16*) getIndicesPointer()) + indices_offset);
+ drawRange(mode, 0, mNumVerts, count, indices_offset);
}
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
- llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
+ llassert(first + count <= mNumVerts);
+ llassert(mGLBuffer == sGLRenderBuffer);
+ llassert(mGLIndices == sGLRenderIndices);
+
gGL.syncMatrices();
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- llassert(mNumVerts >= 0);
- if (first >= (U32) mNumVerts ||
- first + count > (U32) mNumVerts)
- {
- LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << LL_ENDL;
- }
-
- if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
- {
- LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
- }
-
- if (mode >= LLRender::NUM_MODES)
- {
- LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
- return;
- }
-#endif
-
glDrawArrays(sGLMode[mode], first, count);
}
//static
void LLVertexBuffer::initClass(LLWindow* window)
{
- sEnableVBOs = true;
- sDisableVBOMapping = true;
-
+ llassert(sVBOPool == nullptr);
sVBOPool = new LLVBOPool();
#if ENABLE_GL_WORK_QUEUE
@@ -841,29 +766,11 @@ void LLVertexBuffer::initClass(LLWindow* window)
//static
void LLVertexBuffer::unbind()
{
- if (sGLRenderArray)
- {
- glBindVertexArray(0);
- sGLRenderArray = 0;
- sGLRenderIndices = 0;
- sIBOActive = false;
- }
-
- if (sVBOActive)
- {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- sVBOActive = false;
- }
- if (sIBOActive)
- {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- sIBOActive = false;
- }
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
sGLRenderBuffer = 0;
sGLRenderIndices = 0;
-
- setupClientArrays(0);
}
//static
@@ -886,67 +793,26 @@ void LLVertexBuffer::cleanupClass()
delete sQueue;
sQueue = nullptr;
#endif
-
- //llassert(0 == sAllocatedBytes);
- //llassert(0 == sAllocatedIndexBytes);
}
//----------------------------------------------------------------------------
-S32 LLVertexBuffer::determineUsage(S32 usage)
-{
- S32 ret_usage = usage;
-
- if (!sEnableVBOs)
- {
- ret_usage = 0;
- }
-
- if (ret_usage == GL_STREAM_DRAW && !sUseStreamDraw)
- {
- ret_usage = 0;
- }
-
- // dynamic draw or nothing
- ret_usage = GL_DYNAMIC_DRAW;
-
- return ret_usage;
-}
-
-LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage)
+LLVertexBuffer::LLVertexBuffer(U32 typemask)
: LLRefCount(),
-
- mNumVerts(0),
- mNumIndices(0),
- mSize(0),
- mIndicesSize(0),
- mTypeMask(typemask),
- mUsage(LLVertexBuffer::determineUsage(usage)),
- mGLBuffer(0),
- mGLIndices(0),
- mMappedData(NULL),
- mMappedIndexData(NULL),
- mMappedDataUsingVBOs(false),
- mMappedIndexDataUsingVBOs(false),
- mVertexLocked(false),
- mIndexLocked(false),
- mFinal(false),
- mEmpty(true)
+ mTypeMask(typemask)
{
//zero out offsets
for (U32 i = 0; i < TYPE_MAX; i++)
{
mOffsets[i] = 0;
}
-
- sCount++;
}
//static
-S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)
+U32 LLVertexBuffer::calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices)
{
- S32 offset = 0;
- for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++)
+ U32 offset = 0;
+ for (U32 i=0; i<TYPE_TEXTURE_INDEX; i++)
{
U32 mask = 1<<i;
if (typemask & mask)
@@ -966,10 +832,10 @@ S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_verti
}
//static
-S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
+U32 LLVertexBuffer::calcVertexSize(const U32& typemask)
{
- S32 size = 0;
- for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++)
+ U32 size = 0;
+ for (U32 i = 0; i < TYPE_TEXTURE_INDEX; i++)
{
U32 mask = 1<<i;
if (typemask & mask)
@@ -981,11 +847,6 @@ S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
return size;
}
-S32 LLVertexBuffer::getSize() const
-{
- return mSize;
-}
-
// protected, use unref()
//virtual
LLVertexBuffer::~LLVertexBuffer()
@@ -993,11 +854,6 @@ LLVertexBuffer::~LLVertexBuffer()
destroyGLBuffer();
destroyGLIndices();
- sCount--;
-
- sVertexCount -= mNumVerts;
- sIndexCount -= mNumIndices;
-
if (mMappedData)
{
LL_ERRS() << "Failed to clear vertex buffer's vertices" << LL_ENDL;
@@ -1013,57 +869,32 @@ LLVertexBuffer::~LLVertexBuffer()
void LLVertexBuffer::genBuffer(U32 size)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-
- mSize = size;
+ llassert(sVBOPool);
if (sVBOPool)
{
- sVBOPool->allocate(GL_ARRAY_BUFFER, size, mGLBuffer, mMappedData);
- }
-
- sGLCount++;
-}
-
-void LLVertexBuffer::genIndices(U32 size)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-
- mIndicesSize = size;
+ llassert(mSize == 0);
+ llassert(mGLBuffer == 0);
+ llassert(mMappedData == nullptr);
- if (sVBOPool)
- {
- sVBOPool->allocate(GL_ELEMENT_ARRAY_BUFFER, size, mGLIndices, mMappedIndexData);
+ mSize = size;
+ sVBOPool->allocate(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData);
}
- sGLCount++;
}
-void LLVertexBuffer::releaseBuffer()
+void LLVertexBuffer::genIndices(U32 size)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+ llassert(sVBOPool);
if (sVBOPool)
{
- sVBOPool->free(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData);
- }
-
- mGLBuffer = 0;
- mMappedData = nullptr;
-
- sGLCount--;
-}
-
-void LLVertexBuffer::releaseIndices()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-
- if (sVBOPool)
- {
- sVBOPool->free(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices, mMappedIndexData);
+ llassert(mIndicesSize == 0);
+ llassert(mGLIndices == 0);
+ llassert(mMappedIndexData == nullptr);
+ mIndicesSize = size;
+ sVBOPool->allocate(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices, mMappedIndexData);
}
-
- mMappedIndexData = nullptr;
-
- sGLCount--;
}
bool LLVertexBuffer::createGLBuffer(U32 size)
@@ -1080,23 +911,8 @@ bool LLVertexBuffer::createGLBuffer(U32 size)
bool success = true;
- mEmpty = true;
-
- mMappedDataUsingVBOs = useVBOs();
+ genBuffer(size);
- if (mMappedDataUsingVBOs)
- {
- genBuffer(size);
- }
- else
- {
- static int gl_buffer_idx = 0;
- mGLBuffer = ++gl_buffer_idx;
-
- mMappedData = (U8*)ll_aligned_malloc_16(size);
- mSize = size;
- }
-
if (!mMappedData)
{
success = false;
@@ -1118,27 +934,8 @@ bool LLVertexBuffer::createGLIndices(U32 size)
bool success = true;
- mEmpty = true;
-
- //pad by 16 bytes for aligned copies
- size += 16;
-
- mMappedIndexDataUsingVBOs = useVBOs();
-
- if (mMappedIndexDataUsingVBOs)
- {
- //pad by another 16 bytes for VBO pointer adjustment
- size += 16;
- genIndices(size);
- }
- else
- {
- mMappedIndexData = (U8*)ll_aligned_malloc_16(size);
- static int gl_buffer_idx = 0;
- mGLIndices = ++gl_buffer_idx;
- mIndicesSize = size;
- }
-
+ genIndices(size);
+
if (!mMappedIndexData)
{
success = false;
@@ -1150,43 +947,37 @@ void LLVertexBuffer::destroyGLBuffer()
{
if (mGLBuffer || mMappedData)
{
- if (mMappedDataUsingVBOs)
- {
- releaseBuffer();
- }
- else
- {
- ll_aligned_free_16((void*)mMappedData);
- mMappedData = NULL;
- mEmpty = true;
- }
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+ //llassert(sVBOPool);
+ if (sVBOPool)
+ {
+ sVBOPool->free(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData);
+ }
+
+ mSize = 0;
+ mGLBuffer = 0;
+ mMappedData = nullptr;
}
-
- mGLBuffer = 0;
- //unbind();
}
void LLVertexBuffer::destroyGLIndices()
{
if (mGLIndices || mMappedIndexData)
{
- if (mMappedIndexDataUsingVBOs)
- {
- releaseIndices();
- }
- else
- {
- ll_aligned_free_16((void*)mMappedIndexData);
- mMappedIndexData = NULL;
- mEmpty = true;
- }
- }
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+ //llassert(sVBOPool);
+ if (sVBOPool)
+ {
+ sVBOPool->free(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices, mMappedIndexData);
+ }
- mGLIndices = 0;
- //unbind();
+ mIndicesSize = 0;
+ mGLIndices = 0;
+ mMappedIndexData = nullptr;
+ }
}
-bool LLVertexBuffer::updateNumVerts(S32 nverts)
+bool LLVertexBuffer::updateNumVerts(U32 nverts)
{
llassert(nverts >= 0);
@@ -1200,19 +991,17 @@ bool LLVertexBuffer::updateNumVerts(S32 nverts)
U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
- if (needed_size > mSize || needed_size <= mSize/2)
- {
- success &= createGLBuffer(needed_size);
- }
+ if (needed_size != mSize)
+ {
+ success &= createGLBuffer(needed_size);
+ }
- sVertexCount -= mNumVerts;
+ llassert(mSize == needed_size);
mNumVerts = nverts;
- sVertexCount += mNumVerts;
-
return success;
}
-bool LLVertexBuffer::updateNumIndices(S32 nindices)
+bool LLVertexBuffer::updateNumIndices(U32 nindices)
{
llassert(nindices >= 0);
@@ -1220,22 +1009,18 @@ bool LLVertexBuffer::updateNumIndices(S32 nindices)
U32 needed_size = sizeof(U16) * nindices;
- if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2)
+ if (needed_size != mIndicesSize)
{
success &= createGLIndices(needed_size);
}
- sIndexCount -= mNumIndices;
+ llassert(mIndicesSize == needed_size);
mNumIndices = nindices;
- sIndexCount += mNumIndices;
-
return success;
}
-bool LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
+bool LLVertexBuffer::allocateBuffer(U32 nverts, U32 nindices)
{
- stop_glerror();
-
if (nverts < 0 || nindices < 0 ||
nverts > 65536)
{
@@ -1247,44 +1032,14 @@ bool LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
success &= updateNumVerts(nverts);
success &= updateNumIndices(nindices);
- if (create && (nverts || nindices))
- {
- //actually allocate space for the vertex buffer if using VBO mapping
- flush(); //unmap
- }
-
return success;
}
-bool LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
-{
- llassert(newnverts >= 0);
- llassert(newnindices >= 0);
-
- bool success = true;
-
- success &= updateNumVerts(newnverts);
- success &= updateNumIndices(newnindices);
-
- if (useVBOs())
- {
- flush(); //unmap
- }
-
- return success;
-}
-
-bool LLVertexBuffer::useVBOs() const
-{
- //it's generally ineffective to use VBO for things that are streaming on apple
- return (mUsage != 0);
-}
-
//----------------------------------------------------------------------------
// if no gap between region and given range exists, expand region to cover given range and return true
// otherwise return false
-bool expand_region(LLVertexBuffer::MappedRegion& region, S32 start, S32 end)
+bool expand_region(LLVertexBuffer::MappedRegion& region, U32 start, U32 end)
{
if (end < region.mStart ||
@@ -1301,152 +1056,79 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 start, S32 end)
// Map for data access
-U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
+U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 index, S32 count)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
- if (mFinal)
- {
- LL_ERRS() << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << LL_ENDL;
- }
- if (!useVBOs() && !mMappedData && !mMappedIndexData)
- {
- LL_ERRS() << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << LL_ENDL;
- }
+
+ if (count == -1)
+ {
+ count = mNumVerts - index;
+ }
+ U32 start = mOffsets[type] + sTypeSize[type] * index;
+ U32 end = start + sTypeSize[type] * count-1;
- if (useVBOs())
- {
- if (count == -1)
+ bool flagged = false;
+ // flag region as mapped
+ for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
+ {
+ MappedRegion& region = mMappedVertexRegions[i];
+ if (expand_region(region, start, end))
{
- count = mNumVerts - index;
+ flagged = true;
+ break;
}
-
- S32 start = mOffsets[type] + sTypeSize[type] * index;
- S32 end = start + sTypeSize[type] * count;
-
- bool flagged = false;
- // flag region as mapped
- for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
- {
- MappedRegion& region = mMappedVertexRegions[i];
- if (expand_region(region, start, end))
- {
- flagged = true;
- break;
- }
- }
-
- if (!flagged)
- {
- //didn't expand an existing region, make a new one
- mMappedVertexRegions.push_back({ start, end });
- }
-
- if (mVertexLocked && map_range)
- {
- LL_ERRS() << "Attempted to map a specific range of a buffer that was already mapped." << LL_ENDL;
- }
-
- if (!mVertexLocked)
- {
- mVertexLocked = true;
- sMappedCount++;
- stop_glerror();
-
- map_range = false;
-
- if (!mMappedData)
- {
- log_glerror();
-
- //check the availability of memory
- LLMemory::logMemoryInfo(true);
-
- LL_ERRS() << "memory allocation for vertex data failed." << LL_ENDL;
-
- }
- }
}
- else
+
+ if (!flagged)
{
- map_range = false;
+ //didn't expand an existing region, make a new one
+ mMappedVertexRegions.push_back({ start, end });
}
return mMappedData+mOffsets[type]+sTypeSize[type]*index;
}
-U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
+U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
- if (mFinal)
- {
- LL_ERRS() << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << LL_ENDL;
- }
- if (!useVBOs() && !mMappedData && !mMappedIndexData)
+
+ if (count == -1)
{
- LL_ERRS() << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << LL_ENDL;
+ count = mNumIndices-index;
}
- if (useVBOs())
- {
- if (count == -1)
- {
- count = mNumIndices-index;
- }
-
- S32 start = sizeof(U16) * index;
- S32 end = start + sizeof(U16) * count;
-
- bool flagged = false;
- // flag region as mapped
- for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
- {
- MappedRegion& region = mMappedIndexRegions[i];
- if (expand_region(region, start, end))
- {
- flagged = true;
- break;
- }
- }
+ U32 start = sizeof(U16) * index;
+ U32 end = start + sizeof(U16) * count-1;
- if (!flagged)
+ bool flagged = false;
+ // flag region as mapped
+ for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+ {
+ MappedRegion& region = mMappedIndexRegions[i];
+ if (expand_region(region, start, end))
{
- //didn't expand an existing region, make a new one
- mMappedIndexRegions.push_back({ start, end });
+ flagged = true;
+ break;
}
+ }
- if (mIndexLocked && map_range)
- {
- LL_ERRS() << "Attempted to map a specific range of a buffer that was already mapped." << LL_ENDL;
- }
-
- if (!mIndexLocked)
- {
- mIndexLocked = true;
- sMappedCount++;
- stop_glerror();
-
- map_range = false;
- }
-
- if (!mMappedIndexData)
- {
- log_glerror();
- LLMemory::logMemoryInfo(true);
-
- LL_ERRS() << "memory allocation for Index data failed. " << LL_ENDL;
- }
- }
- else
- {
- map_range = false;
- }
+ if (!flagged)
+ {
+ //didn't expand an existing region, make a new one
+ mMappedIndexRegions.push_back({ start, end });
+ }
return mMappedIndexData + sizeof(U16)*index;
}
-static void flush_vbo(GLenum target, S32 start, S32 end, void* data)
+// flush the given byte range
+// target -- "targret" parameter for glBufferSubData
+// start -- first byte to copy
+// end -- last byte to copy (NOT last byte + 1)
+// data -- mMappedData or mMappedIndexData
+static void flush_vbo(GLenum target, U32 start, U32 end, void* data)
{
if (end != 0)
{
@@ -1455,122 +1137,109 @@ static void flush_vbo(GLenum target, S32 start, S32 end, void* data)
LL_PROFILE_ZONE_NUM(end);
LL_PROFILE_ZONE_NUM(end-start);
- constexpr S32 block_size = 65536;
+ constexpr U32 block_size = 8192;
- for (S32 i = start; i < end; i += block_size)
+ for (U32 i = start; i <= end; i += block_size)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
- LL_PROFILE_GPU_ZONE("glBufferSubData");
- S32 tend = llmin(i + block_size, end);
- glBufferSubData(target, i, tend - i, (U8*) data + (i-start));
+ //LL_PROFILE_GPU_ZONE("glBufferSubData");
+ U32 tend = llmin(i + block_size, end);
+ glBufferSubData(target, i, tend - i+1, (U8*) data + (i-start));
}
}
}
void LLVertexBuffer::unmapBuffer()
{
- if (!useVBOs())
- {
- return; //nothing to unmap
- }
+ struct SortMappedRegion
+ {
+ bool operator()(const MappedRegion& lhs, const MappedRegion& rhs)
+ {
+ return lhs.mStart < rhs.mStart;
+ }
+ };
- bool updated_all = false;
- LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
- if (mMappedData && mVertexLocked)
+ if (!mMappedVertexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
- bindGLBuffer(true);
- updated_all = mIndexLocked; //both vertex and index buffers done updating
-
- if (!mMappedVertexRegions.empty())
- {
- S32 start = 0;
- S32 end = 0;
-
- for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
- {
- const MappedRegion& region = mMappedVertexRegions[i];
- if (region.mStart == end + 1)
- {
- end = region.mEnd;
- }
- else
- {
- flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
- start = region.mStart;
- end = region.mEnd;
- }
- }
+ if (sGLRenderBuffer != mGLBuffer)
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
+ sGLRenderBuffer = mGLBuffer;
+ }
+
+ U32 start = 0;
+ U32 end = 0;
- flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
+ std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion());
- mMappedVertexRegions.clear();
- }
- else
+ for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
{
- llassert(false); // this shouldn't happen -- a buffer must always be explicitly mapped
+ const MappedRegion& region = mMappedVertexRegions[i];
+ if (region.mStart == end + 1)
+ {
+ end = region.mEnd;
+ }
+ else
+ {
+ flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
+ start = region.mStart;
+ end = region.mEnd;
+ }
}
-
- mVertexLocked = false;
- sMappedCount--;
+
+ flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
+
+ mMappedVertexRegions.clear();
}
- if (mMappedIndexData && mIndexLocked)
+ if (!mMappedIndexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
- bindGLIndices();
-
- if (!mMappedIndexRegions.empty())
- {
- S32 start = 0;
- S32 end = 0;
- for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+ if (mGLIndices != sGLRenderIndices)
+ {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
+ sGLRenderIndices = mGLIndices;
+ }
+ U32 start = 0;
+ U32 end = 0;
+
+ std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion());
+
+ for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+ {
+ const MappedRegion& region = mMappedIndexRegions[i];
+ if (region.mStart == end + 1)
{
- const MappedRegion& region = mMappedIndexRegions[i];
- if (region.mStart == end + 1)
- {
- end = region.mEnd;
- }
- else
- {
- flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start);
- start = region.mStart;
- end = region.mEnd;
- }
+ end = region.mEnd;
}
+ else
+ {
+ flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start);
+ start = region.mStart;
+ end = region.mEnd;
+ }
+ }
- flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start);
-
- mMappedIndexRegions.clear();
- }
- else
- {
- llassert(false); // this shouldn't happen -- a buffer must always be explicitly mapped
- }
-
- mIndexLocked = false;
- sMappedCount--;
- }
+ flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start);
- if(updated_all)
- {
- mEmpty = false;
+ mMappedIndexRegions.clear();
}
}
//----------------------------------------------------------------------------
-template <class T,S32 type> struct VertexBufferStrider
+template <class T,LLVertexBuffer::AttributeType type> struct VertexBufferStrider
{
typedef LLStrider<T> strider_t;
static bool get(LLVertexBuffer& vbo,
strider_t& strider,
- S32 index, S32 count, bool map_range)
+ S32 index, S32 count)
{
if (type == LLVertexBuffer::TYPE_INDEX)
{
- U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
+ U8* ptr = vbo.mapIndexBuffer(index, count);
if (ptr == NULL)
{
@@ -1584,9 +1253,9 @@ template <class T,S32 type> struct VertexBufferStrider
}
else if (vbo.hasDataType(type))
{
- S32 stride = LLVertexBuffer::sTypeSize[type];
+ U32 stride = LLVertexBuffer::sTypeSize[type];
- U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
+ U8* ptr = vbo.mapVertexBuffer(type, index, count);
if (ptr == NULL)
{
@@ -1606,500 +1275,157 @@ template <class T,S32 type> struct VertexBufferStrider
}
};
-bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector4a>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLVector4a,TYPE_TANGENT>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector4a,TYPE_TANGENT>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count);
}
-bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, U32 index, S32 count)
{
- return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count, map_range);
+ return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count);
}
//----------------------------------------------------------------------------
-bool LLVertexBuffer::bindGLBuffer(bool force_bind)
+
+// Set for rendering
+void LLVertexBuffer::setBuffer()
{
- bool ret = false;
+ // no data may be pending
+ llassert(mMappedVertexRegions.empty());
+ llassert(mMappedIndexRegions.empty());
- if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
- {
- LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
- glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
- sGLRenderBuffer = mGLBuffer;
- sBindCount++;
- sVBOActive = true;
- ret = true;
- }
+ // a shader must be bound
+ llassert(LLGLSLShader::sCurBoundShaderPtr);
- return ret;
-}
+ U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
-bool LLVertexBuffer::bindGLBufferFast()
-{
- if (mGLBuffer != sGLRenderBuffer || !sVBOActive)
+ // this Vertex Buffer must provide all necessary attributes for currently bound shader
+ llassert(((~data_mask & mTypeMask) > 0) || (mTypeMask == data_mask));
+
+ if (sGLRenderBuffer != mGLBuffer)
{
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
- sBindCount++;
- sVBOActive = true;
- return true;
- }
-
- return false;
-}
-
-bool LLVertexBuffer::bindGLIndices(bool force_bind)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-
- bool ret = false;
- if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))))
- {
- /*if (sMapped)
- {
- LL_ERRS() << "VBO bound while another VBO mapped!" << LL_ENDL;
- }*/
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
- sGLRenderIndices = mGLIndices;
- stop_glerror();
- sBindCount++;
- sIBOActive = true;
- ret = true;
- }
-
- return ret;
-}
-
-bool LLVertexBuffer::bindGLIndicesFast()
-{
- if (mGLIndices != sGLRenderIndices || !sIBOActive)
- {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
- sGLRenderIndices = mGLIndices;
- sBindCount++;
- sIBOActive = true;
-
- return true;
+ setupVertexBuffer();
}
-
- return false;
-}
-
-void LLVertexBuffer::flush(bool discard)
-{
- 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)
-{
- flush();
-
- //set up pointers if the data mask is different ...
- 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)
- {
- LL_WARNS() << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << LL_ENDL;
- }
-
- required_mask |= required;
- }
- }
-
- if ((data_mask & required_mask) != required_mask)
- {
-
- U32 unsatisfied_mask = (required_mask & ~data_mask);
-
- for (U32 i = 0; i < TYPE_MAX; i++)
- {
- U32 unsatisfied_flag = unsatisfied_mask & (1 << i);
- switch (unsatisfied_flag)
- {
- case 0: break;
- case MAP_VERTEX: LL_INFOS() << "Missing vert pos" << LL_ENDL; break;
- case MAP_NORMAL: LL_INFOS() << "Missing normals" << LL_ENDL; break;
- case MAP_TEXCOORD0: LL_INFOS() << "Missing TC 0" << LL_ENDL; break;
- case MAP_TEXCOORD1: LL_INFOS() << "Missing TC 1" << LL_ENDL; break;
- case MAP_TEXCOORD2: LL_INFOS() << "Missing TC 2" << LL_ENDL; break;
- case MAP_TEXCOORD3: LL_INFOS() << "Missing TC 3" << LL_ENDL; break;
- case MAP_COLOR: LL_INFOS() << "Missing vert color" << LL_ENDL; break;
- case MAP_EMISSIVE: LL_INFOS() << "Missing emissive" << LL_ENDL; break;
- case MAP_TANGENT: LL_INFOS() << "Missing tangent" << LL_ENDL; break;
- case MAP_WEIGHT: LL_INFOS() << "Missing weight" << LL_ENDL; break;
- case MAP_WEIGHT4: LL_INFOS() << "Missing weightx4" << LL_ENDL; break;
- case MAP_CLOTHWEIGHT: LL_INFOS() << "Missing clothweight" << LL_ENDL; break;
- case MAP_TEXTURE_INDEX: LL_INFOS() << "Missing tex index" << LL_ENDL; break;
- default: LL_INFOS() << "Missing who effin knows: " << unsatisfied_flag << LL_ENDL;
- }
- }
-
- // TYPE_INDEX is beyond TYPE_MAX, so check for it individually
- if (unsatisfied_mask & (1 << TYPE_INDEX))
- {
- LL_INFOS() << "Missing indices" << LL_ENDL;
- }
-
- LL_ERRS() << "Shader consumption mismatches data provision." << LL_ENDL;
- }
- }
- }
-
- if (useVBOs())
- {
- const bool bindBuffer = bindGLBuffer();
- const bool bindIndices = bindGLIndices();
-
- setup = setup || bindBuffer || bindIndices;
-
- if (gDebugGL)
- {
- GLint buff;
- glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buff);
- if ((GLuint)buff != mGLBuffer)
- {
- if (gDebugSession)
- {
- gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl;
- }
- else
- {
- LL_ERRS() << "Invalid GL vertex buffer bound: " << buff << LL_ENDL;
- }
- }
-
- if (mGLIndices)
- {
- glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buff);
- if ((GLuint)buff != mGLIndices)
- {
- if (gDebugSession)
- {
- gFailLog << "Invalid GL index buffer bound: " << buff << std::endl;
- }
- else
- {
- LL_ERRS() << "Invalid GL index buffer bound: " << buff << LL_ENDL;
- }
- }
- }
- }
-
-
- }
- else
- {
- if (sGLRenderArray)
- {
- glBindVertexArray(0);
- sGLRenderArray = 0;
- sGLRenderIndices = 0;
- sIBOActive = false;
- }
-
- if (mGLBuffer)
- {
- if (sVBOActive)
- {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- sBindCount++;
- sVBOActive = false;
- setup = true; // ... or a VBO is deactivated
- }
- if (sGLRenderBuffer != mGLBuffer)
- {
- sGLRenderBuffer = mGLBuffer;
- setup = true; // ... or a client memory pointer changed
- }
- }
- if (mGLIndices)
- {
- if (sIBOActive)
- {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- sBindCount++;
- sIBOActive = false;
- }
-
- sGLRenderIndices = mGLIndices;
- }
- }
-
- setupClientArrays(data_mask);
-
- if (mGLBuffer)
- {
- if (data_mask && setup)
- {
- setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
- sSetCount++;
- }
- }
-}
-
-void LLVertexBuffer::setBufferFast(U32 data_mask)
-{
- if (useVBOs())
+ else if (sLastMask != data_mask)
{
- //set up pointers if the data mask is different ...
- bool setup = (sLastMask != data_mask);
-
- const bool bindBuffer = bindGLBufferFast();
- const bool bindIndices = bindGLIndicesFast();
-
- setup = setup || bindBuffer || bindIndices;
-
- setupClientArrays(data_mask);
-
- if (data_mask && setup)
- {
- setupVertexBufferFast(data_mask);
- sSetCount++;
- }
+ setupVertexBuffer();
+ sLastMask = data_mask;
}
- else
+
+ if (mGLIndices != sGLRenderIndices)
{
- //fallback to slow path when not using VBOs
- setBuffer(data_mask);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
+ sGLRenderIndices = mGLIndices;
}
}
// virtual (default)
-void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
-{
- stop_glerror();
- U8* base = useVBOs() ? nullptr: mMappedData;
-
- if (gDebugGL && ((data_mask & mTypeMask) != data_mask))
- {
- for (U32 i = 0; i < LLVertexBuffer::TYPE_MAX; ++i)
- {
- U32 mask = 1 << i;
- if (mask & data_mask && !(mask & mTypeMask))
- { //bit set in data_mask, but not set in mTypeMask
- LL_WARNS() << "Missing required component " << vb_type_name[i] << LL_ENDL;
- }
- }
- LL_ERRS() << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << LL_ENDL;
- }
-
- if (data_mask & MAP_NORMAL)
- {
- S32 loc = TYPE_NORMAL;
- void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
- glVertexAttribPointer(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]);
- glVertexAttribPointer(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]);
- glVertexAttribPointer(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]);
- glVertexAttribPointer(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
- }
- if (data_mask & MAP_TANGENT)
- {
- S32 loc = TYPE_TANGENT;
- void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
- glVertexAttribPointer(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
- }
- if (data_mask & MAP_TEXCOORD0)
- {
- S32 loc = TYPE_TEXCOORD0;
- void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
- glVertexAttribPointer(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
- }
- if (data_mask & MAP_COLOR)
- {
- S32 loc = TYPE_COLOR;
- //bind emissive instead of color pointer if emissive is present
- void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
- glVertexAttribPointer(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]);
- glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
-
- if (!(data_mask & MAP_COLOR))
- { //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps
- loc = TYPE_COLOR;
- glVertexAttribPointer(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]);
- glVertexAttribPointer(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]);
- glVertexAttribPointer(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]);
- glVertexAttribPointer(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
- {
- S32 loc = TYPE_TEXTURE_INDEX;
- void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
- glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
- }
- if (data_mask & MAP_VERTEX)
- {
- S32 loc = TYPE_VERTEX;
- void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
- glVertexAttribPointer(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
- }
-
- llglassertok();
- }
-
-void LLVertexBuffer::setupVertexBufferFast(U32 data_mask)
+void LLVertexBuffer::setupVertexBuffer()
{
U8* base = nullptr;
+ U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
+
if (data_mask & MAP_NORMAL)
{
- S32 loc = TYPE_NORMAL;
+ AttributeType loc = TYPE_NORMAL;
void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
}
if (data_mask & MAP_TEXCOORD3)
{
- S32 loc = TYPE_TEXCOORD3;
+ AttributeType loc = TYPE_TEXCOORD3;
void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
}
if (data_mask & MAP_TEXCOORD2)
{
- S32 loc = TYPE_TEXCOORD2;
+ AttributeType loc = TYPE_TEXCOORD2;
void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
}
if (data_mask & MAP_TEXCOORD1)
{
- S32 loc = TYPE_TEXCOORD1;
+ AttributeType loc = TYPE_TEXCOORD1;
void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
}
if (data_mask & MAP_TANGENT)
{
- S32 loc = TYPE_TANGENT;
+ AttributeType loc = TYPE_TANGENT;
void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
}
if (data_mask & MAP_TEXCOORD0)
{
- S32 loc = TYPE_TEXCOORD0;
+ AttributeType loc = TYPE_TEXCOORD0;
void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
}
if (data_mask & MAP_COLOR)
{
- S32 loc = TYPE_COLOR;
+ AttributeType loc = TYPE_COLOR;
//bind emissive instead of color pointer if emissive is present
void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
}
if (data_mask & MAP_EMISSIVE)
{
- S32 loc = TYPE_EMISSIVE;
+ AttributeType loc = TYPE_EMISSIVE;
void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
@@ -2111,31 +1437,31 @@ void LLVertexBuffer::setupVertexBufferFast(U32 data_mask)
}
if (data_mask & MAP_WEIGHT)
{
- S32 loc = TYPE_WEIGHT;
+ AttributeType loc = TYPE_WEIGHT;
void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
glVertexAttribPointer(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
}
if (data_mask & MAP_WEIGHT4)
{
- S32 loc = TYPE_WEIGHT4;
+ AttributeType loc = TYPE_WEIGHT4;
void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT4]);
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
}
if (data_mask & MAP_CLOTHWEIGHT)
{
- S32 loc = TYPE_CLOTHWEIGHT;
+ AttributeType loc = TYPE_CLOTHWEIGHT;
void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
}
if (data_mask & MAP_TEXTURE_INDEX)
{
- S32 loc = TYPE_TEXTURE_INDEX;
+ AttributeType loc = TYPE_TEXTURE_INDEX;
void* ptr = (void*)(base + mOffsets[TYPE_VERTEX] + 12);
glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
}
if (data_mask & MAP_VERTEX)
{
- S32 loc = TYPE_VERTEX;
+ AttributeType loc = TYPE_VERTEX;
void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
}
@@ -2143,20 +1469,20 @@ void LLVertexBuffer::setupVertexBufferFast(U32 data_mask)
void LLVertexBuffer::setPositionData(const LLVector4a* data)
{
- bindGLBuffer();
- flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts(), (U8*) data);
+ llassert(sGLRenderBuffer == mGLBuffer);
+ flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data);
}
void LLVertexBuffer::setTexCoordData(const LLVector2* data)
{
- bindGLBuffer();
- flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts(), (U8*)data);
+ llassert(sGLRenderBuffer == mGLBuffer);
+ flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data);
}
void LLVertexBuffer::setColorData(const LLColor4U* data)
{
- bindGLBuffer();
- flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts(), (U8*) data);
+ llassert(sGLRenderBuffer == mGLBuffer);
+ flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts() - 1, (U8*) data);
}
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 926d37b052..571856f013 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -53,17 +53,16 @@
//============================================================================
// base class
class LLPrivateMemoryPool;
-class LLVertexBuffer : public LLRefCount
+class LLVertexBuffer final : public LLRefCount
{
public:
struct MappedRegion
{
- S32 mStart;
- S32 mEnd;
+ U32 mStart;
+ U32 mEnd;
};
LLVertexBuffer(const LLVertexBuffer& rhs)
- : mUsage(rhs.mUsage)
{
*this = rhs;
}
@@ -74,42 +73,31 @@ public:
return *this;
}
- static std::list<U32> sAvailableVAOName;
- static U32 sCurVAOName;
-
- static bool sUseStreamDraw;
- static bool sUseVAO;
- static bool sPreferStreamDraw;
-
- static U32 getVAOName();
- static void releaseVAOName(U32 name);
-
static void initClass(LLWindow* window);
static void cleanupClass();
static void setupClientArrays(U32 data_mask);
static void drawArrays(U32 mode, const std::vector<LLVector3>& pos);
- static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
+ static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, U32 num_indices, const U16* indicesp);
static void unbind(); //unbind any bound vertex buffer
//get the size of a vertex with the given typemask
- static S32 calcVertexSize(const U32& typemask);
+ static U32 calcVertexSize(const U32& typemask);
//get the size of a buffer with the given typemask and vertex count
//fill offsets with the offset of each vertex component array into the buffer
// indexed by the following enum
- static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices);
+ static U32 calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices);
//WARNING -- when updating these enums you MUST
// 1 - update LLVertexBuffer::sTypeSize
// 2 - update LLVertexBuffer::vb_type_name
// 3 - add a strider accessor
// 4 - modify LLVertexBuffer::setupVertexBuffer
- // 5 - modify LLVertexBuffer::setupVertexBufferFast
// 6 - modify LLViewerShaderMgr::mReservedAttribs
// clang-format off
- enum { // Shader attribute name, set in LLShaderMgr::initAttribsAndUniforms()
+ enum AttributeType { // Shader attribute name, set in LLShaderMgr::initAttribsAndUniforms()
TYPE_VERTEX = 0, // "position"
TYPE_NORMAL, // "normal"
TYPE_TEXCOORD0, // "texcoord0"
@@ -147,45 +135,37 @@ public:
protected:
friend class LLRender;
- virtual ~LLVertexBuffer(); // use unref()
+ ~LLVertexBuffer(); // use unref()
- virtual void setupVertexBuffer(U32 data_mask);
- void setupVertexBufferFast(U32 data_mask);
+ void setupVertexBuffer();
void genBuffer(U32 size);
void genIndices(U32 size);
- bool bindGLBuffer(bool force_bind = false);
- bool bindGLBufferFast();
- bool bindGLIndices(bool force_bind = false);
- bool bindGLIndicesFast();
- void releaseBuffer();
- void releaseIndices();
bool createGLBuffer(U32 size);
bool createGLIndices(U32 size);
void destroyGLBuffer();
void destroyGLIndices();
- bool updateNumVerts(S32 nverts);
- bool updateNumIndices(S32 nindices);
- void unmapBuffer();
-
+ bool updateNumVerts(U32 nverts);
+ bool updateNumIndices(U32 nindices);
+
public:
- LLVertexBuffer(U32 typemask, S32 usage);
+ LLVertexBuffer(U32 typemask);
- // map for data access
- U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
- U8* mapIndexBuffer(S32 index, S32 count, bool map_range);
+ // allocate buffer
+ bool allocateBuffer(U32 nverts, U32 nindices);
- void bindForFeedback(U32 channel, U32 type, U32 index, U32 count);
+ // map for data access (see also getFooStrider below)
+ U8* mapVertexBuffer(AttributeType type, U32 index, S32 count = -1);
+ U8* mapIndexBuffer(U32 index, S32 count = -1);
+ void unmapBuffer();
// set for rendering
- virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0
- void setBufferFast(U32 data_mask); // calls setupVertexBufferFast(), assumes data_mask is not 0 among other assumptions
-
- void flush(bool discard = false); //flush pending data to GL memory, if discard is true, discard previous VBO
- // allocate buffer
- bool allocateBuffer(S32 nverts, S32 nindices, bool create);
- virtual bool resizeBuffer(S32 newnverts, S32 newnindices);
-
+ // assumes (and will assert on) the following:
+ // - this buffer has no pending unampBuffer call
+ // - a shader is currently bound
+ // - This buffer has sufficient attributes within it to satisfy the needs of the currently bound shader
+ void setBuffer();
+
// Only call each getVertexPointer, etc, once before calling unmapBuffer()
// call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer()
// example:
@@ -193,57 +173,49 @@ public:
// vb->getNormalStrider(norms);
// 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 getTexCoord2Strider(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 getTangentStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getTangentStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getBasecolorTexcoordStrider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getNormalTexcoordStrider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getMetallicRoughnessTexcoordStrider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
- bool getEmissiveTexcoordStrider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool getVertexStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1);
+ bool getVertexStrider(LLStrider<LLVector4a>& strider, U32 index=0, S32 count = -1);
+ bool getIndexStrider(LLStrider<U16>& strider, U32 index=0, S32 count = -1);
+ bool getTexCoord0Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+ bool getTexCoord1Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+ bool getTexCoord2Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+ bool getNormalStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1);
+ bool getTangentStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1);
+ bool getTangentStrider(LLStrider<LLVector4a>& strider, U32 index=0, S32 count = -1);
+ bool getColorStrider(LLStrider<LLColor4U>& strider, U32 index=0, S32 count = -1);
+ bool getEmissiveStrider(LLStrider<LLColor4U>& strider, U32 index=0, S32 count = -1);
+ bool getWeightStrider(LLStrider<F32>& strider, U32 index=0, S32 count = -1);
+ bool getWeight4Strider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1);
+ bool getClothWeightStrider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1);
+ bool getBasecolorTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+ bool getNormalTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+ bool getMetallicRoughnessTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+ bool getEmissiveTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
void setPositionData(const LLVector4a* data);
void setTexCoordData(const LLVector2* data);
void setColorData(const LLColor4U* data);
- bool useVBOs() const;
- bool isEmpty() const { return mEmpty; }
- bool isLocked() const { return mVertexLocked || mIndexLocked; }
- S32 getNumVerts() const { return mNumVerts; }
- S32 getNumIndices() const { return mNumIndices; }
+ U32 getNumVerts() const { return mNumVerts; }
+ U32 getNumIndices() const { return mNumIndices; }
- U8* getIndicesPointer() const { return useVBOs() ? nullptr : mMappedIndexData; }
- U8* getVerticesPointer() const { return useVBOs() ? nullptr : mMappedData; }
U32 getTypeMask() const { return mTypeMask; }
- bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); }
- S32 getSize() const;
- S32 getIndicesSize() const { return mIndicesSize; }
+ bool hasDataType(AttributeType type) const { return ((1 << type) & getTypeMask()); }
+ U32 getSize() const { return mSize; }
+ U32 getIndicesSize() const { return mIndicesSize; }
U8* getMappedData() const { return mMappedData; }
U8* getMappedIndices() const { return mMappedIndexData; }
- S32 getOffset(S32 type) const { return mOffsets[type]; }
- S32 getUsage() const { return mUsage; }
- bool isWriteable() const { return (mUsage == GL_STREAM_DRAW) ? true : false; }
-
+ U32 getOffset(AttributeType type) const { return mOffsets[type]; }
+
+ // these functions assume (and assert on) the current VBO being bound
+ // Detailed error checking can be enabled by setting gDebugGL to true
void draw(U32 mode, U32 count, U32 indices_offset) const;
void drawArrays(U32 mode, U32 offset, U32 count) const;
- void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
-
- //implementation for inner loops that does no safety checking
- void drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
+ void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
//for debugging, validate data in given range is valid
- void validateRange(U32 start, U32 end, U32 count, U32 offset) const;
+ bool validateRange(U32 start, U32 end, U32 count, U32 offset) const;
#ifdef LL_PROFILER_ENABLE_RENDER_DOC
void setLabel(const char* label);
@@ -251,62 +223,45 @@ public:
protected:
- U32 mGLBuffer; // GL VBO handle
- U32 mGLIndices; // GL IBO handle
+ U32 mGLBuffer = 0; // GL VBO handle
+ U32 mGLIndices = 0; // GL IBO handle
+ U32 mNumVerts = 0; // Number of vertices allocated
+ U32 mNumIndices = 0; // Number of indices allocated
+ U32 mOffsets[TYPE_MAX]; // byte offsets into mMappedData of each attribute
- U32 mTypeMask;
+ U8* mMappedData = nullptr; // pointer to currently mapped data (NULL if unmapped)
+ U8* mMappedIndexData = nullptr; // pointer to currently mapped indices (NULL if unmapped)
- S32 mNumVerts; // Number of vertices allocated
- S32 mNumIndices; // Number of indices allocated
-
- S32 mSize;
- S32 mIndicesSize;
-
- const S32 mUsage; // GL usage
-
- U8* mMappedData; // pointer to currently mapped data (NULL if unmapped)
- 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.
+ U32 mTypeMask = 0; // bitmask of present vertex attributes
- S32 mOffsets[TYPE_MAX];
-
- std::vector<MappedRegion> mMappedVertexRegions;
- std::vector<MappedRegion> mMappedIndexRegions;
+ U32 mSize = 0; // size in bytes of mMappedData
+ U32 mIndicesSize = 0; // size in bytes of mMappedIndexData
- static S32 determineUsage(S32 usage);
+ std::vector<MappedRegion> mMappedVertexRegions; // list of mMappedData byte ranges that must be sent to GL
+ std::vector<MappedRegion> mMappedIndexRegions; // list of mMappedIndexData byte ranges that must be sent to GL
private:
- static LLPrivateMemoryPool* sPrivatePoolp;
+ // DEPRECATED
+ // These function signatures are deprecated, but for some reason
+ // there are classes in an external package that depend on LLVertexBuffer
+
+ // TODO: move these classes into viewer repository
+ friend class LLNavShapeVBOManager;
+ friend class LLNavMeshVBOManager;
+
+ LLVertexBuffer(U32 typemask, U32 usage)
+ : LLVertexBuffer(typemask)
+ {}
+
+ bool allocateBuffer(S32 nverts, S32 nindices, BOOL create) { return allocateBuffer(nverts, nindices); }
public:
- static S32 sCount;
- static S32 sGLCount;
- static S32 sMappedCount;
- static bool sMapped;
- typedef std::list<LLVertexBuffer*> buffer_list_t;
-
- static bool sDisableVBOMapping; //disable glMapBufferARB
- static bool sEnableVBOs;
- static const S32 sTypeSize[TYPE_MAX];
+ static const U32 sTypeSize[TYPE_MAX];
static const U32 sGLMode[LLRender::NUM_MODES];
static U32 sGLRenderBuffer;
- static U32 sGLRenderArray;
static U32 sGLRenderIndices;
- 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;
};
#ifdef LL_PROFILER_ENABLE_RENDER_DOC