mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-22 04:16:22 +02:00
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:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user