From a9f2a7d7cdc6ae81e2f5cb071ca8ddc70db89fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 17 May 2023 17:57:47 +0200 Subject: [PATCH] OpenGL: For contiguous DrawArrays, avoid re-binding the vertex buffer if possible. --- Common/GPU/OpenGL/GLQueueRunner.cpp | 40 +++++++++++++++++++++++++---- Common/GPU/OpenGL/GLRenderManager.h | 2 +- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp index 0b6c65b4d0..98c2095865 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -834,6 +834,11 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last bool logicEnabled = false; #endif bool clipDistanceEnabled[8]{}; + + bool lastDrawIsArray = false; + int lastBindOffset = 0; + GLRInputLayout *lastDrawLayout = nullptr; + GLuint blendEqColor = (GLuint)-1; GLuint blendEqAlpha = (GLuint)-1; @@ -1176,16 +1181,19 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last if (buf != curArrayBuffer) { glBindBuffer(GL_ARRAY_BUFFER, buf); curArrayBuffer = buf; + // Invalidate any draw offset caching. + lastDrawLayout = nullptr; } + if (attrMask != layout->semanticsMask_) { EnableDisableVertexArrays(attrMask, layout->semanticsMask_); attrMask = layout->semanticsMask_; } - for (size_t i = 0; i < layout->entries.size(); i++) { - auto &entry = layout->entries[i]; - glVertexAttribPointer(entry.location, entry.count, entry.type, entry.normalized, layout->stride, (const void *)(c.draw.offset + entry.offset)); - } if (c.draw.indexBuffer) { + for (size_t i = 0; i < layout->entries.size(); i++) { + auto &entry = layout->entries[i]; + glVertexAttribPointer(entry.location, entry.count, entry.type, entry.normalized, layout->stride, (const void *)(c.draw.offset + entry.offset)); + } GLuint buf = c.draw.indexBuffer->buffer_; _dbg_assert_(!(c.draw.indexBuffer && c.draw.indexBuffer->Mapped())); if (buf != curElemArrayBuffer) { @@ -1197,9 +1205,31 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last } else { glDrawElementsInstanced(c.draw.mode, c.draw.count, c.draw.indexType, c.draw.indices, c.draw.instances); } + lastDrawIsArray = false; } else { - glDrawArrays(c.draw.mode, c.draw.first, c.draw.count); + // See if we can avoid calling glVertexAttribPointer. + int offset = 0; + bool rebind = true; + if (lastDrawIsArray && layout == lastDrawLayout) { + unsigned int diff = (unsigned int)c.draw.offset - (unsigned int)lastBindOffset; + if (diff % layout->stride == 0) { + // Compatible draws. + offset = diff / layout->stride; + rebind = false; + } + } + if (rebind) { + // Rebind. + for (size_t i = 0; i < layout->entries.size(); i++) { + auto &entry = layout->entries[i]; + glVertexAttribPointer(entry.location, entry.count, entry.type, entry.normalized, layout->stride, (const void *)(c.draw.offset + entry.offset)); + } + lastBindOffset = (int)c.draw.offset; + } + glDrawArrays(c.draw.mode, c.draw.first + offset, c.draw.count); + lastDrawIsArray = true; } + lastDrawLayout = layout; CHECK_GL_ERROR_IF_DEBUG(); break; } diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 6b7010d284..d5f6e88d09 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -362,7 +362,7 @@ public: intptr_t offset; }; std::vector entries; - int stride; + unsigned int stride; int semanticsMask_ = 0; };