[graphite] Move work and resource tracking to CommandBuffer base class.

Also adds test of texture copyback to CommandBufferTest, and
endEncoding() to BlitCommandEncoder.

Bug: skia:12466
Change-Id: I57e4646aacc1d950cc16b70d7feeced1a04e6867
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/462078
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/experimental/graphite/src/CommandBuffer.cpp b/experimental/graphite/src/CommandBuffer.cpp
index 5cd9961..c5407c5 100644
--- a/experimental/graphite/src/CommandBuffer.cpp
+++ b/experimental/graphite/src/CommandBuffer.cpp
@@ -11,6 +11,9 @@
 #include "experimental/graphite/src/RenderPipeline.h"
 #include "src/core/SkTraceEvent.h"
 
+#include "experimental/graphite/src/Buffer.h"
+#include "experimental/graphite/src/Texture.h"
+
 namespace skgpu {
 
 CommandBuffer::CommandBuffer() {}
@@ -21,10 +24,47 @@
     fTrackedResources.reset();
 }
 
+void CommandBuffer::beginRenderPass(const RenderPassDesc& renderPassDesc) {
+    this->onBeginRenderPass(renderPassDesc);
+
+    auto& colorInfo = renderPassDesc.fColorAttachment;
+    if (colorInfo.fTexture) {
+        this->trackResource(std::move(colorInfo.fTexture));
+    }
+    if (colorInfo.fStoreOp == StoreOp::kStore) {
+        fHasWork = true;
+    }
+}
+
 void CommandBuffer::setRenderPipeline(sk_sp<RenderPipeline> renderPipeline) {
     this->onSetRenderPipeline(renderPipeline);
     this->trackResource(std::move(renderPipeline));
     fHasWork = true;
 }
 
+static bool check_max_blit_width(int widthInPixels) {
+    if (widthInPixels > 32767) {
+        SkASSERT(false); // surfaces should not be this wide anyway
+        return false;
+    }
+    return true;
+}
+
+void CommandBuffer::copyTextureToBuffer(sk_sp<skgpu::Texture> texture,
+                                        SkIRect srcRect,
+                                        sk_sp<skgpu::Buffer> buffer,
+                                        size_t bufferOffset,
+                                        size_t bufferRowBytes) {
+    if (!check_max_blit_width(srcRect.width())) {
+        return;
+    }
+
+    this->onCopyTextureToBuffer(texture, srcRect, buffer, bufferOffset, bufferRowBytes);
+
+    this->trackResource(std::move(texture));
+    this->trackResource(std::move(buffer));
+
+    fHasWork = true;
+}
+
 } // namespace skgpu
diff --git a/experimental/graphite/src/CommandBuffer.h b/experimental/graphite/src/CommandBuffer.h
index cfc5fdc..3adb6e4c 100644
--- a/experimental/graphite/src/CommandBuffer.h
+++ b/experimental/graphite/src/CommandBuffer.h
@@ -9,6 +9,7 @@
 #define skgpu_CommandBuffer_DEFINED
 
 #include "experimental/graphite/include/private/GraphiteTypesPriv.h"
+#include "include/core/SkRect.h"
 #include "include/core/SkRefCnt.h"
 #include "include/private/SkTArray.h"
 
@@ -48,16 +49,16 @@
 
     bool hasWork() { return fHasWork; }
 
-    virtual void beginRenderPass(const RenderPassDesc&) = 0;
+    void beginRenderPass(const RenderPassDesc&);
     virtual void endRenderPass() = 0;
 
     void setRenderPipeline(sk_sp<RenderPipeline> renderPipeline);
 
-    virtual void copyTextureToBuffer(sk_sp<Texture>,
-                                     SkIRect srcRect,
-                                     sk_sp<Buffer>,
-                                     size_t bufferOffset,
-                                     size_t bufferRowBytes) = 0;
+    void copyTextureToBuffer(sk_sp<Texture>,
+                             SkIRect srcRect,
+                             sk_sp<Buffer>,
+                             size_t bufferOffset,
+                             size_t bufferRowBytes);
 
     void draw(PrimitiveType type, unsigned int vertexStart, unsigned int vertexCount) {
         this->onDraw(type, vertexStart, vertexCount);
@@ -70,6 +71,16 @@
     void trackResource(sk_sp<SkRefCnt> resource) {
         fTrackedResources.push_back(std::move(resource));
     }
+
+    virtual void onBeginRenderPass(const RenderPassDesc&) = 0;
+
+    virtual void onCopyTextureToBuffer(sk_sp<Texture>,
+                                       SkIRect srcRect,
+                                       sk_sp<Buffer>,
+                                       size_t bufferOffset,
+                                       size_t bufferRowBytes) = 0;
+
+private:
     void releaseResources();
 
     virtual void onSetRenderPipeline(sk_sp<RenderPipeline>&) = 0;
@@ -78,7 +89,6 @@
 
     bool fHasWork = false;
 
-private:
     inline static constexpr int kInitialTrackedResourcesCount = 32;
     SkSTArray<kInitialTrackedResourcesCount, sk_sp<SkRefCnt>> fTrackedResources;
 };
diff --git a/experimental/graphite/src/mtl/MtlBlitCommandEncoder.h b/experimental/graphite/src/mtl/MtlBlitCommandEncoder.h
index 1abe683..fdc38cc 100644
--- a/experimental/graphite/src/mtl/MtlBlitCommandEncoder.h
+++ b/experimental/graphite/src/mtl/MtlBlitCommandEncoder.h
@@ -56,6 +56,10 @@
                    destinationBytesPerImage: bufferRowBytes * srcRect.height()];
     }
 
+    void endEncoding() {
+        [(*fCommandEncoder) endEncoding];
+    }
+
 private:
     BlitCommandEncoder(sk_cfp<id<MTLBlitCommandEncoder>> encoder)
         : fCommandEncoder(std::move(encoder)) {}
diff --git a/experimental/graphite/src/mtl/MtlCommandBuffer.h b/experimental/graphite/src/mtl/MtlCommandBuffer.h
index 3248e92..1658946 100644
--- a/experimental/graphite/src/mtl/MtlCommandBuffer.h
+++ b/experimental/graphite/src/mtl/MtlCommandBuffer.h
@@ -41,23 +41,25 @@
     }
     bool commit();
 
-    void copyTextureToBuffer(sk_sp<skgpu::Texture>,
-                             SkIRect srcRect,
-                             sk_sp<skgpu::Buffer>,
-                             size_t bufferOffset,
-                             size_t bufferRowBytes) override;
-
 private:
     CommandBuffer(sk_cfp<id<MTLCommandBuffer>> cmdBuffer, const Gpu* gpu);
 
-    void beginRenderPass(const RenderPassDesc&) override;
+    void onBeginRenderPass(const RenderPassDesc&) override;
     void endRenderPass() override;
 
     void onSetRenderPipeline(sk_sp<skgpu::RenderPipeline>&) override;
 
     void onDraw(PrimitiveType type, unsigned int vertexStart, unsigned int vertexCount) override;
 
+    void onCopyTextureToBuffer(sk_sp<skgpu::Texture>,
+                               SkIRect srcRect,
+                               sk_sp<skgpu::Buffer>,
+                               size_t bufferOffset,
+                               size_t bufferRowBytes) override;
+
+
     BlitCommandEncoder* getBlitCommandEncoder();
+    void endBlitCommandEncoder();
 
     sk_cfp<id<MTLCommandBuffer>> fCommandBuffer;
     sk_sp<RenderCommandEncoder> fActiveRenderCommandEncoder;
diff --git a/experimental/graphite/src/mtl/MtlCommandBuffer.mm b/experimental/graphite/src/mtl/MtlCommandBuffer.mm
index ba7885e..bca53f7 100644
--- a/experimental/graphite/src/mtl/MtlCommandBuffer.mm
+++ b/experimental/graphite/src/mtl/MtlCommandBuffer.mm
@@ -13,7 +13,6 @@
 #include "experimental/graphite/src/mtl/MtlRenderCommandEncoder.h"
 #include "experimental/graphite/src/mtl/MtlRenderPipeline.h"
 #include "experimental/graphite/src/mtl/MtlTexture.h"
-#include "include/core/SkRect.h"
 
 namespace skgpu::mtl {
 
@@ -49,7 +48,8 @@
 CommandBuffer::~CommandBuffer() {}
 
 bool CommandBuffer::commit() {
-    // TODO: end any encoding
+    SkASSERT(!fActiveRenderCommandEncoder);
+    this->endBlitCommandEncoder();
     [(*fCommandBuffer) commit];
 
     // TODO: better error reporting
@@ -62,8 +62,9 @@
     return ((*fCommandBuffer).status != MTLCommandBufferStatusError);
 }
 
-void CommandBuffer::beginRenderPass(const RenderPassDesc& renderPassDesc) {
+void CommandBuffer::onBeginRenderPass(const RenderPassDesc& renderPassDesc) {
     SkASSERT(!fActiveRenderCommandEncoder);
+    this->endBlitCommandEncoder();
 
     auto& colorInfo = renderPassDesc.fColorAttachment;
 
@@ -103,14 +104,7 @@
     fActiveRenderCommandEncoder = RenderCommandEncoder::Make(fCommandBuffer.get(),
                                                              descriptor.get());
 
-    if (colorTexture) {
-        this->trackResource(std::move(colorInfo.fTexture));
-    }
     this->trackResource(fActiveRenderCommandEncoder);
-
-    if (colorInfo.fStoreOp == StoreOp::kStore) {
-        fHasWork = true;
-    }
 }
 
 void CommandBuffer::endRenderPass() {
@@ -119,14 +113,6 @@
     fActiveRenderCommandEncoder.reset();
 }
 
-static bool check_max_blit_width(int widthInPixels) {
-    if (widthInPixels > 32767) {
-        SkASSERT(false); // surfaces should not be this wide anyway
-        return false;
-    }
-    return true;
-}
-
 BlitCommandEncoder* CommandBuffer::getBlitCommandEncoder() {
     if (fActiveBlitCommandEncoder) {
         return fActiveBlitCommandEncoder.get();
@@ -144,17 +130,20 @@
     return fActiveBlitCommandEncoder.get();
 }
 
-void CommandBuffer::copyTextureToBuffer(sk_sp<skgpu::Texture> texture,
+void CommandBuffer::endBlitCommandEncoder() {
+    if (fActiveBlitCommandEncoder) {
+        fActiveBlitCommandEncoder->endEncoding();
+        fActiveBlitCommandEncoder.reset();
+    }
+}
+
+void CommandBuffer::onCopyTextureToBuffer(sk_sp<skgpu::Texture> texture,
                                         SkIRect srcRect,
                                         sk_sp<skgpu::Buffer> buffer,
                                         size_t bufferOffset,
                                         size_t bufferRowBytes) {
     SkASSERT(!fActiveRenderCommandEncoder);
 
-    if (!check_max_blit_width(srcRect.width())) {
-        return;
-    }
-
     id<MTLTexture> mtlTexture = static_cast<Texture*>(texture.get())->mtlTexture();
     id<MTLBuffer> mtlBuffer = static_cast<Buffer*>(buffer.get())->mtlBuffer();
 
@@ -174,11 +163,6 @@
 #ifdef SK_ENABLE_MTL_DEBUG_INFO
     blitCmdEncoder->popDebugGroup();
 #endif
-
-    this->trackResource(std::move(texture));
-    this->trackResource(std::move(buffer));
-
-    fHasWork = true;
 }
 
 void CommandBuffer::onSetRenderPipeline(sk_sp<skgpu::RenderPipeline>& renderPipeline) {
diff --git a/tests/graphite/CommandBufferTest.cpp b/tests/graphite/CommandBufferTest.cpp
index fb33523..179db27 100644
--- a/tests/graphite/CommandBufferTest.cpp
+++ b/tests/graphite/CommandBufferTest.cpp
@@ -11,6 +11,7 @@
 #include "experimental/graphite/src/ContextPriv.h"
 
 #include "experimental/graphite/include/mtl/MtlTypes.h"
+#include "experimental/graphite/src/Buffer.h"
 #include "experimental/graphite/src/CommandBuffer.h"
 #include "experimental/graphite/src/Gpu.h"
 #include "experimental/graphite/src/RenderPipeline.h"
@@ -52,8 +53,10 @@
 
     sk_sp<Texture> texture = gpu->resourceProvider()->findOrCreateTexture(textureSize,
                                                                           textureInfo);
+    REPORTER_ASSERT(reporter, texture);
+
     RenderPassDesc renderPassDesc = {};
-    renderPassDesc.fColorAttachment.fTexture = std::move(texture);
+    renderPassDesc.fColorAttachment.fTexture = texture;
     renderPassDesc.fColorAttachment.fLoadOp = LoadOp::kClear;
     renderPassDesc.fColorAttachment.fStoreOp = StoreOp::kStore;
     renderPassDesc.fClearColor = { 1, 0, 0, 1 };
@@ -67,10 +70,21 @@
 
     commandBuffer->endRenderPass();
 
+    sk_sp<Buffer> buffer = gpu->resourceProvider()->findOrCreateBuffer(1024*768*4,
+                                                                       BufferType::kXferGpuToCpu,
+                                                                       PrioritizeGpuReads::kNo);
+    REPORTER_ASSERT(reporter, buffer);
+    SkIRect srcRect = { 0, 0, 1024, 768 };
+    size_t rowBytes = 1024*4;
+    commandBuffer->copyTextureToBuffer(texture, srcRect, buffer, 0, rowBytes);
+
     bool result = gpu->submit(commandBuffer);
     REPORTER_ASSERT(reporter, result);
 
     gpu->checkForFinishedWork(skgpu::SyncToCpu::kYes);
+    uint32_t* pixels = (uint32_t*)(buffer->map());
+    REPORTER_ASSERT(reporter, pixels[0] == 0xffff0000);
+
 #if GRAPHITE_TEST_UTILS && CAPTURE_COMMANDBUFFER
     gpu->testingOnly_endCapture();
 #endif