Prevent redundant calls to glEnable/DisableVertexAttribArray. This should hopefully fix a performance regression compared to 0.9.2 as well.

This commit is contained in:
Alex Szpakowski
2015-06-23 20:55:23 -03:00
parent e3ff0a0d63
commit ed3f419747
11 changed files with 94 additions and 115 deletions
+3 -9
View File
@@ -307,31 +307,25 @@ void Canvas::drawv(const Matrix &t, const Vertex *v)
gl.bindTexture(texture);
glEnableVertexAttribArray(ATTRIB_POS);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].x);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].s);
gl.prepareDraw();
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(ATTRIB_TEXCOORD);
glDisableVertexAttribArray(ATTRIB_POS);
}
void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{
static Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
Matrix t(x, y, angle, sx, sy, ox, oy, kx, ky);
drawv(t, vertices);
}
void Canvas::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{
static Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
Matrix t(x, y, angle, sx, sy, ox, oy, kx, ky);
const Vertex *v = quad->getVertices();
drawv(t, v);
+4 -19
View File
@@ -564,25 +564,12 @@ void Font::printv(const Matrix &t, const std::vector<DrawCommand> &drawcommands,
OpenGL::TempTransform transform(gl);
transform.get() *= t;
glEnableVertexAttribArray(ATTRIB_POS);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(GlyphVertex), &vertices[0].x);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(GlyphVertex), &vertices[0].s);
try
{
drawVertices(drawcommands);
}
catch (love::Exception &)
{
glDisableVertexAttribArray(ATTRIB_TEXCOORD);
glDisableVertexAttribArray(ATTRIB_POS);
throw;
}
glDisableVertexAttribArray(ATTRIB_TEXCOORD);
glDisableVertexAttribArray(ATTRIB_POS);
drawVertices(drawcommands);
}
void Font::print(const std::string &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
@@ -590,8 +577,7 @@ void Font::print(const std::string &text, float x, float y, float angle, float s
std::vector<GlyphVertex> vertices;
std::vector<DrawCommand> drawcommands = generateVertices(text, vertices);
Matrix t;
t.setTransformation(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
Matrix t(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
printv(t, drawcommands, vertices);
}
@@ -601,8 +587,7 @@ void Font::printf(const std::string &text, float x, float y, float wrap, AlignMo
std::vector<GlyphVertex> vertices;
std::vector<DrawCommand> drawcommands = generateVerticesFormatted(text, wrap, align, vertices);
Matrix t;
t.setTransformation(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
Matrix t(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
printv(t, drawcommands, vertices);
}
+3 -6
View File
@@ -1088,10 +1088,9 @@ void Graphics::point(float x, float y)
gl.prepareDraw();
gl.bindTexture(gl.getDefaultTexture());
glEnableVertexAttribArray(ATTRIB_POS);
gl.useVertexAttribArrays(ATTRIBFLAG_POS);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, coord);
gl.drawArrays(GL_POINTS, 0, 1);
glDisableVertexAttribArray(ATTRIB_POS);
}
void Graphics::polyline(const float *coords, size_t count)
@@ -1247,10 +1246,9 @@ void Graphics::arc(DrawMode mode, float x, float y, float radius, float angle1,
gl.prepareDraw();
gl.bindTexture(gl.getDefaultTexture());
glEnableVertexAttribArray(ATTRIB_POS);
gl.useVertexAttribArrays(ATTRIBFLAG_POS);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, coords);
gl.drawArrays(GL_TRIANGLE_FAN, 0, points + 2);
glDisableVertexAttribArray(ATTRIB_POS);
}
delete[] coords;
@@ -1273,10 +1271,9 @@ void Graphics::polygon(DrawMode mode, const float *coords, size_t count)
gl.prepareDraw();
gl.bindTexture(gl.getDefaultTexture());
glEnableVertexAttribArray(ATTRIB_POS);
gl.useVertexAttribArrays(ATTRIBFLAG_POS);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, coords);
gl.drawArrays(GL_TRIANGLE_FAN, 0, (int)count/2-1); // opengl will close the polygon for us
glDisableVertexAttribArray(ATTRIB_POS);
}
}
+3 -9
View File
@@ -360,31 +360,25 @@ void Image::drawv(const Matrix &t, const Vertex *v)
gl.bindTexture(texture);
glEnableVertexAttribArray(ATTRIB_POS);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].x);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].s);
gl.prepareDraw();
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(ATTRIB_TEXCOORD);
glDisableVertexAttribArray(ATTRIB_POS);
}
void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{
Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
Matrix t(x, y, angle, sx, sy, ox, oy, kx, ky);
drawv(t, vertices);
}
void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{
Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
Matrix t(x, y, angle, sx, sy, ox, oy, kx, ky);
drawv(t, quad->getVertices());
}
+5 -20
View File
@@ -546,10 +546,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
{
OpenGL::TempDebugGroup debuggroup("Mesh draw");
std::vector<GLint> attriblocations;
attriblocations.reserve(attachedAttributes.size());
bool hasposattrib = false;
uint32 enabledattribs = 0;
for (const auto &attrib : attachedAttributes)
{
@@ -585,24 +582,19 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
GLenum datatype = getGLDataType(format.type);
GLboolean normalized = (datatype == GL_UNSIGNED_BYTE);
glEnableVertexAttribArray(attriblocation);
glVertexAttribPointer(attriblocation, format.components, datatype, normalized, mesh->vertexStride, gloffset);
attriblocations.push_back(attriblocation);
if (attriblocation == ATTRIB_POS)
hasposattrib = true;
enabledattribs |= 1 << uint32(attriblocation);
}
if (!hasposattrib)
if (!(enabledattribs & ATTRIBFLAG_POS))
{
for (GLint attrib : attriblocations)
glDisableVertexAttribArray(attrib);
// Not supported on all platforms or GL versions at least, I believe.
throw love::Exception("Mesh must have an enabled VertexPosition attribute to be drawn.");
}
gl.useVertexAttribArrays(enabledattribs);
if (texture.get())
gl.bindTexture(*(GLuint *) texture->getHandle());
else
@@ -649,13 +641,6 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
// Normal non-indexed drawing (no custom vertex map.)
gl.drawArrays(getGLDrawMode(drawMode), min, max - min + 1);
}
for (GLint attrib : attriblocations)
{
glDisableVertexAttribArray(attrib);
if (attrib == ATTRIB_COLOR)
glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
}
}
size_t Mesh::getAttribFormatSize(const AttribFormat &format)
+37
View File
@@ -90,6 +90,11 @@ void OpenGL::setupContext()
glVertexAttrib4fv(ATTRIB_COLOR, glcolor);
glVertexAttrib4fv(ATTRIB_CONSTANTCOLOR, glcolor);
GLint maxvertexattribs = 1;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxvertexattribs);
state.enabledAttribArrays = 1u << uint32(maxvertexattribs - 1);
useVertexAttribArrays(0);
// Get the current viewport.
glGetIntegerv(GL_VIEWPORT, (GLint *) &state.viewport.x);
@@ -375,6 +380,38 @@ void OpenGL::drawElements(GLenum mode, GLsizei count, GLenum type, const void *i
++stats.drawCalls;
}
void OpenGL::useVertexAttribArrays(uint32 arraybits)
{
uint32 diff = arraybits ^ state.enabledAttribArrays;
if (diff == 0)
return;
// Max 32 attributes. As of when this was written, no GL driver exposes more
// than 32. Lets hope that doesn't change...
for (uint32 i = 0; i < 32; i++)
{
uint32 bit = 1 << i;
if (diff & bit)
{
if (arraybits & bit)
glEnableVertexAttribArray(i);
else
glDisableVertexAttribArray(i);
}
}
state.enabledAttribArrays = arraybits;
// glDisableVertexAttribArray will make the constant value for a vertex
// attribute undefined. We rely on the per-vertex color attribte being white
// when no per-vertex color is used, so we set it here.
// FIXME: Is there a better place to do this?
if ((diff & ATTRIBFLAG_COLOR) && !(arraybits & ATTRIBFLAG_COLOR))
glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
}
void OpenGL::setViewport(const OpenGL::Viewport &v)
{
glViewport(v.x, v.y, v.w, v.h);
+20
View File
@@ -23,6 +23,7 @@
// LOVE
#include "common/config.h"
#include "common/int.h"
#include "graphics/Color.h"
#include "graphics/Texture.h"
#include "common/Matrix.h"
@@ -60,6 +61,14 @@ enum VertexAttribID
ATTRIB_MAX_ENUM
};
enum VertexAttribFlags
{
ATTRIBFLAG_POS = 1 << ATTRIB_POS,
ATTRIBFLAG_TEXCOORD = 1 << ATTRIB_TEXCOORD,
ATTRIBFLAG_COLOR = 1 << ATTRIB_COLOR,
ATTRIBFLAG_CONSTANTCOLOR = 1 << ATTRIB_CONSTANTCOLOR
};
/**
* Thin layer between OpenGL and the rest of the program.
* Internally shadows some OpenGL context state for improved efficiency and
@@ -197,6 +206,15 @@ public:
void drawArrays(GLenum mode, GLint first, GLsizei count);
void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
/**
* Sets the enabled vertex attribute arrays based on the specified attribute
* bits. Each bit in the uint32 represents an enabled attribute array index.
* For example, useVertexAttribArrays(1 << 0) will enable attribute index 0.
* See the VertexAttribFlags enum for the standard vertex attributes.
* This function *must* be used instead of glEnable/DisableVertexAttribArray.
**/
void useVertexAttribArrays(uint32 arraybits);
/**
* Sets the OpenGL rendering viewport to the specified rectangle.
* The y-coordinate starts at the top.
@@ -353,6 +371,8 @@ private:
// Currently active texture unit.
int curTextureUnit;
uint32 enabledAttribArrays;
Viewport viewport;
Viewport scissor;
+2 -11
View File
@@ -854,8 +854,7 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
OpenGL::TempDebugGroup debuggroup("ParticleSystem draw");
static Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
Matrix t(x, y, angle, sx, sy, ox, oy, kx, ky);
OpenGL::TempTransform transform(gl);
transform.get() *= t;
@@ -896,9 +895,7 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
gl.bindTexture(*(GLuint *) texture->getHandle());
gl.prepareDraw();
glEnableVertexAttribArray(ATTRIB_COLOR);
glEnableVertexAttribArray(ATTRIB_POS);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR);
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), &particleVerts[0].r);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].x);
@@ -909,12 +906,6 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
GLBuffer::Bind ibo_bind(*quadIndices.getBuffer());
gl.drawElements(GL_TRIANGLES, count, quadIndices.getType(), quadIndices.getPointer(0));
}
glDisableVertexAttribArray(ATTRIB_TEXCOORD);
glDisableVertexAttribArray(ATTRIB_POS);
glDisableVertexAttribArray(ATTRIB_COLOR);
glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
}
void ParticleSystem::update(float dt)
+9 -11
View File
@@ -402,21 +402,26 @@ void Polyline::draw()
gl.prepareDraw();
gl.bindTexture(gl.getDefaultTexture());
glEnableVertexAttribArray(ATTRIB_POS);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, vertices + vertex_start);
uint32 enabledattribs = ATTRIBFLAG_POS;
if (overdraw)
{
// Prepare colors. Set the core line's colors to white, and the overdraw
// Prepare per-vertex colors. Set the core to white, and the overdraw
// line's colors to white on one side and transparent on the other.
colors = new Color[total_vertex_count];
memset(colors, 255, overdraw_vertex_start * sizeof(Color));
fill_color_array(colors + overdraw_vertex_start);
glEnableVertexAttribArray(ATTRIB_COLOR);
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
enabledattribs |= ATTRIBFLAG_COLOR;
}
gl.useVertexAttribArrays(enabledattribs);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, vertices + vertex_start);
// Draw the core line and the overdraw in a single draw call. We can do this
// because the vertex array contains both the core line and the overdraw
// vertices.
@@ -425,15 +430,8 @@ void Polyline::draw()
else
gl.drawArrays(draw_mode, 0, (int) total_vertex_count);
glDisableVertexAttribArray(ATTRIB_POS);
if (overdraw)
{
glDisableVertexAttribArray(ATTRIB_COLOR);
glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
delete[] colors;
}
if (indices)
delete[] indices;
+5 -13
View File
@@ -236,30 +236,22 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float
array_buf->unmap(buffer_used_offset, buffer_used_size);
buffer_used_offset = buffer_used_size = 0;
uint32 enabledattribs = ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD;
// Apply per-sprite color, if a color is set.
if (color)
{
glEnableVertexAttribArray(ATTRIB_COLOR);
enabledattribs |= ATTRIBFLAG_COLOR;
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), array_buf->getPointer(color_offset));
}
glEnableVertexAttribArray(ATTRIB_POS);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), array_buf->getPointer(pos_offset));
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), array_buf->getPointer(texel_offset));
gl.useVertexAttribArrays(enabledattribs);
gl.prepareDraw();
gl.drawElements(GL_TRIANGLES, (GLsizei) quad_indices.getIndexCount(next), quad_indices.getType(), quad_indices.getPointer(0));
glDisableVertexAttribArray(ATTRIB_TEXCOORD);
glDisableVertexAttribArray(ATTRIB_POS);
if (color)
{
glDisableVertexAttribArray(ATTRIB_COLOR);
glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
}
}
void SpriteBatch::addv(const Vertex *v, const Matrix &m, int index)
+3 -17
View File
@@ -232,8 +232,7 @@ void Text::draw(float x, float y, float angle, float sx, float sy, float ox, flo
const size_t tex_offset = offsetof(Font::GlyphVertex, s);
const size_t stride = sizeof(Font::GlyphVertex);
Matrix t;
t.setTransformation(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
Matrix t(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
OpenGL::TempTransform transform(gl);
transform.get() *= t;
@@ -247,22 +246,9 @@ void Text::draw(float x, float y, float angle, float sx, float sy, float ox, flo
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, vbo->getPointer(tex_offset));
}
glEnableVertexAttribArray(ATTRIB_POS);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD);
try
{
font->drawVertices(draw_commands);
}
catch (love::Exception &)
{
glDisableVertexAttribArray(ATTRIB_TEXCOORD);
glDisableVertexAttribArray(ATTRIB_POS);
throw;
}
glDisableVertexAttribArray(ATTRIB_TEXCOORD);
glDisableVertexAttribArray(ATTRIB_POS);
font->drawVertices(draw_commands);
}
void Text::setFont(Font *f)