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:
parent
848904e5b3
commit
4c18b62a00
@ -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;
|
||||
|
||||
|
@ -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]);
|
||||
|
@ -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"));
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user