From 4c18b62a004599d5a36ab7d772302dff2be91a3b Mon Sep 17 00:00:00 2001 From: csmartdalton Date: Fri, 29 Jul 2016 12:19:28 -0700 Subject: Add ES 3.0 fallback for instanced rendering Adds the ability for GLInstancedRendering to use glDrawElementsInstanced when glDrawElementsIndirect is not supported. The only remaining 3.1 dependency now is EXT_texture_buffer. Also moves the cap for glDraw*Instanced out of GrCaps and into GrGLCaps. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2193303002 Review-Url: https://codereview.chromium.org/2193303002 --- include/gpu/GrCaps.h | 5 -- src/gpu/GrCaps.cpp | 2 - src/gpu/gl/GrGLCaps.cpp | 15 +++-- src/gpu/gl/GrGLCaps.h | 4 ++ src/gpu/instanced/GLInstancedRendering.cpp | 93 +++++++++++++++++++----------- src/gpu/instanced/GLInstancedRendering.h | 4 +- 6 files changed, 74 insertions(+), 49 deletions(-) diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h index 0f39a5e485..c6b535d0bb 100644 --- a/include/gpu/GrCaps.h +++ b/include/gpu/GrCaps.h @@ -277,10 +277,6 @@ public: return fBufferMapThreshold; } - bool supportsInstancedDraws() const { - return fSupportsInstancedDraws; - } - bool fullClearIsFree() const { return fFullClearIsFree; } /** True in environments that will issue errors if memory uploaded to buffers @@ -314,7 +310,6 @@ protected: bool fMultisampleDisableSupport : 1; bool fUsesMixedSamples : 1; bool fPreferClientSideDynamicBuffers : 1; - bool fSupportsInstancedDraws : 1; bool fFullClearIsFree : 1; bool fMustClearUploadedBufferData : 1; diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp index fa4230f9fc..33c22be9a0 100644 --- a/src/gpu/GrCaps.cpp +++ b/src/gpu/GrCaps.cpp @@ -99,7 +99,6 @@ GrCaps::GrCaps(const GrContextOptions& options) { fMultisampleDisableSupport = false; fUsesMixedSamples = false; fPreferClientSideDynamicBuffers = false; - fSupportsInstancedDraws = false; fFullClearIsFree = false; fMustClearUploadedBufferData = false; fSampleShadingSupport = false; @@ -181,7 +180,6 @@ SkString GrCaps::dump() const { r.appendf("Multisample disable support : %s\n", gNY[fMultisampleDisableSupport]); r.appendf("Uses Mixed Samples : %s\n", gNY[fUsesMixedSamples]); r.appendf("Prefer client-side dynamic buffers : %s\n", gNY[fPreferClientSideDynamicBuffers]); - r.appendf("Supports instanced draws : %s\n", gNY[fSupportsInstancedDraws]); r.appendf("Full screen clear is free : %s\n", gNY[fFullClearIsFree]); r.appendf("Must clear buffer memory : %s\n", gNY[fMustClearUploadedBufferData]); r.appendf("Draw Instead of Clear [workaround] : %s\n", gNY[fUseDrawInsteadOfClear]); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 653b5ca725..5a1a5b459b 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -38,6 +38,7 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, fDirectStateAccessSupport = false; fDebugSupport = false; fES2CompatibilitySupport = false; + fDrawInstancedSupport = false; fDrawIndirectSupport = false; fMultiDrawIndirectSupport = false; fBaseInstanceSupport = false; @@ -502,12 +503,12 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, if (kGL_GrGLStandard == standard) { // 3.1 has draw_instanced but not instanced_arrays, for the time being we only care about // instanced arrays, but we could make this more granular if we wanted - fSupportsInstancedDraws = + fDrawInstancedSupport = version >= GR_GL_VER(3, 2) || (ctxInfo.hasExtension("GL_ARB_draw_instanced") && ctxInfo.hasExtension("GL_ARB_instanced_arrays")); } else { - fSupportsInstancedDraws = + fDrawInstancedSupport = version >= GR_GL_VER(3, 0) || (ctxInfo.hasExtension("GL_EXT_draw_instanced") && ctxInfo.hasExtension("GL_EXT_instanced_arrays")); @@ -518,12 +519,15 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, ctxInfo.hasExtension("GL_ARB_draw_indirect"); fBaseInstanceSupport = version >= GR_GL_VER(4,2); fMultiDrawIndirectSupport = version >= GR_GL_VER(4,3) || - (!fBaseInstanceSupport && // The ARB extension has no base inst. + (fDrawIndirectSupport && + !fBaseInstanceSupport && // The ARB extension has no base inst. ctxInfo.hasExtension("GL_ARB_multi_draw_indirect")); } else { fDrawIndirectSupport = version >= GR_GL_VER(3,1); - fMultiDrawIndirectSupport = ctxInfo.hasExtension("GL_EXT_multi_draw_indirect"); - fBaseInstanceSupport = ctxInfo.hasExtension("GL_EXT_base_instance"); + fMultiDrawIndirectSupport = fDrawIndirectSupport && + ctxInfo.hasExtension("GL_EXT_multi_draw_indirect"); + fBaseInstanceSupport = fDrawIndirectSupport && + ctxInfo.hasExtension("GL_EXT_base_instance"); } this->initShaderPrecisionTable(ctxInfo, gli, glslCaps); @@ -1105,6 +1109,7 @@ SkString GrGLCaps::dump() const { r.appendf("Vertex array object support: %s\n", (fVertexArrayObjectSupport ? "YES": "NO")); r.appendf("Direct state access support: %s\n", (fDirectStateAccessSupport ? "YES": "NO")); r.appendf("Debug support: %s\n", (fDebugSupport ? "YES": "NO")); + r.appendf("Draw instanced support: %s\n", (fDrawInstancedSupport ? "YES" : "NO")); r.appendf("Draw indirect support: %s\n", (fDrawIndirectSupport ? "YES" : "NO")); r.appendf("Multi draw indirect support: %s\n", (fMultiDrawIndirectSupport ? "YES" : "NO")); r.appendf("Base instance support: %s\n", (fBaseInstanceSupport ? "YES" : "NO")); diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index 0cb353aa9f..3408ae0e8f 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -296,6 +296,9 @@ public: /// Is there support for ES2 compatability? bool ES2CompatibilitySupport() const { return fES2CompatibilitySupport; } + /// Is there support for glDraw*Instanced? + bool drawInstancedSupport() const { return fDrawInstancedSupport; } + /// Is there support for glDraw*Indirect? Note that the baseInstance fields of indirect draw /// commands cannot be used unless we have base instance support. bool drawIndirectSupport() const { return fDrawIndirectSupport; } @@ -395,6 +398,7 @@ private: bool fDirectStateAccessSupport : 1; bool fDebugSupport : 1; bool fES2CompatibilitySupport : 1; + bool fDrawInstancedSupport : 1; bool fDrawIndirectSupport : 1; bool fMultiDrawIndirectSupport : 1; bool fBaseInstanceSupport : 1; diff --git a/src/gpu/instanced/GLInstancedRendering.cpp b/src/gpu/instanced/GLInstancedRendering.cpp index 440796e19a..3af1aa7ab3 100644 --- a/src/gpu/instanced/GLInstancedRendering.cpp +++ b/src/gpu/instanced/GLInstancedRendering.cpp @@ -34,7 +34,8 @@ private: GrCaps::InstancedSupport GLInstancedRendering::CheckSupport(const GrGLCaps& glCaps) { // This method is only intended to be used for initializing fInstancedSupport in the caps. SkASSERT(GrCaps::InstancedSupport::kNone == glCaps.instancedSupport()); - if (!glCaps.vertexArrayObjectSupport() || !glCaps.drawIndirectSupport()) { + if (!glCaps.vertexArrayObjectSupport() || + (!glCaps.drawIndirectSupport() && !glCaps.drawInstancedSupport())) { return GrCaps::InstancedSupport::kNone; } return InstanceProcessor::CheckSupport(*glCaps.glslCaps(), glCaps); @@ -118,23 +119,32 @@ void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) { } SkASSERT(!fDrawIndirectBuffer); - fDrawIndirectBuffer.reset( - rp->createBuffer(sizeof(GrGLDrawElementsIndirectCommand) * numGLDrawCmds, - kDrawIndirect_GrBufferType, kDynamic_GrAccessPattern, - GrResourceProvider::kNoPendingIO_Flag | - GrResourceProvider::kRequireGpuMemory_Flag)); - if (!fDrawIndirectBuffer) { - return; + if (this->glGpu()->glCaps().drawIndirectSupport()) { + fDrawIndirectBuffer.reset( + rp->createBuffer(sizeof(GrGLDrawElementsIndirectCommand) * numGLDrawCmds, + kDrawIndirect_GrBufferType, kDynamic_GrAccessPattern, + GrResourceProvider::kNoPendingIO_Flag | + GrResourceProvider::kRequireGpuMemory_Flag)); + if (!fDrawIndirectBuffer) { + return; + } } Instance* glMappedInstances = static_cast(fInstanceBuffer->map()); + SkASSERT(glMappedInstances); int glInstancesIdx = 0; - auto* glMappedCmds = static_cast(fDrawIndirectBuffer->map()); + GrGLDrawElementsIndirectCommand* glMappedCmds = nullptr; int glDrawCmdsIdx = 0; + if (fDrawIndirectBuffer) { + glMappedCmds = static_cast(fDrawIndirectBuffer->map()); + SkASSERT(glMappedCmds); + } bool baseInstanceSupport = this->glGpu()->glCaps().baseInstanceSupport(); + SkASSERT(!baseInstanceSupport || fDrawIndirectBuffer); + SkASSERT(!fGLDrawCmdsInfo); if (GR_GL_LOG_INSTANCED_BATCHES || !baseInstanceSupport) { fGLDrawCmdsInfo.reset(numGLDrawCmds); } @@ -160,18 +170,19 @@ void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) { draw = draw->fNext; } while (draw && draw->fGeometry == geometry); - GrGLDrawElementsIndirectCommand& glCmd = glMappedCmds[glDrawCmdsIdx]; - glCmd.fCount = geometry.fCount; - glCmd.fInstanceCount = instanceCount; - glCmd.fFirstIndex = geometry.fStart; - glCmd.fBaseVertex = 0; - glCmd.fBaseInstance = baseInstanceSupport ? glInstancesIdx : 0; + if (fDrawIndirectBuffer) { + GrGLDrawElementsIndirectCommand& glCmd = glMappedCmds[glDrawCmdsIdx]; + glCmd.fCount = geometry.fCount; + glCmd.fInstanceCount = instanceCount; + glCmd.fFirstIndex = geometry.fStart; + glCmd.fBaseVertex = 0; + glCmd.fBaseInstance = baseInstanceSupport ? glInstancesIdx : 0; + } if (GR_GL_LOG_INSTANCED_BATCHES || !baseInstanceSupport) { - fGLDrawCmdsInfo[glDrawCmdsIdx].fInstanceCount = instanceCount; -#if GR_GL_LOG_INSTANCED_BATCHES - fGLDrawCmdsInfo[glDrawCmdsIdx].fGeometry = geometry; -#endif + GLDrawCmdInfo& cmdInfo = fGLDrawCmdsInfo[glDrawCmdsIdx]; + cmdInfo.fGeometry = geometry; + cmdInfo.fInstanceCount = instanceCount; } glInstancesIdx += instanceCount; @@ -180,7 +191,9 @@ void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) { } SkASSERT(glDrawCmdsIdx == numGLDrawCmds); - fDrawIndirectBuffer->unmap(); + if (fDrawIndirectBuffer) { + fDrawIndirectBuffer->unmap(); + } SkASSERT(glInstancesIdx == numGLInstances); fInstanceBuffer->unmap(); @@ -188,14 +201,16 @@ void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) { void GLInstancedRendering::onDraw(const GrPipeline& pipeline, const InstanceProcessor& instProc, const Batch* baseBatch) { - if (!fDrawIndirectBuffer) { + if (!fDrawIndirectBuffer && !fGLDrawCmdsInfo) { return; // beginFlush was not successful. } if (!this->glGpu()->flushGLState(pipeline, instProc)) { return; } - this->glGpu()->bindBuffer(kDrawIndirect_GrBufferType, fDrawIndirectBuffer.get()); + if (fDrawIndirectBuffer) { + this->glGpu()->bindBuffer(kDrawIndirect_GrBufferType, fDrawIndirectBuffer.get()); + } const GrGLCaps& glCaps = this->glGpu()->glCaps(); const GLBatch* batch = static_cast(baseBatch); @@ -214,23 +229,33 @@ void GLInstancedRendering::onDraw(const GrPipeline& pipeline, const InstanceProc SkASSERT(SkToBool(fGLDrawCmdsInfo) == !glCaps.baseInstanceSupport()); #endif - if (1 == numCommands || !glCaps.baseInstanceSupport() || !glCaps.multiDrawIndirectSupport()) { - int emulatedBaseInstance = batch->fEmulatedBaseInstance; - for (int i = 0; i < numCommands; ++i) { - int glCmdIdx = batch->fGLDrawCmdsIdx + i; - this->flushInstanceAttribs(emulatedBaseInstance); - GL_CALL(DrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE, - (GrGLDrawElementsIndirectCommand*) nullptr + glCmdIdx)); - if (!glCaps.baseInstanceSupport()) { - emulatedBaseInstance += fGLDrawCmdsInfo[glCmdIdx].fInstanceCount; - } - } - } else { + if (numCommands > 1 && glCaps.multiDrawIndirectSupport() && glCaps.baseInstanceSupport()) { + SkASSERT(fDrawIndirectBuffer); int glCmdsIdx = batch->fGLDrawCmdsIdx; this->flushInstanceAttribs(batch->fEmulatedBaseInstance); GL_CALL(MultiDrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE, (GrGLDrawElementsIndirectCommand*) nullptr + glCmdsIdx, numCommands, 0)); + return; + } + + int emulatedBaseInstance = batch->fEmulatedBaseInstance; + for (int i = 0; i < numCommands; ++i) { + int glCmdIdx = batch->fGLDrawCmdsIdx + i; + const GLDrawCmdInfo& cmdInfo = fGLDrawCmdsInfo[glCmdIdx]; + this->flushInstanceAttribs(emulatedBaseInstance); + if (fDrawIndirectBuffer) { + GL_CALL(DrawElementsIndirect(GR_GL_TRIANGLES, GR_GL_UNSIGNED_BYTE, + (GrGLDrawElementsIndirectCommand*) nullptr + glCmdIdx)); + } else { + GL_CALL(DrawElementsInstanced(GR_GL_TRIANGLES, cmdInfo.fGeometry.fCount, + GR_GL_UNSIGNED_BYTE, + (GrGLubyte*) nullptr + cmdInfo.fGeometry.fStart, + cmdInfo.fInstanceCount)); + } + if (!glCaps.baseInstanceSupport()) { + emulatedBaseInstance += cmdInfo.fInstanceCount; + } } } diff --git a/src/gpu/instanced/GLInstancedRendering.h b/src/gpu/instanced/GLInstancedRendering.h index 4e17cb4535..ce1638c7fc 100644 --- a/src/gpu/instanced/GLInstancedRendering.h +++ b/src/gpu/instanced/GLInstancedRendering.h @@ -43,10 +43,8 @@ private: void flushInstanceAttribs(int baseInstance); struct GLDrawCmdInfo { - int fInstanceCount; -#if GR_GL_LOG_INSTANCED_BATCHES IndexRange fGeometry; -#endif + int fInstanceCount; }; GrGLuint fVertexArrayID; -- cgit v1.2.3