diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index 25391875e..d98372eca 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -617,7 +617,7 @@ std::vector Font::generateVerticesFormatted(const ColoredCode return drawcommands; } -void Font::drawVertices(const std::vector &drawcommands) +void Font::drawVertices(const std::vector &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 &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 &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 &drawcommands, const std::vector &vertices) @@ -665,7 +677,7 @@ void Font::printv(const Matrix4 &t, const std::vector &drawcommands gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR); - drawVertices(drawcommands); + drawVertices(drawcommands, false); } void Font::print(const std::vector &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index 6ed474b01..3f65d7772 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -109,7 +109,7 @@ public: std::vector generateVerticesFormatted(const ColoredCodepoints &text, float wrap, AlignMode align, std::vector &vertices, TextInfo *info = nullptr); - void drawVertices(const std::vector &drawcommands); + void drawVertices(const std::vector &drawcommands, bool bufferedvertices); static void getCodepointsFromString(const std::string &str, Codepoints &codepoints); static void getCodepointsFromString(const std::vector &strs, ColoredCodepoints &codepoints); diff --git a/src/modules/graphics/opengl/GLBuffer.cpp b/src/modules/graphics/opengl/GLBuffer.cpp index 2a7789243..d1cb0d866 100644 --- a/src/modules/graphics/opengl/GLBuffer.cpp +++ b/src/modules/graphics/opengl/GLBuffer.cpp @@ -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 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 diff --git a/src/modules/graphics/opengl/GLBuffer.h b/src/modules/graphics/opengl/GLBuffer.h index 940db89bf..9b64442b7 100644 --- a/src/modules/graphics/opengl/GLBuffer.h +++ b/src/modules/graphics/opengl/GLBuffer.h @@ -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 diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 83cb4969b..43dee397c 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -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 diff --git a/src/modules/graphics/opengl/Text.cpp b/src/modules/graphics/opengl/Text.cpp index 06a0ac476..b6327107c 100644 --- a/src/modules/graphics/opengl/Text.cpp +++ b/src/modules/graphics/opengl/Text.cpp @@ -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)