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
This commit is contained in:
csmartdalton 2016-07-29 12:19:28 -07:00 committed by Commit bot
parent 848904e5b3
commit 4c18b62a00
6 changed files with 74 additions and 49 deletions

View File

@ -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;

View File

@ -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]);

View File

@ -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"));

View File

@ -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;

View File

@ -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<Instance*>(fInstanceBuffer->map());
SkASSERT(glMappedInstances);
int glInstancesIdx = 0;
auto* glMappedCmds = static_cast<GrGLDrawElementsIndirectCommand*>(fDrawIndirectBuffer->map());
GrGLDrawElementsIndirectCommand* glMappedCmds = nullptr;
int glDrawCmdsIdx = 0;
if (fDrawIndirectBuffer) {
glMappedCmds = static_cast<GrGLDrawElementsIndirectCommand*>(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<const GLBatch*>(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;
}
}
}

View File

@ -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;