Implement support for indirect draws

Change-Id: Ib1c0570d747bf9f46be3486f37eba3af53ed1e3d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/281642
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/GrOpsRenderPass.cpp b/src/gpu/GrOpsRenderPass.cpp
index 8167363..060b9fc 100644
--- a/src/gpu/GrOpsRenderPass.cpp
+++ b/src/gpu/GrOpsRenderPass.cpp
@@ -265,6 +265,61 @@
     this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance, baseVertex);
 }
 
+void GrOpsRenderPass::drawIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
+                                   int drawCount) {
+    SkASSERT(this->gpu()->caps()->drawInstancedSupport());
+    SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
+             !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
+    if (!this->prepareToDraw()) {
+        return;
+    }
+    SkASSERT(!fHasIndexBuffer);
+    SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
+    SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
+    if (!this->gpu()->caps()->nativeDrawIndirectSupport()) {
+        // Polyfill indirect draws with looping instanced calls.
+        SkASSERT(drawIndirectBuffer->isCpuBuffer());
+        auto cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
+        auto cmd = reinterpret_cast<const GrDrawIndirectCommand*>(
+                cpuIndirectBuffer->data() + bufferOffset);
+        auto end = cmd + drawCount;
+        for (; cmd != end; ++cmd) {
+            this->onDrawInstanced(cmd->fInstanceCount, cmd->fBaseInstance, cmd->fVertexCount,
+                                  cmd->fBaseVertex);
+        }
+        return;
+    }
+    this->onDrawIndirect(drawIndirectBuffer, bufferOffset, drawCount);
+}
+
+void GrOpsRenderPass::drawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
+                                          int drawCount) {
+    SkASSERT(this->gpu()->caps()->drawInstancedSupport());
+    SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
+             !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
+    if (!this->prepareToDraw()) {
+        return;
+    }
+    SkASSERT(fHasIndexBuffer);
+    SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
+    SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
+    if (!this->gpu()->caps()->nativeDrawIndirectSupport() ||
+        this->gpu()->caps()->nativeDrawIndexedIndirectIsBroken()) {
+        // Polyfill indexedIndirect draws with looping indexedInstanced calls.
+        SkASSERT(drawIndirectBuffer->isCpuBuffer());
+        auto cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
+        auto cmd = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(
+                cpuIndirectBuffer->data() + bufferOffset);
+        auto end = cmd + drawCount;
+        for (; cmd != end; ++cmd) {
+            this->onDrawIndexedInstanced(cmd->fIndexCount, cmd->fBaseIndex, cmd->fInstanceCount,
+                                         cmd->fBaseInstance, cmd->fBaseVertex);
+        }
+        return;
+    }
+    this->onDrawIndexedIndirect(drawIndirectBuffer, bufferOffset, drawCount);
+}
+
 void GrOpsRenderPass::drawIndexPattern(int patternIndexCount, int patternRepeatCount,
                                        int maxPatternRepetitionsInIndexBuffer,
                                        int patternVertexCount, int baseVertex) {