From d1c5edd79203ee5e408f234243ce306d35e839b0 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 20 Oct 2016 21:50:48 -0300 Subject: [PATCH] Prevent redundant glBindBuffer calls. --HG-- branch : minor --- src/modules/graphics/opengl/Canvas.cpp | 1 + src/modules/graphics/opengl/Font.cpp | 6 +- src/modules/graphics/opengl/GLBuffer.cpp | 54 ++++++--------- src/modules/graphics/opengl/GLBuffer.h | 66 ++----------------- src/modules/graphics/opengl/Graphics.cpp | 2 + src/modules/graphics/opengl/Image.cpp | 1 + src/modules/graphics/opengl/Mesh.cpp | 34 ++-------- src/modules/graphics/opengl/OpenGL.cpp | 39 +++++++++++ src/modules/graphics/opengl/OpenGL.h | 26 +++++++- .../graphics/opengl/ParticleSystem.cpp | 2 + src/modules/graphics/opengl/Polyline.cpp | 4 ++ src/modules/graphics/opengl/SpriteBatch.cpp | 45 +++++-------- src/modules/graphics/opengl/Text.cpp | 7 +- src/modules/graphics/opengl/Video.cpp | 1 + 14 files changed, 128 insertions(+), 160 deletions(-) diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 55268b16b..c7f6ad2d6 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -315,6 +315,7 @@ void Canvas::drawv(const Matrix4 &t, const Vertex *v) gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD); + gl.bindBuffer(BUFFER_VERTEX, 0); 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); diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index 77cf1f760..5ce09186a 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -663,6 +663,8 @@ void Font::drawVertices(const std::vector &drawcommands, bool buffe // with client-side vertex arrays. if (bufferedvertices) quadIndices.getBuffer()->bind(); + else + gl.bindBuffer(BUFFER_INDEX, 0); // We need a separate draw call for every section of the text which uses a // different texture than the previous section. @@ -679,9 +681,6 @@ void Font::drawVertices(const std::vector &drawcommands, bool buffe 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) @@ -694,6 +693,7 @@ void Font::printv(const Matrix4 &t, const std::vector &drawcommands OpenGL::TempTransform transform(gl); transform.get() *= t; + gl.bindBuffer(BUFFER_VERTEX, 0); glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(GlyphVertex), &vertices[0].x); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(GlyphVertex), &vertices[0].s); glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GlyphVertex), &vertices[0].color.r); diff --git a/src/modules/graphics/opengl/GLBuffer.cpp b/src/modules/graphics/opengl/GLBuffer.cpp index 4cee2f34a..3d76e9dc0 100644 --- a/src/modules/graphics/opengl/GLBuffer.cpp +++ b/src/modules/graphics/opengl/GLBuffer.cpp @@ -34,11 +34,10 @@ namespace graphics namespace opengl { -GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage, uint32 mapflags) - : is_bound(false) - , is_mapped(false) +GLBuffer::GLBuffer(size_t size, const void *data, BufferType type, GLenum usage, uint32 mapflags) + : is_mapped(false) , size(size) - , target(target) + , type(type) , usage(usage) , vbo(0) , memory_map(nullptr) @@ -46,6 +45,8 @@ GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage, u , modified_size(0) , map_flags(mapflags) { + target = OpenGL::getGLBufferType(type); + try { memory_map = new char[size]; @@ -92,15 +93,17 @@ void GLBuffer::unmapStatic(size_t offset, size_t size) return; // Upload the mapped data to the buffer. - glBufferSubData(getTarget(), (GLintptr) offset, (GLsizeiptr) size, memory_map + offset); + gl.bindBuffer(type, vbo); + glBufferSubData(target, (GLintptr) offset, (GLsizeiptr) size, memory_map + offset); } void GLBuffer::unmapStream() { // "orphan" current buffer to avoid implicit synchronisation on the GPU: // http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf - glBufferData(getTarget(), (GLsizeiptr) getSize(), nullptr, getUsage()); - glBufferData(getTarget(), (GLsizeiptr) getSize(), memory_map, getUsage()); + gl.bindBuffer(type, vbo); + glBufferData(target, (GLsizeiptr) getSize(), nullptr, getUsage()); + glBufferData(target, (GLsizeiptr) getSize(), memory_map, getUsage()); } void GLBuffer::unmap() @@ -119,14 +122,6 @@ void GLBuffer::unmap() modified_size = getSize(); } - // VBO::bind is a no-op when the VBO is mapped, so we have to make sure it's - // bound here. - if (!is_bound) - { - glBindBuffer(getTarget(), vbo); - is_bound = true; - } - if (modified_size > 0) { switch (getUsage()) @@ -173,19 +168,7 @@ void GLBuffer::setMappedRangeModified(size_t offset, size_t modifiedsize) void GLBuffer::bind() { - if (!is_mapped) - { - glBindBuffer(getTarget(), vbo); - is_bound = true; - } -} - -void GLBuffer::unbind() -{ - if (is_bound) - glBindBuffer(getTarget(), 0); - - is_bound = false; + gl.bindBuffer(getType(), vbo); } void GLBuffer::fill(size_t offset, size_t size, const void *data) @@ -195,7 +178,10 @@ void GLBuffer::fill(size_t offset, size_t size, const void *data) if (is_mapped) setMappedRangeModified(offset, size); else - glBufferSubData(getTarget(), (GLintptr) offset, (GLsizeiptr) size, data); + { + gl.bindBuffer(type, vbo); + glBufferSubData(target, (GLintptr) offset, (GLsizeiptr) size, data); + } } const void *GLBuffer::getPointer(size_t offset) const @@ -217,7 +203,7 @@ bool GLBuffer::load(bool restore) { glGenBuffers(1, &vbo); - GLBuffer::Bind bind(*this); + bind(); while (glGetError() != GL_NO_ERROR) /* Clear the error buffer. */; @@ -226,7 +212,7 @@ bool GLBuffer::load(bool restore) const GLvoid *src = restore ? memory_map : nullptr; // Note that if 'src' is '0', no data will be copied. - glBufferData(getTarget(), (GLsizeiptr) getSize(), src, getUsage()); + glBufferData(target, (GLsizeiptr) getSize(), src, getUsage()); return (glGetError() == GL_NO_ERROR); } @@ -234,8 +220,7 @@ bool GLBuffer::load(bool restore) void GLBuffer::unload() { is_mapped = false; - - glDeleteBuffers(1, &vbo); + gl.deleteBuffer(vbo); vbo = 0; } @@ -274,7 +259,7 @@ QuadIndices::QuadIndices(size_t size) // QuadIndices will propagate the exception and keep the old GLBuffer. try { - newbuffer = new GLBuffer(buffersize, nullptr, GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW); + newbuffer = new GLBuffer(buffersize, nullptr, BUFFER_INDEX, GL_STATIC_DRAW); newindices = new char[buffersize]; } catch (std::bad_alloc &) @@ -394,7 +379,6 @@ void QuadIndices::fill() inds[i*6+5] = T(i * 4 + 3); } - GLBuffer::Bind bind(*indexBuffer); indexBuffer->fill(0, indexBuffer->getSize(), indices); } diff --git a/src/modules/graphics/opengl/GLBuffer.h b/src/modules/graphics/opengl/GLBuffer.h index de320161a..665cfd435 100644 --- a/src/modules/graphics/opengl/GLBuffer.h +++ b/src/modules/graphics/opengl/GLBuffer.h @@ -56,10 +56,10 @@ public: * Constructor. * * @param size The size of the GLBuffer in bytes. - * @param target The target GLBuffer object, e.g. GL_ARRAY_BUFFER. + * @param type The type of the buffer object. * @param usage Usage hint, e.g. GL_DYNAMIC_DRAW. */ - GLBuffer(size_t size, const void *data, GLenum target, GLenum usage, uint32 mapflags = 0); + GLBuffer(size_t size, const void *data, BufferType type, GLenum usage, uint32 mapflags = 0); /** * Destructor. @@ -77,13 +77,11 @@ public: } /** - * Get the target buffer object. - * - * @return The target buffer object, e.g. GL_ARRAY_BUFFER. + * Get the type of the buffer object. */ - GLenum getTarget() const + BufferType getType() const { - return target; + return type; } /** @@ -96,11 +94,6 @@ public: return usage; } - bool isBound() const - { - return is_bound; - } - bool isMapped() const { return is_mapped; @@ -112,8 +105,6 @@ public: * This can be faster for large changes to the buffer. For smaller * changes, see fill(). * - * The GLBuffer must be bound to use this function. - * * @return A pointer to memory which represents the buffer. */ void *map(); @@ -121,8 +112,6 @@ public: /** * Unmap a previously mapped GLBuffer. The buffer must be unmapped * when used to draw elements. - * - * The GLBuffer must be bound to use this function. */ void unmap(); @@ -138,16 +127,9 @@ public: */ void bind(); - /** - * Unbind a prevously bound GLBuffer. - */ - void unbind(); - /** * Fill a portion of the buffer with data and marks the range as modified. * - * The GLBuffer must be bound to use this function. - * * @param offset The offset in the GLBuffer to store the data. * @param size The size of the incoming data. * @param data Pointer to memory to copy data from. @@ -171,38 +153,6 @@ public: bool loadVolatile() override; void unloadVolatile() override; - /** - * This helper class can bind a GLBuffer temporarily, and - * automatically un-bind when it's destroyed. - */ - class Bind - { - public: - - /** - * Bind a GLBuffer. - */ - Bind(GLBuffer &buf) - : buf(buf) - { - buf.bind(); - } - - /** - * Unbinds a GLBuffer. - */ - ~Bind() - { - buf.unbind(); - } - - private: - - // GLBuffer to work on. - GLBuffer &buf; - - }; // Bind - class Mapper { public: @@ -253,16 +203,14 @@ private: void unmapStatic(size_t offset, size_t size); void unmapStream(); - // Whether the buffer is currently bound. - bool is_bound; - // Whether the buffer is currently mapped to main memory. bool is_mapped; // The size of the buffer, in bytes. size_t size; - // The target buffer object. (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER). + // The type of the buffer object. + BufferType type; GLenum target; // Usage hint. GL_[DYNAMIC, STATIC, STREAM]_DRAW. diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 2ce372fbc..3cb2db610 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1288,6 +1288,7 @@ void Graphics::points(const float *coords, const uint8 *colors, size_t numpoints gl.prepareDraw(); gl.bindTexture(gl.getDefaultTexture()); + gl.bindBuffer(BUFFER_VERTEX, 0); uint32 attribflags = ATTRIBFLAG_POS; glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, coords); @@ -1550,6 +1551,7 @@ void Graphics::polygon(DrawMode mode, const float *coords, size_t count) gl.prepareDraw(); gl.bindTexture(gl.getDefaultTexture()); + gl.bindBuffer(BUFFER_VERTEX, 0); 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 diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 67ebd99b7..5e971eb31 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -453,6 +453,7 @@ void Image::drawv(const Matrix4 &t, const Vertex *v) gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD); + gl.bindBuffer(BUFFER_VERTEX, 0); 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); diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index a8cc0a688..16807d780 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -80,7 +80,7 @@ Mesh::Mesh(const std::vector &vertexformat, const void *data, size if (vertexCount == 0) throw love::Exception("Data size is too small for specified vertex attribute formats."); - vbo = new GLBuffer(datasize, data, GL_ARRAY_BUFFER, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); + vbo = new GLBuffer(datasize, data, BUFFER_VERTEX, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); vertexScratchBuffer = new char[vertexStride]; } @@ -106,10 +106,9 @@ Mesh::Mesh(const std::vector &vertexformat, int vertexcount, DrawM size_t buffersize = vertexCount * vertexStride; - vbo = new GLBuffer(buffersize, nullptr, GL_ARRAY_BUFFER, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); + vbo = new GLBuffer(buffersize, nullptr, BUFFER_VERTEX, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); // Initialize the buffer's contents to 0. - GLBuffer::Bind bind(*vbo); memset(vbo->map(), 0, buffersize); vbo->setMappedRangeModified(0, vbo->getSize()); vbo->unmap(); @@ -192,9 +191,7 @@ void Mesh::setVertex(size_t vertindex, const void *data, size_t datasize) size_t offset = vertindex * vertexStride; size_t size = std::min(datasize, vertexStride); - GLBuffer::Bind bind(*vbo); uint8 *bufferdata = (uint8 *) vbo->map(); - memcpy(bufferdata + offset, data, size); vbo->setMappedRangeModified(offset, size); @@ -209,9 +206,7 @@ size_t Mesh::getVertex(size_t vertindex, void *data, size_t datasize) size_t size = std::min(datasize, vertexStride); // We're relying on vbo->map() returning read/write data... ew. - GLBuffer::Bind bind(*vbo); const uint8 *bufferdata = (const uint8 *) vbo->map(); - memcpy(data, bufferdata + offset, size); return size; @@ -233,9 +228,7 @@ void Mesh::setVertexAttribute(size_t vertindex, int attribindex, const void *dat size_t offset = vertindex * vertexStride + getAttributeOffset(attribindex); size_t size = std::min(datasize, attributeSizes[attribindex]); - GLBuffer::Bind bind(*vbo); uint8 *bufferdata = (uint8 *) vbo->map(); - memcpy(bufferdata + offset, data, size); vbo->setMappedRangeModified(offset, size); @@ -253,9 +246,7 @@ size_t Mesh::getVertexAttribute(size_t vertindex, int attribindex, void *data, s size_t size = std::min(datasize, attributeSizes[attribindex]); // We're relying on vbo->map() returning read/write data... ew. - GLBuffer::Bind bind(*vbo); const uint8 *bufferdata = (const uint8 *) vbo->map(); - memcpy(data, bufferdata + offset, size); return size; @@ -356,29 +347,21 @@ void Mesh::attachAttribute(const std::string &name, Mesh *mesh) void *Mesh::mapVertexData() { - GLBuffer::Bind bind(*vbo); return vbo->map(); } void Mesh::unmapVertexData(size_t modifiedoffset, size_t modifiedsize) { - GLBuffer::Bind bind(*vbo); vbo->setMappedRangeModified(modifiedoffset, modifiedsize); vbo->unmap(); } void Mesh::flush() { - { - GLBuffer::Bind vbobind(*vbo); - vbo->unmap(); - } + vbo->unmap(); if (ibo != nullptr) - { - GLBuffer::Bind ibobind(*ibo); ibo->unmap(); - } } /** @@ -414,7 +397,7 @@ void Mesh::setVertexMap(const std::vector &map) } if (!ibo && size > 0) - ibo = new GLBuffer(size, nullptr, GL_ELEMENT_ARRAY_BUFFER, vbo->getUsage()); + ibo = new GLBuffer(size, nullptr, BUFFER_INDEX, vbo->getUsage()); useIndexBuffer = true; elementCount = map.size(); @@ -422,7 +405,6 @@ void Mesh::setVertexMap(const std::vector &map) if (!ibo || elementCount == 0) return; - GLBuffer::Bind ibobind(*ibo); GLBuffer::Mapper ibomap(*ibo); // Fill the buffer with the index values from the vector. @@ -467,8 +449,6 @@ bool Mesh::getVertexMap(std::vector &map) const if (!ibo || elementCount == 0) return true; - GLBuffer::Bind ibobind(*ibo); - // We unmap the buffer in Mesh::draw, Mesh::setVertexMap, and Mesh::flush. void *buffer = ibo->map(); @@ -559,8 +539,8 @@ int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inpu if (attriblocation < 0) return attriblocation; - // Needed for unmap and glVertexAttribPointer. - GLBuffer::Bind vbobind(*vbo); + // Needed for glVertexAttribPointer. + vbo->bind(); // Make sure the buffer isn't mapped (sends data to GPU if needed.) vbo->unmap(); @@ -614,7 +594,7 @@ void Mesh::draw(const Matrix4 &m) if (useIndexBuffer && ibo && elementCount > 0) { // Use the custom vertex map (index buffer) to draw the vertices. - GLBuffer::Bind ibo_bind(*ibo); + ibo->bind(); // Make sure the index buffer isn't mapped (sends data to GPU if needed.) ibo->unmap(); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index bb084993e..e7e70264c 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -143,6 +143,12 @@ void OpenGL::setupContext() else state.framebufferSRGBEnabled = false; + for (int i = 0; i < (int) BUFFER_MAX_ENUM; i++) + { + state.boundBuffers[i] = 0; + glBindBuffer(getGLBufferType((BufferType) i), 0); + } + // Initialize multiple texture unit support for shaders. state.boundTextures.clear(); state.boundTextures.resize(maxTextureUnits, 0); @@ -380,6 +386,39 @@ void OpenGL::prepareDraw() } } +GLenum OpenGL::getGLBufferType(BufferType type) +{ + switch (type) + { + case BUFFER_VERTEX: + return GL_ARRAY_BUFFER; + case BUFFER_INDEX: + return GL_ELEMENT_ARRAY_BUFFER; + case BUFFER_MAX_ENUM: + return GL_ZERO; + } +} + +void OpenGL::bindBuffer(BufferType type, GLuint buffer) +{ + if (state.boundBuffers[type] != buffer) + { + glBindBuffer(getGLBufferType(type), buffer); + state.boundBuffers[type] = buffer; + } +} + +void OpenGL::deleteBuffer(GLuint buffer) +{ + glDeleteBuffers(1, &buffer); + + for (int i = 0; i < (int) BUFFER_MAX_ENUM; i++) + { + if (state.boundBuffers[i] == buffer) + state.boundBuffers[i] = 0; + } +} + void OpenGL::drawArrays(GLenum mode, GLint first, GLsizei count) { glDrawArrays(mode, first, count); diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 8b89f018c..10bbf8c95 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -69,6 +69,13 @@ enum VertexAttribFlags ATTRIBFLAG_CONSTANTCOLOR = 1 << ATTRIB_CONSTANTCOLOR }; +enum BufferType +{ + BUFFER_VERTEX = 0, + BUFFER_INDEX, + BUFFER_MAX_ENUM +}; + /** * Thin layer between OpenGL and the rest of the program. * Internally shadows some OpenGL context state for improved efficiency and @@ -243,6 +250,18 @@ public: **/ void prepareDraw(); + /** + * State-tracked glBindBuffer. + * NOTE: This does not account for multiple VAOs being used! Index buffer + * bindings are per-VAO in OpenGL, but this doesn't know about that. + **/ + void bindBuffer(BufferType type, GLuint buffer); + + /** + * glDeleteBuffers which updates our shadowed state. + **/ + void deleteBuffer(GLuint buffer); + /** * glDrawArrays and glDrawElements which increment the draw-call counter by * themselves. @@ -396,6 +415,9 @@ public: **/ Vendor getVendor() const; + static GLenum getGLBufferType(BufferType type); + static GLint getGLWrapMode(Texture::WrapMode wmode); + static const char *errorString(GLenum errorcode); // Get human-readable strings for debug info. @@ -411,8 +433,6 @@ private: void initMatrices(); void createDefaultTexture(); - GLint getGLWrapMode(Texture::WrapMode wmode); - bool contextInitialized; float maxAnisotropy; @@ -427,6 +447,8 @@ private: // Tracked OpenGL state. struct { + GLuint boundBuffers[BUFFER_MAX_ENUM]; + // Texture unit state (currently bound texture for each texture unit.) std::vector boundTextures; diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 40d991c14..9f6e97c7e 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -137,6 +137,7 @@ void ParticleSystem::draw(const Matrix4 &m) gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR); + gl.bindBuffer(BUFFER_VERTEX, 0); 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); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].s); @@ -148,6 +149,7 @@ void ParticleSystem::draw(const Matrix4 &m) // 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.bindBuffer(BUFFER_INDEX, 0); gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getIndices(0)); } diff --git a/src/modules/graphics/opengl/Polyline.cpp b/src/modules/graphics/opengl/Polyline.cpp index 2a55bf2ec..0e9bb21f3 100644 --- a/src/modules/graphics/opengl/Polyline.cpp +++ b/src/modules/graphics/opengl/Polyline.cpp @@ -402,6 +402,7 @@ void Polyline::draw() gl.prepareDraw(); gl.bindTexture(gl.getDefaultTexture()); + gl.bindBuffer(BUFFER_VERTEX, 0); uint32 enabledattribs = ATTRIBFLAG_POS; @@ -426,7 +427,10 @@ void Polyline::draw() // because the vertex array contains both the core line and the overdraw // vertices. if (use_quad_indices) + { + gl.bindBuffer(BUFFER_INDEX, 0); gl.drawElements(draw_mode, (int) (total_vertex_count / 4) * 6, GL_UNSIGNED_SHORT, indices); + } else gl.drawArrays(draw_mode, 0, (int) total_vertex_count); diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index be22ab81c..426929fad 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -57,7 +57,7 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, Mesh::Usage usage) GLenum gl_usage = Mesh::getGLBufferUsage(usage); size_t vertex_size = sizeof(Vertex) * 4 * size; - array_buf = new GLBuffer(vertex_size, nullptr, GL_ARRAY_BUFFER, gl_usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); + array_buf = new GLBuffer(vertex_size, nullptr, BUFFER_VERTEX, gl_usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); } SpriteBatch::~SpriteBatch() @@ -108,7 +108,6 @@ void SpriteBatch::clear() void SpriteBatch::flush() { - GLBuffer::Bind bind(*array_buf); array_buf->unmap(); } @@ -155,11 +154,7 @@ void SpriteBatch::setBufferSize(int newsize) return; // Map the old GLBuffer to get a pointer to its data. - void *old_data = nullptr; - { - GLBuffer::Bind bind(*array_buf); - old_data = array_buf->map(); - } + void *old_data = array_buf->map(); size_t vertex_size = sizeof(Vertex) * 4 * newsize; GLBuffer *new_array_buf = nullptr; @@ -168,9 +163,7 @@ void SpriteBatch::setBufferSize(int newsize) try { - new_array_buf = new GLBuffer(vertex_size, nullptr, array_buf->getTarget(), array_buf->getUsage(), array_buf->getMapFlags()); - - GLBuffer::Bind bind(*new_array_buf); + new_array_buf = new GLBuffer(vertex_size, nullptr, array_buf->getType(), array_buf->getUsage(), array_buf->getMapFlags()); // Copy as much of the old data into the new GLBuffer as can fit. size_t copy_size = sizeof(Vertex) * 4 * new_next; @@ -263,25 +256,21 @@ void SpriteBatch::draw(const Matrix4 &m) uint32 enabledattribs = ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD; + // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.) + array_buf->unmap(); + + array_buf->bind(); + + // Apply per-sprite color, if a color is set. + if (color) { - // Scope this bind so it doesn't interfere with the - // Mesh::bindAttributeToShaderInput calls below. - GLBuffer::Bind array_bind(*array_buf); - - // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.) - array_buf->unmap(); - - // Apply per-sprite color, if a color is set. - if (color) - { - enabledattribs |= ATTRIBFLAG_COLOR; - glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), array_buf->getPointer(color_offset)); - } - - glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), array_buf->getPointer(pos_offset)); - glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), array_buf->getPointer(texel_offset)); + enabledattribs |= ATTRIBFLAG_COLOR; + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), array_buf->getPointer(color_offset)); } + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), array_buf->getPointer(pos_offset)); + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), array_buf->getPointer(texel_offset)); + for (const auto &it : attached_attributes) { Mesh *mesh = it.second.mesh.get(); @@ -309,7 +298,7 @@ void SpriteBatch::draw(const Matrix4 &m) count = std::min(count, next - start); - GLBuffer::Bind element_bind(*quad_indices.getBuffer()); + quad_indices.getBuffer()->bind(); const void *indices = quad_indices.getPointer(start * quad_indices.getElementSize()); if (count > 0) @@ -327,8 +316,6 @@ void SpriteBatch::addv(const Vertex *v, const Matrix4 &m, int index) if (color) setColorv(sprite, *color); - GLBuffer::Bind bind(*array_buf); - // Always keep the VBO mapped when adding data for now (it'll be unmapped // on draw.) array_buf->map(); diff --git a/src/modules/graphics/opengl/Text.cpp b/src/modules/graphics/opengl/Text.cpp index 9fcbc2e1e..76aafadd6 100644 --- a/src/modules/graphics/opengl/Text.cpp +++ b/src/modules/graphics/opengl/Text.cpp @@ -58,13 +58,12 @@ void Text::uploadVertices(const std::vector &vertices, size_t if (vbo != nullptr) newsize = std::max(size_t(vbo->getSize() * 1.5), newsize); - GLBuffer *new_vbo = new GLBuffer(newsize, nullptr, GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW); + GLBuffer *new_vbo = new GLBuffer(newsize, nullptr, BUFFER_VERTEX, GL_DYNAMIC_DRAW); if (vbo != nullptr) { try { - GLBuffer::Bind bind(*vbo); vbodata = (uint8 *) vbo->map(); } catch (love::Exception &) @@ -73,7 +72,6 @@ void Text::uploadVertices(const std::vector &vertices, size_t throw; } - GLBuffer::Bind bind(*new_vbo); new_vbo->fill(0, vbo->getSize(), vbodata); } @@ -83,7 +81,6 @@ void Text::uploadVertices(const std::vector &vertices, size_t if (vbo != nullptr && datasize > 0) { - GLBuffer::Bind bind(*vbo); vbodata = (uint8 *) vbo->map(); memcpy(vbodata + offset, &vertices[0], datasize); // We unmap when we draw, to avoid unnecessary full map()/unmap() calls. @@ -228,7 +225,7 @@ void Text::draw(const Matrix4 &m) transform.get() *= m; { - GLBuffer::Bind bind(*vbo); + vbo->bind(); vbo->unmap(); // Make sure all pending data is flushed to the GPU. // Font::drawVertices expects AttribPointer calls to be done already. diff --git a/src/modules/graphics/opengl/Video.cpp b/src/modules/graphics/opengl/Video.cpp index eb8e3b3db..8016426f1 100644 --- a/src/modules/graphics/opengl/Video.cpp +++ b/src/modules/graphics/opengl/Video.cpp @@ -134,6 +134,7 @@ void Video::draw(const Matrix4 &m) gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD); + gl.bindBuffer(BUFFER_VERTEX, 0); glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertices[0].x); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertices[0].s);