Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion indra/llrender/llglslshader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,14 @@ void LLGLSLShader::bind()
{
sCurBoundShaderPtr->readProfileQuery();
}
LLVertexBuffer::unbind();
// Apple's OpenGL-on-Metal layer pays a high price for rebinding buffer
// objects on every shader transition. LLVertexBuffer tracks the
// attribute formats needed by the new shader, so the current buffer
// can remain bound until a draw actually selects a different one.
if (!gGLManager.mIsApple)
{
LLVertexBuffer::unbind();
}
glUseProgram(mProgramObject);
sCurBoundShader = mProgramObject;
sCurBoundShaderPtr = this;
Expand Down
75 changes: 50 additions & 25 deletions indra/llrender/llvertexbuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,15 @@ U32 LLVertexBuffer::sGLRenderIndices = 0;
U32 LLVertexBuffer::sLastMask = 0;
U32 LLVertexBuffer::sVertexCount = 0;

// The viewer keeps a single VAO bound. Attribute pointer calls store state in
// that VAO and capture the current array buffer. Track the formats configured
// for sGLRenderBuffer to avoid resubmitting identical state to OpenGL-on-Metal.
// If VAO switching is introduced, invalidate this cache when the VAO changes.
static U32 sVertexAttribsConfigured = 0;
static U32 sColorPointerSource = 0;
static constexpr U32 COLOR_POINTER_COLOR = 1;
static constexpr U32 COLOR_POINTER_EMISSIVE = 2;


//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware
const U32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
Expand Down Expand Up @@ -972,6 +981,8 @@ void LLVertexBuffer::unbind()
STOP_GLERROR;
sGLRenderBuffer = 0;
sGLRenderIndices = 0;
sVertexAttribsConfigured = 0;
sColorPointerSource = 0;
}

//static
Expand Down Expand Up @@ -1444,12 +1455,16 @@ void LLVertexBuffer::_unmapBuffer()
mGLBuffer = gen_buffer();
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
sVertexAttribsConfigured = 0;
sColorPointerSource = 0;
glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW);
}
else if (mGLBuffer != sGLRenderBuffer)
{
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
sVertexAttribsConfigured = 0;
sColorPointerSource = 0;
}
STOP_GLERROR;

Expand Down Expand Up @@ -1689,10 +1704,12 @@ void LLVertexBuffer::setBuffer()
{
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
sVertexAttribsConfigured = 0;
sColorPointerSource = 0;

setupVertexBuffer();
}
else if (sLastMask != data_mask)
else if (gGLManager.mIsApple || sLastMask != data_mask)
{
setupVertexBuffer();
sLastMask = data_mask;
Expand All @@ -1715,98 +1732,108 @@ void LLVertexBuffer::setupVertexBuffer()
U8* base = nullptr;

U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
U32 setup_mask = gGLManager.mIsApple ?
data_mask & ~sVertexAttribsConfigured : data_mask;

if (data_mask & MAP_NORMAL)
if (setup_mask & MAP_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)
if (setup_mask & MAP_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)
if (setup_mask & MAP_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)
if (setup_mask & MAP_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)
if (setup_mask & MAP_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)
if (setup_mask & MAP_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)
const U32 desired_color_source = (data_mask & MAP_EMISSIVE) ?
COLOR_POINTER_EMISSIVE :
((data_mask & MAP_COLOR) ? COLOR_POINTER_COLOR : 0);
if (desired_color_source &&
(!gGLManager.mIsApple || desired_color_source != sColorPointerSource))
{
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]);
void* ptr = desired_color_source == COLOR_POINTER_EMISSIVE ?
(void*)(base + mOffsets[TYPE_EMISSIVE]) :
(void*)(base + mOffsets[TYPE_COLOR]);
glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
sColorPointerSource = desired_color_source;
}
if (data_mask & MAP_EMISSIVE)
if (setup_mask & MAP_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);

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)
if (setup_mask & MAP_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)
if (setup_mask & MAP_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_JOINT)
if (setup_mask & MAP_JOINT)
{
AttributeType loc = TYPE_JOINT;
void* ptr = (void*)(base + mOffsets[TYPE_JOINT]);
glVertexAttribIPointer(loc, 4, GL_UNSIGNED_SHORT, LLVertexBuffer::sTypeSize[TYPE_JOINT], ptr);
}
if (data_mask & MAP_CLOTHWEIGHT)
if (setup_mask & MAP_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)
if (setup_mask & MAP_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)
if (setup_mask & MAP_VERTEX)
{
AttributeType loc = TYPE_VERTEX;
void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
}
if (gGLManager.mIsApple)
{
sVertexAttribsConfigured |= data_mask;
if (desired_color_source)
{
sVertexAttribsConfigured |= MAP_COLOR;
}
}
STOP_GLERROR;
}

Expand Down Expand Up @@ -1923,5 +1950,3 @@ void LLVertexBuffer::setIndexData(const U32* data, U32 offset, U32 count)
}




Loading