Add GrOpsRenderPass::bindPipeline()

Clients now must call bindPipeline() before drawing.

Also renames GrOpsRenderPass::draw() to drawMeshes(), in order to
ensure every call site gets updated. drawMeshes() will soon be
replaced by individual calls for each draw type (indexed, instanced,
indexed-patterned, indirect, etc.).

Change-Id: I93ef579ded7d0048c5aa1bf1d7c0eb7bc1cd27b2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/270424
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/GrOpsRenderPass.cpp b/src/gpu/GrOpsRenderPass.cpp
index 8626ada..dd511f7 100644
--- a/src/gpu/GrOpsRenderPass.cpp
+++ b/src/gpu/GrOpsRenderPass.cpp
@@ -26,41 +26,53 @@
     // be redirected to draws instead
     SkASSERT(!this->gpu()->caps()->performColorClearsAsDraws());
     SkASSERT(!clip.scissorEnabled() || !this->gpu()->caps()->performPartialClearsAsDraws());
+    fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
     this->onClear(clip, color);
 }
 
 void GrOpsRenderPass::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
     // As above, make sure the stencil clear wasn't supposed to be a draw rect with stencil settings
     SkASSERT(!this->gpu()->caps()->performStencilClearsAsDraws());
+    fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
     this->onClearStencilClip(clip, insideStencilMask);
 }
 
-bool GrOpsRenderPass::draw(const GrProgramInfo& programInfo,
-                           const GrMesh meshes[], int meshCount, const SkRect& bounds) {
-    if (!meshCount) {
-        return true;
-    }
+void GrOpsRenderPass::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
+    fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
+    this->onExecuteDrawable(std::move(drawable));
+}
 
+void GrOpsRenderPass::bindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) {
 #ifdef SK_DEBUG
-    SkASSERT(GrPrimitiveType::kPatches != programInfo.primitiveType() ||
-             this->gpu()->caps()->shaderCaps()->tessellationSupport());
-    SkASSERT(!programInfo.primProc().hasInstanceAttributes() ||
-             this->gpu()->caps()->instanceAttribSupport());
-    SkASSERT(!programInfo.pipeline().usesConservativeRaster() ||
-             this->gpu()->caps()->conservativeRasterSupport());
-    SkASSERT(!programInfo.pipeline().isWireframe() ||
-             this->gpu()->caps()->wireframeSupport());
-
-    programInfo.compatibleWithMeshes(meshes, meshCount, *this->gpu()->caps());
+    if (programInfo.primProc().hasInstanceAttributes()) {
+         SkASSERT(this->gpu()->caps()->instanceAttribSupport());
+    }
+    if (programInfo.pipeline().usesConservativeRaster()) {
+        SkASSERT(this->gpu()->caps()->conservativeRasterSupport());
+        // Conservative raster, by default, only supports triangles. Implementations can
+        // optionally indicate that they also support points and lines, but we don't currently
+        // query or track that info.
+        SkASSERT(GrIsPrimTypeTris(programInfo.primitiveType()));
+    }
+    if (programInfo.pipeline().isWireframe()) {
+         SkASSERT(this->gpu()->caps()->wireframeSupport());
+    }
+    if (GrPrimitiveType::kPatches == programInfo.primitiveType()) {
+        SkASSERT(this->gpu()->caps()->shaderCaps()->tessellationSupport());
+    }
     programInfo.checkAllInstantiated();
     programInfo.checkMSAAAndMIPSAreResolved();
 #endif
 
     if (programInfo.primProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
-        this->gpu()->stats()->incNumFailedDraws();
-        return false;
+        fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
+        return;
     }
-    this->onDraw(programInfo, meshes, meshCount, bounds);
+
+    if (!this->onBindPipeline(programInfo, drawBounds)) {
+        fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
+        return;
+    }
 
 #ifdef SK_DEBUG
     GrProcessor::CustomFeatures processorFeatures = programInfo.requestedFeatures();
@@ -70,5 +82,34 @@
                          == fRenderTarget->renderTargetPriv().getSamplePatternKey());
     }
 #endif
-    return true;
+
+    fDrawPipelineStatus = DrawPipelineStatus::kOk;
+}
+
+void GrOpsRenderPass::drawMeshes(const GrProgramInfo& programInfo, const GrMesh meshes[],
+                                 int meshCount) {
+    if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
+        SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
+        this->gpu()->stats()->incNumFailedDraws();
+        return;
+    }
+
+#ifdef SK_DEBUG
+    if (int numDynamicStateArrays = programInfo.numDynamicStateArrays()) {
+        SkASSERT(meshCount == numDynamicStateArrays);
+    }
+    for (int i = 0; i < meshCount; ++i) {
+        SkASSERT(programInfo.primProc().hasVertexAttributes() ==
+                 SkToBool(meshes[i].vertexBuffer()));
+        SkASSERT(programInfo.primProc().hasInstanceAttributes() ==
+                 SkToBool(meshes[i].instanceBuffer()));
+        if (GrPrimitiveRestart::kYes == meshes[i].primitiveRestart()) {
+             SkASSERT(this->gpu()->caps()->usePrimitiveRestart());
+        }
+    }
+#endif
+
+    if (meshCount) {
+        this->onDrawMeshes(programInfo, meshes, meshCount);
+    }
 }