Manage renderCmdEncoder over lifetime of GrMtlOpsRenderPass.

Rather than create a renderCmdEncoder per draw, we create it up front
and each draw just uses it. On a clear or upload we switch away and
then recreate it.

Bug: skia:
Change-Id: Ic6d612119ed3f7c41183d0186083deae14f96398
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/270841
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm
index 5436a54..5bc35cd 100644
--- a/src/gpu/mtl/GrMtlCaps.mm
+++ b/src/gpu/mtl/GrMtlCaps.mm
@@ -1057,7 +1057,7 @@
     }
 #endif
 
-    b.add32(programInfo.pipeline().isStencilEnabled()
+    b.add32(rt->renderTargetPriv().getStencilAttachment()
                                  ? this->preferredStencilFormat().fInternalFormat
                                  : MTLPixelFormatInvalid);
     b.add32((uint32_t)programInfo.pipeline().isStencilEnabled());
diff --git a/src/gpu/mtl/GrMtlOpsRenderPass.h b/src/gpu/mtl/GrMtlOpsRenderPass.h
index 28c953f..30f19ca 100644
--- a/src/gpu/mtl/GrMtlOpsRenderPass.h
+++ b/src/gpu/mtl/GrMtlOpsRenderPass.h
@@ -33,10 +33,7 @@
 
     void initRenderState(id<MTLRenderCommandEncoder>);
 
-    void inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) override {
-        // TODO: this could be more efficient
-        state->doUpload(upload);
-    }
+    void inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) override;
     void submit();
 
 private:
diff --git a/src/gpu/mtl/GrMtlOpsRenderPass.mm b/src/gpu/mtl/GrMtlOpsRenderPass.mm
index 5a30f6a..41cef25 100644
--- a/src/gpu/mtl/GrMtlOpsRenderPass.mm
+++ b/src/gpu/mtl/GrMtlOpsRenderPass.mm
@@ -29,14 +29,11 @@
 }
 
 GrMtlOpsRenderPass::~GrMtlOpsRenderPass() {
-    SkASSERT(nil == fActiveRenderCmdEncoder);
 }
 
 void GrMtlOpsRenderPass::precreateCmdEncoder() {
     // For clears, we may not have an associated draw. So we prepare a cmdEncoder that
     // will be submitted whether there's a draw or not.
-    SkASSERT(nil == fActiveRenderCmdEncoder);
-
     SkDEBUGCODE(id<MTLRenderCommandEncoder> cmdEncoder =)
             fGpu->commandBuffer()->getRenderCommandEncoder(fRenderPassDesc, nullptr, this);
     SkASSERT(nil != cmdEncoder);
@@ -49,6 +46,7 @@
     SkIRect iBounds;
     fBounds.roundOut(&iBounds);
     fGpu->submitIndirectCommandBuffer(fRenderTarget, fOrigin, &iBounds);
+    fActiveRenderCmdEncoder = nil;
 }
 
 GrMtlPipelineState* GrMtlOpsRenderPass::prepareDrawState(const GrProgramInfo& programInfo) {
@@ -78,10 +76,10 @@
         return;
     }
 
-    SkASSERT(nil == fActiveRenderCmdEncoder);
-    fActiveRenderCmdEncoder = fGpu->commandBuffer()->getRenderCommandEncoder(
-            fRenderPassDesc, pipelineState, this);
-    SkASSERT(fActiveRenderCmdEncoder);
+    if (!fActiveRenderCmdEncoder) {
+        fActiveRenderCmdEncoder =
+                fGpu->commandBuffer()->getRenderCommandEncoder(fRenderPassDesc, nullptr, this);
+    }
 
     [fActiveRenderCmdEncoder setRenderPipelineState:pipelineState->mtlPipelineState()];
     pipelineState->setDrawState(fActiveRenderCmdEncoder,
@@ -131,7 +129,6 @@
         mesh.sendToGpu(programInfo.primitiveType(), this);
     }
 
-    fActiveRenderCmdEncoder = nil;
     fBounds.join(bounds);
 }
 
@@ -162,6 +159,16 @@
     fRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionClear;
     this->precreateCmdEncoder();
     fRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
+    fActiveRenderCmdEncoder =
+            fGpu->commandBuffer()->getRenderCommandEncoder(fRenderPassDesc, nullptr, this);
+}
+
+void GrMtlOpsRenderPass::inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) {
+    // TODO: this could be more efficient
+    state->doUpload(upload);
+    // doUpload() creates a blitCommandEncoder, so we need to recreate a renderCommandEncoder
+    fActiveRenderCmdEncoder =
+            fGpu->commandBuffer()->getRenderCommandEncoder(fRenderPassDesc, nullptr, this);
 }
 
 void GrMtlOpsRenderPass::initRenderState(id<MTLRenderCommandEncoder> encoder) {
@@ -240,6 +247,12 @@
     } else {
         fBounds.setEmpty();
     }
+
+    // For now, we lazily create the renderCommandEncoder because we may have no draws,
+    // and an empty renderCommandEncoder can still produce output. This can cause issues
+    // when we've cleared a texture upon creation -- we'll subsequently discard the contents.
+    // This can be removed when that ordering is fixed.
+    fActiveRenderCmdEncoder = nil;
 }
 
 static MTLPrimitiveType gr_to_mtl_primitive(GrPrimitiveType primitiveType) {