mirror of
https://github.com/love2d/love.git
synced 2026-08-16 00:02:12 +02:00
Prevent redundant glBindBuffer calls.
--HG-- branch : minor
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -663,6 +663,8 @@ void Font::drawVertices(const std::vector<DrawCommand> &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<DrawCommand> &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<DrawCommand> &drawcommands, const std::vector<GlyphVertex> &vertices)
|
||||
@@ -694,6 +693,7 @@ void Font::printv(const Matrix4 &t, const std::vector<DrawCommand> &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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ Mesh::Mesh(const std::vector<AttribFormat> &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<AttribFormat> &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<uint32> &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<uint32> &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<uint32> &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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<GLuint> boundTextures;
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -58,13 +58,12 @@ void Text::uploadVertices(const std::vector<Font::GlyphVertex> &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<Font::GlyphVertex> &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<Font::GlyphVertex> &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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user