Move CopyOps to CopyRenderTask.

This also means copies are no longer part of OpList or GpuCommandBuffer.

Change-Id: I234de2c93ca13e069d7e4423a3c8b292be2eb500
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/235831
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrCopyRenderTask.cpp b/src/gpu/GrCopyRenderTask.cpp
new file mode 100644
index 0000000..6c41370
--- /dev/null
+++ b/src/gpu/GrCopyRenderTask.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/gpu/GrCopyRenderTask.h"
+
+#include "src/gpu/GrGpu.h"
+#include "src/gpu/GrOpFlushState.h"
+#include "src/gpu/GrResourceAllocator.h"
+
+sk_sp<GrRenderTask> GrCopyRenderTask::Make(sk_sp<GrSurfaceProxy> srcProxy,
+                                           const SkIRect& srcRect,
+                                           sk_sp<GrSurfaceProxy> dstProxy,
+                                           const SkIPoint& dstPoint) {
+    SkASSERT(dstProxy);
+    SkASSERT(srcProxy);
+    SkIRect clippedSrcRect;
+    SkIPoint clippedDstPoint;
+    // If the rect is outside the srcProxy or dstProxy then we've already succeeded.
+    if (!GrClipSrcRectAndDstPoint(dstProxy->isize(), srcProxy->isize(), srcRect, dstPoint,
+                                  &clippedSrcRect, &clippedDstPoint)) {
+        return nullptr;
+    }
+    if (GrPixelConfigIsCompressed(dstProxy->config())) {
+        return nullptr;
+    }
+
+    SkASSERT(dstProxy->origin() == srcProxy->origin());
+    if (srcProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
+        int rectHeight = clippedSrcRect.height();
+        clippedSrcRect.fTop = srcProxy->height() - clippedSrcRect.fBottom;
+        clippedSrcRect.fBottom = clippedSrcRect.fTop + rectHeight;
+        clippedDstPoint.fY = dstProxy->height() - clippedDstPoint.fY - rectHeight;
+    }
+
+    sk_sp<GrCopyRenderTask> task(new GrCopyRenderTask(
+            std::move(srcProxy), clippedSrcRect, std::move(dstProxy), clippedDstPoint));
+    return task;
+}
+
+GrCopyRenderTask::GrCopyRenderTask(sk_sp<GrSurfaceProxy> srcProxy,
+                                   const SkIRect& srcRect,
+                                   sk_sp<GrSurfaceProxy> dstProxy,
+                                   const SkIPoint& dstPoint)
+        : GrRenderTask(std::move(dstProxy))
+        , fSrcProxy(std::move(srcProxy))
+        , fSrcRect(srcRect)
+        , fDstPoint(dstPoint) {
+    fTarget->setLastRenderTask(this);
+}
+
+void GrCopyRenderTask::gatherProxyIntervals(GrResourceAllocator* alloc) const {
+    // This renderTask doesn't have "normal" ops. In this case we still need to add an interval (so
+    // fEndOfOpListOpIndices will remain in sync), so we create a fake op# to capture the fact that
+    // we read fSrcProxy and copy to fTarget.
+    alloc->addInterval(fSrcProxy.get(), alloc->curOp(), alloc->curOp(),
+                       GrResourceAllocator::ActualUse::kYes);
+    alloc->addInterval(fTarget.get(), alloc->curOp(), alloc->curOp(),
+                       GrResourceAllocator::ActualUse::kYes);
+    alloc->incOps();
+}
+
+bool GrCopyRenderTask::onExecute(GrOpFlushState* flushState) {
+    if (!fSrcProxy->isInstantiated() || !fTarget->isInstantiated()) {
+        return false;
+    }
+    GrSurface* srcSurface = fSrcProxy->peekSurface();
+    GrSurface* dstSurface = fTarget->peekSurface();
+    if (fSrcProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
+        if (fSrcProxy->height() != srcSurface->height()) {
+            fSrcRect.offset(0, srcSurface->height() - fSrcProxy->height());
+        }
+        if (fTarget->height() != dstSurface->height()) {
+            fDstPoint.fY = fDstPoint.fY + (dstSurface->height() - fTarget->height());
+        }
+    }
+    return flushState->gpu()->copySurface(dstSurface, srcSurface, fSrcRect, fDstPoint);
+}
+