GLES: Pass known index range to glDrawRangeElements

DrawEngineGLES already knows that every index it generates is below the
decoded/transformed vertex count, but only passed the count to
glDrawElements. Drivers that need the vertex range before vertex
shading, like Mesa's Panfrost, then scan the index data on the CPU for
every draw, and their min/max caches can't help since the index push
buffer is rewritten every frame.

Only used for single-instance draws on desktop GL or GLES3, and only
when the caller provides the range, so other DrawIndexed callers are
unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kailash
2026-09-16 21:01:54 +05:30
co-authored by Claude Opus 5
parent 03bb3e20fe
commit eb2f5dfc61
4 changed files with 10 additions and 4 deletions
+3 -1
View File
@@ -1266,7 +1266,9 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
curElemArrayBuffer = buf;
}
if (c.draw.instances == 1) {
if (c.draw.instances == 1 && c.draw.maxIndex >= 0 && (!gl_extensions.IsGLES || gl_extensions.GLES3)) {
glDrawRangeElements(c.draw.mode, 0, c.draw.maxIndex, c.draw.count, c.draw.indexType, (void *)(intptr_t)c.draw.indexOffset);
} else if (c.draw.instances == 1) {
glDrawElements(c.draw.mode, c.draw.count, c.draw.indexType, (void *)(intptr_t)c.draw.indexOffset);
} else {
glDrawElementsInstanced(c.draw.mode, c.draw.count, c.draw.indexType, (void *)(intptr_t)c.draw.indexOffset, c.draw.instances);
+1
View File
@@ -116,6 +116,7 @@ struct GLRRenderData {
GLint count;
GLint indexType;
GLint instances;
GLint maxIndex; // -1 if unknown. Otherwise, all indices are known to be <= maxIndex.
} draw;
struct {
const char *name; // if null, use loc
+4 -1
View File
@@ -794,7 +794,9 @@ public:
}
// Would really love to have a basevertex parameter, but impossible in unextended GLES, without glDrawElementsBaseVertex, unfortunately.
void DrawIndexed(GLRInputLayout *inputLayout, GLRBuffer *vertexBuffer, uint32_t vertexOffset, GLRBuffer *indexBuffer, uint32_t indexOffset, GLenum mode, int count, GLenum indexType, int instances = 1) {
// If maxIndex is known (>= 0), it's passed on to the driver through glDrawRangeElements, which saves drivers that need the index
// range (like Panfrost) from scanning the index data on the CPU for every draw.
void DrawIndexed(GLRInputLayout *inputLayout, GLRBuffer *vertexBuffer, uint32_t vertexOffset, GLRBuffer *indexBuffer, uint32_t indexOffset, GLenum mode, int count, GLenum indexType, int instances = 1, int maxIndex = -1) {
_dbg_assert_(vertexBuffer && indexBuffer && curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
data.cmd = GLRRenderCommand::DRAW;
@@ -807,6 +809,7 @@ public:
data.draw.count = count;
data.draw.indexType = indexType;
data.draw.instances = instances;
data.draw.maxIndex = maxIndex;
}
enum { MAX_INFLIGHT_FRAMES = 3 };
+2 -2
View File
@@ -332,7 +332,7 @@ void DrawEngineGLES::Flush() {
render_->DrawIndexed(inputLayout,
vertexBuffer, vertexBufferOffset,
indexBuffer, indexBufferOffset,
glprim[prim], vertexCount, GL_UNSIGNED_SHORT);
glprim[prim], vertexCount, GL_UNSIGNED_SHORT, 1, maxIndex - 1);
} else {
render_->Draw(
inputLayout, vertexBuffer, vertexBufferOffset,
@@ -419,7 +419,7 @@ void DrawEngineGLES::Flush() {
indexBufferOffset = (uint32_t)frameData.pushIndex->Push(inds, sizeof(uint16_t) * result.drawIndexCount, 2, &indexBuffer);
render_->DrawIndexed(
softwareInputLayout_, vertexBuffer, vertexBufferOffset, indexBuffer, indexBufferOffset,
glprim[prim], result.drawIndexCount, GL_UNSIGNED_SHORT);
glprim[prim], result.drawIndexCount, GL_UNSIGNED_SHORT, 1, result.drawVertexCount - 1);
gpuStats.perFrame.numVertsDrawn += result.drawIndexCount;
} else if (action == SW_CLEAR) {
u32 clearColor = result.color;