Hopefully work around an nvidia graphics driver bug in OS X.

Some nvidia GPUs in OS X fail to render geometry that uses an OpenGL index buffer and client-side vertex arrays. This affected ParticleSystems and love.graphics.print. The code for those has been changed to use a client-side index array instead of an OpenGL index buffer.
This commit is contained in:
Alex Szpakowski
2015-12-15 21:50:38 -04:00
parent aad3c0d4d9
commit 5460a5b872
6 changed files with 68 additions and 21 deletions
+16 -4
View File
@@ -617,7 +617,7 @@ std::vector<Font::DrawCommand> Font::generateVerticesFormatted(const ColoredCode
return drawcommands;
}
void Font::drawVertices(const std::vector<DrawCommand> &drawcommands)
void Font::drawVertices(const std::vector<DrawCommand> &drawcommands, bool bufferedvertices)
{
// Vertex attribute pointers need to be set before calling this function.
// This assumes that the attribute pointers are constant for all vertices.
@@ -634,7 +634,12 @@ void Font::drawVertices(const std::vector<DrawCommand> &drawcommands)
const GLenum gltype = quadIndices.getType();
const size_t elemsize = quadIndices.getElementSize();
GLBuffer::Bind bind(*quadIndices.getBuffer());
// We only get indices from the index buffer if we're also using vertex
// buffers, because at least one graphics driver (the one for Kepler nvidia
// GPUs in OS X 10.11) fails to render geometry if an index buffer is used
// with client-side vertex arrays.
if (bufferedvertices)
quadIndices.getBuffer()->bind();
// We need a separate draw call for every section of the text which uses a
// different texture than the previous section.
@@ -645,8 +650,15 @@ void Font::drawVertices(const std::vector<DrawCommand> &drawcommands)
// TODO: Use glDrawElementsBaseVertex when supported?
gl.bindTexture(cmd.texture);
gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getPointer(offset));
if (bufferedvertices)
gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getPointer(offset));
else
gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getIndices(offset));
}
if (bufferedvertices)
quadIndices.getBuffer()->unbind();
}
void Font::printv(const Matrix4 &t, const std::vector<DrawCommand> &drawcommands, const std::vector<GlyphVertex> &vertices)
@@ -665,7 +677,7 @@ void Font::printv(const Matrix4 &t, const std::vector<DrawCommand> &drawcommands
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR);
drawVertices(drawcommands);
drawVertices(drawcommands, false);
}
void Font::print(const std::vector<ColoredString> &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
+1 -1
View File
@@ -109,7 +109,7 @@ public:
std::vector<DrawCommand> generateVerticesFormatted(const ColoredCodepoints &text, float wrap, AlignMode align, std::vector<GlyphVertex> &vertices, TextInfo *info = nullptr);
void drawVertices(const std::vector<DrawCommand> &drawcommands);
void drawVertices(const std::vector<DrawCommand> &drawcommands, bool bufferedvertices);
static void getCodepointsFromString(const std::string &str, Codepoints &codepoints);
static void getCodepointsFromString(const std::vector<ColoredString> &strs, ColoredCodepoints &codepoints);
+25 -10
View File
@@ -244,7 +244,9 @@ void GLBuffer::unload()
size_t QuadIndices::maxSize = 0;
size_t QuadIndices::elementSize = 0;
size_t QuadIndices::objectCount = 0;
GLBuffer *QuadIndices::indexBuffer = nullptr;
char *QuadIndices::indices = nullptr;
QuadIndices::QuadIndices(size_t size)
: size(size)
@@ -259,6 +261,7 @@ QuadIndices::QuadIndices(size_t size)
if (indexBuffer == nullptr || size > maxSize)
{
GLBuffer *newbuffer = nullptr;
char *newindices = nullptr;
// Depending on the size, a switch to int and more memory is needed.
GLenum targettype = getType(size);
@@ -271,9 +274,12 @@ QuadIndices::QuadIndices(size_t size)
try
{
newbuffer = new GLBuffer(buffersize, nullptr, GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW);
newindices = new char[buffersize];
}
catch (std::bad_alloc &)
{
delete[] newbuffer;
delete[] newindices;
throw love::Exception("Out of memory.");
}
@@ -281,6 +287,10 @@ QuadIndices::QuadIndices(size_t size)
// The old GLBuffer can now be deleted.
delete indexBuffer;
indexBuffer = newbuffer;
delete[] indices;
indices = newindices;
maxSize = size;
elementSize = elemsize;
@@ -355,13 +365,15 @@ const void *QuadIndices::getPointer(size_t offset) const
return indexBuffer->getPointer(offset);
}
const void *QuadIndices::getIndices(size_t offset) const
{
return indices + offset;
}
template <typename T>
void QuadIndices::fill()
{
GLBuffer::Bind bind(*indexBuffer);
GLBuffer::Mapper mapper(*indexBuffer);
T *indices = (T *) mapper.get();
T *inds = (T *) indices;
// 0----2
// | / |
@@ -369,14 +381,17 @@ void QuadIndices::fill()
// 1----3
for (size_t i = 0; i < maxSize; ++i)
{
indices[i*6+0] = T(i * 4 + 0);
indices[i*6+1] = T(i * 4 + 1);
indices[i*6+2] = T(i * 4 + 2);
inds[i*6+0] = T(i * 4 + 0);
inds[i*6+1] = T(i * 4 + 1);
inds[i*6+2] = T(i * 4 + 2);
indices[i*6+3] = T(i * 4 + 2);
indices[i*6+4] = T(i * 4 + 1);
indices[i*6+5] = T(i * 4 + 3);
inds[i*6+3] = T(i * 4 + 2);
inds[i*6+4] = T(i * 4 + 1);
inds[i*6+5] = T(i * 4 + 3);
}
GLBuffer::Bind bind(*indexBuffer);
indexBuffer->fill(0, indexBuffer->getSize(), indices);
}
} // opengl
+17
View File
@@ -384,6 +384,20 @@ public:
*/
const void *getPointer(size_t offset) const;
/**
* Returns a direct pointer to the index data.
*
* At least one graphics driver (the one for Kepler nvidia GPUs in OS X)
* fails to render geometry if the vertex data was a direct CPU pointer but
* the index data came from an Index Buffer.
* So the direct pointer to the index buffer should be used instead of the
* index buffer when rendering using client-side vertex arrays.
*
* @param offset An offset in bytes into the index data.
* @return A direct pointer to the index data at the specified offset.
**/
const void *getIndices(size_t offset) const;
private:
/**
@@ -406,6 +420,9 @@ private:
// The GLBuffer for the element array. Can be null.
static GLBuffer *indexBuffer;
// The array of indices that will also be stored in the index buffer.
static char *indices;
};
} // opengl
@@ -141,11 +141,14 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].x);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].s);
{
GLsizei count = (GLsizei) quadIndices.getIndexCount(pCount);
GLBuffer::Bind ibo_bind(*quadIndices.getBuffer());
gl.drawElements(GL_TRIANGLES, count, quadIndices.getType(), quadIndices.getPointer(0));
}
GLsizei count = (GLsizei) quadIndices.getIndexCount(pCount);
GLenum gltype = quadIndices.getType();
// We use a client-side index array instead of an Index Buffers, because
// at least one graphics driver (the one for Kepler nvidia GPUs in OS X
// 10.11) fails to render geometry if an index buffer is used with
// client-side vertex arrays.
gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getIndices(0));
}
} // opengl
+1 -1
View File
@@ -245,7 +245,7 @@ void Text::draw(float x, float y, float angle, float sx, float sy, float ox, flo
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR);
font->drawVertices(draw_commands);
font->drawVertices(draw_commands, true);
}
void Text::setFont(Font *f)