Simplify quad drawing code, and use glDrawElementsBaseVertex when available.

This commit is contained in:
Alex Szpakowski
2017-12-24 22:05:10 -04:00
parent 785902d8bd
commit a31b500b03
14 changed files with 135 additions and 185 deletions
+72 -11
View File
@@ -55,8 +55,7 @@ namespace opengl
{
Graphics::Graphics()
: quadIndices(nullptr)
, windowHasStencil(false)
: windowHasStencil(false)
, mainVAO(0)
{
gl = OpenGL();
@@ -87,8 +86,6 @@ Graphics::Graphics()
Graphics::~Graphics()
{
if (quadIndices)
delete quadIndices;
}
const char *Graphics::getName() const
@@ -226,13 +223,7 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
if (!Volatile::loadAll())
::printf("Could not reload all volatile objects.\n");
// Create a quad indices object owned by love.graphics, so at least one
// QuadIndices object is alive at all times while love.graphics is alive.
// This makes sure there aren't too many expensive destruction/creations of
// index buffer objects, since the shared index buffer used by QuadIndices
// objects is destroyed when the last object is destroyed.
if (quadIndices == nullptr)
quadIndices = new QuadIndices(this);
createQuadIndexBuffer();
// Restore the graphics state.
restoreState(states.back());
@@ -354,6 +345,76 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
++drawCalls;
}
static inline void advanceVertexOffsets(const vertex::Attributes &attributes, vertex::Buffers &buffers, int vertexcount)
{
// TODO: Figure out a better way to avoid touching the same buffer multiple
// times, if multiple attributes share the buffer.
uint32 touchedbuffers = 0;
for (unsigned int i = 0; i < vertex::Attributes::MAX; i++)
{
if (!attributes.isEnabled(i))
continue;
auto &attrib = attributes.attribs[i];
uint32 bufferbit = 1u << attrib.bufferindex;
if ((touchedbuffers & bufferbit) == 0)
{
touchedbuffers |= bufferbit;
buffers.info[attrib.bufferindex].offset += attrib.stride * vertexcount;
}
}
}
void Graphics::drawQuads(int start, int count, const vertex::Attributes &attributes, const vertex::Buffers &buffers, love::graphics::Texture *texture)
{
const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX;
const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4;
gl.prepareDraw();
gl.bindTextureToUnit(texture, 0, false);
gl.setCullMode(CULL_NONE);
gl.bindBuffer(BUFFER_INDEX, quadIndexBuffer->getHandle());
if (gl.isBaseVertexSupported())
{
gl.setVertexAttributes(attributes, buffers);
int basevertex = start;
for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW)
{
int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
glDrawElementsBaseVertex(GL_TRIANGLES, quadcount * 6, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0), basevertex);
++drawCalls;
basevertex += quadcount * 4;
}
}
else
{
vertex::Buffers bufferscopy = buffers;
if (start > 0)
advanceVertexOffsets(attributes, bufferscopy, start * 4);
for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW)
{
gl.setVertexAttributes(attributes, bufferscopy);
int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
glDrawElements(GL_TRIANGLES, quadcount * 6, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
++drawCalls;
if (count > MAX_QUADS_PER_DRAW)
advanceVertexOffsets(attributes, bufferscopy, quadcount * 4);
}
}
}
static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, const GLvoid* /*usr*/)
{
// Human-readable strings for the debug info.
+1 -1
View File
@@ -71,6 +71,7 @@ public:
void draw(const DrawCommand &cmd) override;
void draw(const DrawIndexedCommand &cmd) override;
void drawQuads(int start, int count, const vertex::Attributes &attributes, const vertex::Buffers &buffers, Texture *texture) override;
void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) override;
void clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth) override;
@@ -127,7 +128,6 @@ private:
void setDebug(bool enable);
std::unordered_map<uint32, GLuint> framebufferObjects;
QuadIndices *quadIndices;
bool windowHasStencil;
GLuint mainVAO;
+35
View File
@@ -95,6 +95,7 @@ OpenGL::OpenGL()
: stats()
, contextInitialized(false)
, pixelShaderHighpSupported(false)
, baseVertexSupported(false)
, maxAnisotropy(1.0f)
, max2DTextureSize(0)
, max3DTextureSize(0)
@@ -375,6 +376,32 @@ void OpenGL::initOpenGLFunctions()
fp_glCompressedTexSubImage3D = fp_glCompressedTexSubImage3DOES;
fp_glFramebufferTexture3D = fp_glFramebufferTexture3DOES;
}
if (!GLAD_VERSION_3_2 && !GLAD_ES_VERSION_3_2 && !GLAD_ARB_draw_elements_base_vertex)
{
if (GLAD_OES_draw_elements_base_vertex)
{
fp_glDrawElementsBaseVertex = fp_glDrawElementsBaseVertexOES;
if (GLAD_ES_VERSION_3_0)
{
fp_glDrawRangeElementsBaseVertex = fp_glDrawRangeElementsBaseVertexOES;
fp_glDrawElementsInstancedBaseVertex = fp_glDrawElementsInstancedBaseVertexOES;
}
}
else if (GLAD_EXT_draw_elements_base_vertex)
{
fp_glDrawElementsBaseVertex = fp_glDrawElementsBaseVertexEXT;
if (GLAD_ES_VERSION_3_0)
{
fp_glDrawRangeElementsBaseVertex = fp_glDrawRangeElementsBaseVertexEXT;
fp_glDrawElementsInstancedBaseVertex = fp_glDrawElementsInstancedBaseVertexEXT;
}
}
}
}
void OpenGL::initMaxValues()
@@ -389,6 +416,9 @@ void OpenGL::initMaxValues()
else
pixelShaderHighpSupported = true;
baseVertexSupported = GLAD_VERSION_3_2 || GLAD_ES_VERSION_3_2 || GLAD_ARB_draw_elements_base_vertex
|| GLAD_OES_draw_elements_base_vertex || GLAD_EXT_draw_elements_base_vertex;
// We'll need this value to clamp anisotropy.
if (GLAD_EXT_texture_filter_anisotropic)
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
@@ -1177,6 +1207,11 @@ bool OpenGL::isSamplerLODBiasSupported() const
return GLAD_VERSION_1_4;
}
bool OpenGL::isBaseVertexSupported() const
{
return baseVertexSupported;
}
int OpenGL::getMax2DTextureSize() const
{
return std::max(max2DTextureSize, 1);
+3
View File
@@ -334,6 +334,7 @@ public:
bool isInstancingSupported() const;
bool isDepthCompareSampleSupported() const;
bool isSamplerLODBiasSupported() const;
bool isBaseVertexSupported() const;
/**
* Returns the maximum supported width or height of a texture.
@@ -413,6 +414,8 @@ private:
bool contextInitialized;
bool pixelShaderHighpSupported;
bool baseVertexSupported;
float maxAnisotropy;
float maxLODBias;
int max2DTextureSize;