mirror of
https://github.com/love2d/love.git
synced 2026-08-17 11:00:31 +02:00
Simplify quad drawing code, and use glDrawElementsBaseVertex when available.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user