Implement GrGpu::transferFromBufferToBuffer on GL

Bug: skia:13427
Bug: skia:12720
Change-Id: Ic2cdebd86a814bed3bf22848218bbf355724a0e0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/550712
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/ganesh/gl/GrGLCaps.cpp b/src/gpu/ganesh/gl/GrGLCaps.cpp
index 026e4bd..e8ce6c5 100644
--- a/src/gpu/ganesh/gl/GrGLCaps.cpp
+++ b/src/gpu/ganesh/gl/GrGLCaps.cpp
@@ -544,6 +544,16 @@
         fTransferFromSurfaceToBufferSupport = false;
     }
 
+    if (GR_IS_GR_GL(standard) &&
+        (version >= GR_GL_VER(3, 1) || ctxInfo.hasExtension("GL_ARB_copy_buffer"))) {
+        fTransferFromBufferToBufferSupport = true;
+    } else if (GR_IS_GR_GL_ES(standard) &&
+               (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_NV_copy_buffer"))) {
+        fTransferFromBufferToBufferSupport = true;
+    } else if (GR_IS_GR_WEBGL(standard) && version >= GR_GL_VER(2,0)) {
+        fTransferFromBufferToBufferSupport = true;
+    }
+
     // On many GPUs, map memory is very expensive, so we effectively disable it here by setting the
     // threshold to the maximum unless the client gives us a hint that map memory is cheap.
     if (fBufferMapThreshold < 0) {
@@ -3691,6 +3701,10 @@
         fDisallowDynamicMSAA = true;
     }
 
+    // Below we are aggressive about turning off all mapping/transfer functionality together. This
+    // could be finer grained if code paths and tests were adjusted to check more specific caps.
+    // For example it might be possible to support buffer to buffer transfers even if buffer mapping
+    // or buffer to surface transfers don't work.
 #if defined(__has_feature)
 #if defined(SK_BUILD_FOR_MAC) && __has_feature(thread_sanitizer)
     // See skbug.com/7058
@@ -3698,6 +3712,7 @@
     fMapBufferFlags = kNone_MapFlags;
     fTransferFromBufferToTextureSupport = false;
     fTransferFromSurfaceToBufferSupport = false;
+    fTransferFromBufferToBufferSupport  = false;
     fTransferBufferType = TransferBufferType::kNone;
 #endif
 #endif
@@ -3712,6 +3727,7 @@
         fMapBufferFlags = kNone_MapFlags;
         fTransferFromBufferToTextureSupport = false;
         fTransferFromSurfaceToBufferSupport = false;
+        fTransferFromBufferToBufferSupport  = false;
         fTransferBufferType = TransferBufferType::kNone;
     }
 
diff --git a/src/gpu/ganesh/gl/GrGLGpu.cpp b/src/gpu/ganesh/gl/GrGLGpu.cpp
index cbce1e8..24b9c78 100644
--- a/src/gpu/ganesh/gl/GrGLGpu.cpp
+++ b/src/gpu/ganesh/gl/GrGLGpu.cpp
@@ -895,6 +895,28 @@
                                         mipLevelCount);
 }
 
+bool GrGLGpu::onTransferFromBufferToBuffer(sk_sp<GrGpuBuffer> src,
+                                           size_t srcOffset,
+                                           sk_sp<GrGpuBuffer> dst,
+                                           size_t dstOffset,
+                                           size_t size) {
+    auto glSrc = static_cast<const GrGLBuffer*>(src.get());
+    auto glDst = static_cast<const GrGLBuffer*>(dst.get());
+
+    // If we refactored bindBuffer() to use something other than GrGpuBufferType to indicate the
+    // binding target then we could use the COPY_READ and COPY_WRITE targets here. But
+    // CopyBufferSubData is documented to work with all the targets so it's not clear it's worth it.
+    this->bindBuffer(GrGpuBufferType::kXferCpuToGpu, glSrc);
+    this->bindBuffer(GrGpuBufferType::kXferGpuToCpu, glDst);
+
+    GL_CALL(CopyBufferSubData(GR_GL_PIXEL_UNPACK_BUFFER,
+                              GR_GL_PIXEL_PACK_BUFFER,
+                              srcOffset,
+                              dstOffset,
+                              size));
+    return true;
+}
+
 bool GrGLGpu::onTransferPixelsTo(GrTexture* texture,
                                  SkIRect rect,
                                  GrColorType textureColorType,
diff --git a/src/gpu/ganesh/gl/GrGLGpu.h b/src/gpu/ganesh/gl/GrGLGpu.h
index 3012fe5..18493b5 100644
--- a/src/gpu/ganesh/gl/GrGLGpu.h
+++ b/src/gpu/ganesh/gl/GrGLGpu.h
@@ -322,6 +322,12 @@
                        int mipLevelCount,
                        bool prepForTexSampling) override;
 
+    bool onTransferFromBufferToBuffer(sk_sp<GrGpuBuffer> src,
+                                      size_t srcOffset,
+                                      sk_sp<GrGpuBuffer> dst,
+                                      size_t dstOffset,
+                                      size_t size) override;
+
     bool onTransferPixelsTo(GrTexture*,
                             SkIRect,
                             GrColorType textureColorType,