Revert "Revert "Add API for flushing surfaces with gpu semaphores""

This reverts commit 7292231905c34ed290ba479338f26b56ae2a7792.

This change relands the original plus the follow on change:
https://skia-review.googlesource.com/20059.

Additionally it adds a blacklist for the mac intel bots which
don't see to respect the added fences on the GPU.

Original change's description:
> Revert "Add API for flushing surfaces with gpu semaphores"
> 
> This reverts commit 66366c697853e906d961ae691e2bc5209cdcfa62.
> 
> Reason for revert: Failing test on mac bots
> 
> Original change's description:
> > Add API for flushing surfaces with gpu semaphores
> > 
> > BUG=skia:
> > 
> > Change-Id: Ia4bfef784cd5f2516ceccafce958be18a86f91d1
> > Reviewed-on: https://skia-review.googlesource.com/11488
> > Commit-Queue: Greg Daniel <egdaniel@google.com>
> > Reviewed-by: Brian Salomon <bsalomon@google.com>
> > Reviewed-by: Forrest Reiling <freiling@google.com>
> 
> TBR=egdaniel@google.com,jvanverth@google.com,bsalomon@google.com,brianosman@google.com,freiling@google.com
> 
> Change-Id: I75633a2732d2d48b1926f9ad818a9f1a9196d211
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:
> Reviewed-on: https://skia-review.googlesource.com/20063
> Commit-Queue: Greg Daniel <egdaniel@google.com>
> Reviewed-by: Greg Daniel <egdaniel@google.com>

TBR=egdaniel@google.com,jvanverth@google.com,bsalomon@google.com,brianosman@google.com,freiling@google.com

Change-Id: I4dc6c0e1deb0398eeb165a34f0a26af7a58259f1
Reviewed-on: https://skia-review.googlesource.com/20141
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 3c400a8..418b8b4 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -21,6 +21,7 @@
 #include <map>
 
 class GrBackendRenderTarget;
+class GrBackendSemaphore;
 class GrBuffer;
 class GrContext;
 struct GrContextOptions;
@@ -376,7 +377,9 @@
     virtual bool waitFence(GrFence, uint64_t timeout = 1000) = 0;
     virtual void deleteFence(GrFence) const = 0;
 
-    virtual sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore() = 0;
+    virtual sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned = true) = 0;
+    virtual sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+                                                    GrWrapOwnership ownership) = 0;
     virtual void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush = false) = 0;
     virtual void waitSemaphore(sk_sp<GrSemaphore> semaphore) = 0;
 
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index c5a115f..17a7db8 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -9,6 +9,7 @@
 #include "../private/GrAuditTrail.h"
 #include "../private/SkShadowFlags.h"
 #include "GrAppliedClip.h"
+#include "GrBackendSemaphore.h"
 #include "GrColor.h"
 #include "GrContextPriv.h"
 #include "GrDrawingManager.h"
@@ -38,6 +39,7 @@
 #include "ops/GrOvalOpFactory.h"
 #include "ops/GrRectOpFactory.h"
 #include "ops/GrRegionOp.h"
+#include "ops/GrSemaphoreOp.h"
 #include "ops/GrShadowRRectOp.h"
 #include "ops/GrStencilPathOp.h"
 #include "text/GrAtlasTextContext.h"
@@ -508,7 +510,7 @@
 
     const SkStrokeRec& stroke = style->strokeRec();
     if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
-        
+
         if (!fContext->caps()->useDrawInsteadOfClear()) {
             // Check if this is a full RT draw and can be replaced with a clear. We don't bother
             // checking cases where the RT is fully inside a stroke.
@@ -1429,13 +1431,44 @@
     this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
 }
 
-void GrRenderTargetContext::prepareForExternalIO() {
+void GrRenderTargetContext::prepareForExternalIO(int numSemaphores,
+                                                 GrBackendSemaphore* backendSemaphores) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::prepareForExternalIO");
 
+    SkTArray<sk_sp<GrSemaphore>> semaphores(numSemaphores);
+    for (int i = 0; i < numSemaphores; ++i) {
+        semaphores.push_back(fContext->resourceProvider()->makeSemaphore(false));
+        std::unique_ptr<GrOp> signalOp(GrSemaphoreOp::MakeSignal(semaphores.back(),
+                                                                 fRenderTargetProxy.get()));
+        this->getOpList()->addOp(std::move(signalOp), *this->caps());
+    }
+
     this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get());
+
+    for (int i = 0; i < numSemaphores; ++i) {
+        semaphores[i]->setBackendSemaphore(&backendSemaphores[i]);
+    }
+}
+
+void GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
+                                             const GrBackendSemaphore* waitSemaphores) {
+    ASSERT_SINGLE_OWNER
+    RETURN_IF_ABANDONED
+    SkDEBUGCODE(this->validate();)
+    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::waitOnSemaphores");
+
+    AutoCheckFlush acf(this->drawingManager());
+
+    SkTArray<sk_sp<GrSemaphore>> semaphores(numSemaphores);
+    for (int i = 0; i < numSemaphores; ++i) {
+        sk_sp<GrSemaphore> sema = fContext->resourceProvider()->wrapBackendSemaphore(
+                waitSemaphores[i], kAdopt_GrWrapOwnership);
+        std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(sema, fRenderTargetProxy.get()));
+        this->getOpList()->addOp(std::move(waitOp), *this->caps());
+    }
 }
 
 // Can 'path' be drawn as a pair of filled nested rectangles?
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index bc22604..a2369dd 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -19,6 +19,7 @@
 #include "SkRefCnt.h"
 #include "SkSurfaceProps.h"
 
+class GrBackendSemaphore;
 class GrClip;
 class GrDrawingManager;
 class GrDrawOp;
@@ -302,7 +303,13 @@
      * After this returns any pending surface IO will be issued to the backend 3D API and
      * if the surface has MSAA it will be resolved.
      */
-    void prepareForExternalIO();
+    void prepareForExternalIO(int numSemaphores, GrBackendSemaphore* backendSemaphores);
+
+    /**
+     *  The next time this GrRenderTargetContext is flushed, the gpu will wait on the passed in
+     *  semaphores before executing any commands.
+     */
+    void waitOnSemaphores(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
 
     GrFSAAType fsaaType() const { return fRenderTargetProxy->fsaaType(); }
     const GrCaps* caps() const { return fContext->caps(); }
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 52340bb..dccfaae 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -7,6 +7,7 @@
 
 #include "GrResourceProvider.h"
 
+#include "GrBackendSemaphore.h"
 #include "GrBuffer.h"
 #include "GrCaps.h"
 #include "GrContext.h"
@@ -505,8 +506,14 @@
     return this->gpu()->wrapBackendTextureAsRenderTarget(tex, origin, sampleCnt);
 }
 
-sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore() {
-    return fGpu->makeSemaphore();
+sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool isOwned) {
+    return fGpu->makeSemaphore(isOwned);
+}
+
+sk_sp<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+                                                            GrWrapOwnership ownership) {
+    ASSERT_SINGLE_OWNER
+    return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore, ownership);
 }
 
 void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h
index 50264ef..a6ddbc5 100644
--- a/src/gpu/GrResourceProvider.h
+++ b/src/gpu/GrResourceProvider.h
@@ -8,13 +8,14 @@
 #ifndef GrResourceProvider_DEFINED
 #define GrResourceProvider_DEFINED
 
-#include "GrBackendSurface.h"
 #include "GrBuffer.h"
 #include "GrPathRange.h"
 #include "SkImageInfo.h"
 #include "SkScalerContext.h"
 
 class GrBackendRenderTarget;
+class GrBackendSemaphore;
+class GrBackendTexture;
 class GrGpu;
 class GrPath;
 class GrRenderTarget;
@@ -227,7 +228,10 @@
      */
     GrGpuResource* findAndRefResourceByUniqueKey(const GrUniqueKey&);
 
-    sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore();
+    sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned = true);
+
+    sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore&,
+                                            GrWrapOwnership = kBorrow_GrWrapOwnership);
 
     // Takes the GrSemaphore and sets the ownership of the semaphore to the GrGpu object used by
     // this class. This call is only used when passing a GrSemaphore from one context to another.
diff --git a/src/gpu/GrSemaphore.h b/src/gpu/GrSemaphore.h
index b4843ff..f6148b0 100644
--- a/src/gpu/GrSemaphore.h
+++ b/src/gpu/GrSemaphore.h
@@ -10,6 +10,7 @@
 
 #include "SkRefCnt.h"
 
+class GrBackendSemaphore;
 class GrGpu;
 
 class GrSemaphore : public SkRefCnt {
@@ -20,9 +21,15 @@
     // GrSemaphore should not be used with its old context.
     void resetGpu(const GrGpu* gpu) { fGpu = gpu; }
 
+    // The derived class will init the GrBackendSemaphore. This is used when flushing with signal
+    // semaphores so we can set the clients GrBackendSemaphore object after we've created the
+    // internal semaphore.
+    virtual void setBackendSemaphore(GrBackendSemaphore*) const = 0;
+
 protected:
     explicit GrSemaphore(const GrGpu* gpu) : fGpu(gpu) {}
 
+    friend class GrRenderTargetContext; // setBackendSemaphore
     friend class GrResourceProvider; // resetGpu
 
     const GrGpu* fGpu;
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index be842ba..ee6e88d 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1730,10 +1730,23 @@
     return GrTextUtils::ShouldDisableLCD(paint);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
 void SkGpuDevice::flush() {
+    this->flushAndSignalSemaphores(0, nullptr);
+}
+
+void SkGpuDevice::flushAndSignalSemaphores(int numSemaphores,
+                                           GrBackendSemaphore* signalSemaphores) {
     ASSERT_SINGLE_OWNER
 
-    fRenderTargetContext->prepareForExternalIO();
+    fRenderTargetContext->prepareForExternalIO(numSemaphores, signalSemaphores);
+}
+
+void SkGpuDevice::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
+    ASSERT_SINGLE_OWNER
+
+    fRenderTargetContext->waitOnSemaphores(numSemaphores, waitSemaphores);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index 0b60a96..317533d 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -118,6 +118,8 @@
     sk_sp<SkSpecialImage> snapSpecial() override;
 
     void flush() override;
+    void flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores);
+    void wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
 
     bool onAccessPixels(SkPixmap*) override;
 
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index d52b73b..95791f1 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -599,7 +599,7 @@
     }
 
     if (kGL_GrGLStandard == standard) {
-        if ((version >= GR_GL_VER(4, 0) || ctxInfo.hasExtension("GL_ARB_sample_shading")) && 
+        if ((version >= GR_GL_VER(4, 0) || ctxInfo.hasExtension("GL_ARB_sample_shading")) &&
             ctxInfo.vendor() != kIntel_GrGLVendor) {
             fSampleShadingSupport = true;
         }
@@ -615,6 +615,12 @@
     } else if (version >= GR_GL_VER(3, 0)) {
         fFenceSyncSupport = true;
     }
+#ifdef SK_BUILD_FOR_MAC
+    if (kIntel_GrGLVendor == ctxInfo.vendor()) {
+        // See skia:6770
+        fFenceSyncSupport = false;
+    }
+#endif
 
     // Safely moving textures between contexts requires fences.
     fCrossContextTextureSupport = fFenceSyncSupport;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index b3f8c2c..d401600 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -9,6 +9,7 @@
 
 #include <cmath>
 #include "../private/GrGLSL.h"
+#include "GrBackendSemaphore.h"
 #include "GrBackendSurface.h"
 #include "GrFixedClip.h"
 #include "GrGLBuffer.h"
@@ -4288,10 +4289,16 @@
     this->deleteSync((GrGLsync)fence);
 }
 
-sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrGLGpu::makeSemaphore() {
-    return GrGLSemaphore::Make(this);
+sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrGLGpu::makeSemaphore(bool isOwned) {
+    return GrGLSemaphore::Make(this, isOwned);
 }
 
+sk_sp<GrSemaphore> GrGLGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+                                                 GrWrapOwnership ownership) {
+    return GrGLSemaphore::MakeWrapped(this, semaphore.glSync(), ownership);
+}
+
+
 void GrGLGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) {
     GrGLSemaphore* glSem = static_cast<GrGLSemaphore*>(semaphore.get());
 
@@ -4316,7 +4323,7 @@
 
 sk_sp<GrSemaphore> GrGLGpu::prepareTextureForCrossContextUsage(GrTexture* texture) {
     // Set up a semaphore to be signaled once the data is ready, and flush GL
-    sk_sp<GrSemaphore> semaphore = this->makeSemaphore();
+    sk_sp<GrSemaphore> semaphore = this->makeSemaphore(true);
     this->insertSemaphore(semaphore, true);
 
     return semaphore;
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index f121df3..80a12eb 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -166,7 +166,9 @@
     bool waitFence(GrFence, uint64_t timeout) override;
     void deleteFence(GrFence) const override;
 
-    sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore() override;
+    sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override;
+    sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+                                            GrWrapOwnership ownership) override;
     void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override;
     void waitSemaphore(sk_sp<GrSemaphore> semaphore) override;
 
diff --git a/src/gpu/gl/GrGLSemaphore.h b/src/gpu/gl/GrGLSemaphore.h
index f439ebd..cfc3de9 100644
--- a/src/gpu/gl/GrGLSemaphore.h
+++ b/src/gpu/gl/GrGLSemaphore.h
@@ -10,16 +10,26 @@
 
 #include "GrSemaphore.h"
 
-class GrGLGpu;
+#include "GrBackendSemaphore.h"
+#include "GrGLGpu.h"
 
 class GrGLSemaphore : public GrSemaphore {
 public:
-    static sk_sp<GrGLSemaphore> Make(const GrGLGpu* gpu) {
-        return sk_sp<GrGLSemaphore>(new GrGLSemaphore(gpu));
+    static sk_sp<GrGLSemaphore> Make(const GrGLGpu* gpu, bool isOwned) {
+        return sk_sp<GrGLSemaphore>(new GrGLSemaphore(gpu, isOwned));
+    }
+
+    static sk_sp<GrGLSemaphore> MakeWrapped(const GrGLGpu* gpu,
+                                            GrGLsync sync,
+                                            GrWrapOwnership ownership) {
+        auto sema = sk_sp<GrGLSemaphore>(new GrGLSemaphore(gpu,
+                                                           kBorrow_GrWrapOwnership != ownership));
+        sema->setSync(sync);
+        return sema;
     }
 
     ~GrGLSemaphore() override {
-        if (fGpu) {
+        if (fIsOwned && fGpu) {
             static_cast<const GrGLGpu*>(fGpu)->deleteSync(fSync);
         }
     }
@@ -28,9 +38,14 @@
     void setSync(const GrGLsync& sync) { fSync = sync; }
 
 private:
-    GrGLSemaphore(const GrGLGpu* gpu) : INHERITED(gpu), fSync(0) {}
+    GrGLSemaphore(const GrGLGpu* gpu, bool isOwned) : INHERITED(gpu), fSync(0), fIsOwned(isOwned) {}
+
+    void setBackendSemaphore(GrBackendSemaphore* backendSemaphore) const override {
+        backendSemaphore->initGL(fSync);
+    }
 
     GrGLsync fSync;
+    bool     fIsOwned;
 
     typedef GrSemaphore INHERITED;
 };
diff --git a/src/gpu/ops/GrSemaphoreOp.cpp b/src/gpu/ops/GrSemaphoreOp.cpp
index e83096d..f50d9c0 100644
--- a/src/gpu/ops/GrSemaphoreOp.cpp
+++ b/src/gpu/ops/GrSemaphoreOp.cpp
@@ -14,15 +14,17 @@
 public:
     DEFINE_OP_CLASS_ID
 
-    static std::unique_ptr<GrSignalSemaphoreOp> Make(sk_sp<GrSemaphore> semaphore) {
-        return std::unique_ptr<GrSignalSemaphoreOp>(new GrSignalSemaphoreOp(std::move(semaphore)));
+    static std::unique_ptr<GrSignalSemaphoreOp> Make(sk_sp<GrSemaphore> semaphore,
+                                                     GrRenderTargetProxy* proxy) {
+        return std::unique_ptr<GrSignalSemaphoreOp>(new GrSignalSemaphoreOp(std::move(semaphore),
+                                                                            proxy));
     }
 
     const char* name() const override { return "SignalSemaphore"; }
 
 private:
-    explicit GrSignalSemaphoreOp(sk_sp<GrSemaphore> semaphore)
-            : INHERITED(ClassID(), std::move(semaphore)) {}
+    explicit GrSignalSemaphoreOp(sk_sp<GrSemaphore> semaphore, GrRenderTargetProxy* proxy)
+            : INHERITED(ClassID(), std::move(semaphore), proxy) {}
 
     void onExecute(GrOpFlushState* state) override {
         state->gpu()->insertSemaphore(fSemaphore);
@@ -35,15 +37,17 @@
 public:
     DEFINE_OP_CLASS_ID
 
-    static std::unique_ptr<GrWaitSemaphoreOp> Make(sk_sp<GrSemaphore> semaphore) {
-        return std::unique_ptr<GrWaitSemaphoreOp>(new GrWaitSemaphoreOp(std::move(semaphore)));
+    static std::unique_ptr<GrWaitSemaphoreOp> Make(sk_sp<GrSemaphore> semaphore,
+                                                   GrRenderTargetProxy* proxy) {
+        return std::unique_ptr<GrWaitSemaphoreOp>(new GrWaitSemaphoreOp(std::move(semaphore),
+                                                                        proxy));
     }
 
     const char* name() const override { return "WaitSemaphore"; }
 
 private:
-    explicit GrWaitSemaphoreOp(sk_sp<GrSemaphore> semaphore)
-            : INHERITED(ClassID(), std::move(semaphore)) {}
+    explicit GrWaitSemaphoreOp(sk_sp<GrSemaphore> semaphore, GrRenderTargetProxy* proxy)
+            : INHERITED(ClassID(), std::move(semaphore), proxy) {}
 
     void onExecute(GrOpFlushState* state) override {
         state->gpu()->waitSemaphore(fSemaphore);
@@ -54,12 +58,14 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-std::unique_ptr<GrSemaphoreOp> GrSemaphoreOp::MakeSignal(sk_sp<GrSemaphore> semaphore) {
-    return GrSignalSemaphoreOp::Make(std::move(semaphore));
+std::unique_ptr<GrSemaphoreOp> GrSemaphoreOp::MakeSignal(sk_sp<GrSemaphore> semaphore,
+                                                         GrRenderTargetProxy* proxy) {
+    return GrSignalSemaphoreOp::Make(std::move(semaphore), proxy);
 }
 
-std::unique_ptr<GrSemaphoreOp> GrSemaphoreOp::MakeWait(sk_sp<GrSemaphore> semaphore) {
-    return GrWaitSemaphoreOp::Make(std::move(semaphore));
+std::unique_ptr<GrSemaphoreOp> GrSemaphoreOp::MakeWait(sk_sp<GrSemaphore> semaphore,
+                                                       GrRenderTargetProxy* proxy) {
+    return GrWaitSemaphoreOp::Make(std::move(semaphore), proxy);
 }
 
 
diff --git a/src/gpu/ops/GrSemaphoreOp.h b/src/gpu/ops/GrSemaphoreOp.h
index a88b66c..af9566a 100644
--- a/src/gpu/ops/GrSemaphoreOp.h
+++ b/src/gpu/ops/GrSemaphoreOp.h
@@ -10,18 +10,24 @@
 
 #include "GrOp.h"
 
+#include "GrRenderTargetProxy.h"
 #include "GrSemaphore.h"
 #include "SkRefCnt.h"
 
 class GrSemaphoreOp : public GrOp {
 public:
-    static std::unique_ptr<GrSemaphoreOp> MakeSignal(sk_sp<GrSemaphore> semaphore);
+    static std::unique_ptr<GrSemaphoreOp> MakeSignal(sk_sp<GrSemaphore> semaphore,
+                                                     GrRenderTargetProxy* proxy);
 
-    static std::unique_ptr<GrSemaphoreOp> MakeWait(sk_sp<GrSemaphore> semaphore);
+    static std::unique_ptr<GrSemaphoreOp> MakeWait(sk_sp<GrSemaphore> semaphore,
+                                                   GrRenderTargetProxy* proxy);
 
 protected:
-    GrSemaphoreOp(uint32_t classId, sk_sp<GrSemaphore> semaphore)
-        : INHERITED(classId), fSemaphore(std::move(semaphore)) {}
+    GrSemaphoreOp(uint32_t classId, sk_sp<GrSemaphore> semaphore, GrRenderTargetProxy* proxy)
+        : INHERITED(classId), fSemaphore(std::move(semaphore)) {
+        this->setBounds(SkRect::MakeIWH(proxy->width(), proxy->height()),
+                        HasAABloat::kNo, IsZeroArea::kNo);
+    }
 
     sk_sp<GrSemaphore> fSemaphore;
 
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index ea0a02c..63642d4 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -402,7 +402,7 @@
         const GrVkGpu* gpu,
         VkQueue queue,
         GrVkGpu::SyncQueue sync,
-        const GrVkSemaphore::Resource* signalSemaphore,
+        SkTArray<const GrVkSemaphore::Resource*>& signalSemaphores,
         SkTArray<const GrVkSemaphore::Resource*>& waitSemaphores) {
     SkASSERT(!fIsActive);
 
@@ -418,23 +418,20 @@
         GR_VK_CALL(gpu->vkInterface(), ResetFences(gpu->device(), 1, &fSubmitFence));
     }
 
-    if (signalSemaphore) {
-        this->addResource(signalSemaphore);
+    int signalCount = signalSemaphores.count();
+    SkTArray<VkSemaphore> vkSignalSem(signalCount);
+    for (int i = 0; i < signalCount; ++i) {
+        this->addResource(signalSemaphores[i]);
+        vkSignalSem.push_back(signalSemaphores[i]->semaphore());
     }
 
     int waitCount = waitSemaphores.count();
     SkTArray<VkSemaphore> vkWaitSems(waitCount);
     SkTArray<VkPipelineStageFlags> vkWaitStages(waitCount);
-    if (waitCount) {
-        for (int i = 0; i < waitCount; ++i) {
-            this->addResource(waitSemaphores[i]);
-            vkWaitSems.push_back(waitSemaphores[i]->semaphore());
-            vkWaitStages.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
-        }
-    }
-    SkTArray<VkSemaphore> vkSignalSem;
-    if (signalSemaphore) {
-        vkSignalSem.push_back(signalSemaphore->semaphore());
+    for (int i = 0; i < waitCount; ++i) {
+        this->addResource(waitSemaphores[i]);
+        vkWaitSems.push_back(waitSemaphores[i]->semaphore());
+        vkWaitStages.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
     }
 
     VkSubmitInfo submitInfo;
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index 1f3c4a5..b387885 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -298,7 +298,7 @@
                       const VkImageResolve* regions);
 
     void submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync,
-                       const GrVkSemaphore::Resource* signalSemaphore,
+                       SkTArray<const GrVkSemaphore::Resource*>& signalSemaphores,
                        SkTArray<const GrVkSemaphore::Resource*>& waitSemaphores);
     bool finished(const GrVkGpu* gpu) const;
 
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index f76f06c..b10e9ed 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -7,6 +7,7 @@
 
 #include "GrVkGpu.h"
 
+#include "GrBackendSemaphore.h"
 #include "GrBackendSurface.h"
 #include "GrContextOptions.h"
 #include "GrGeometryProcessor.h"
@@ -191,6 +192,12 @@
     }
     fSemaphoresToWaitOn.reset();
 
+    for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
+        fSemaphoresToSignal[i]->unref(this);
+    }
+    fSemaphoresToSignal.reset();
+
+
     fCopyManager.destroyResources(this);
 
     // must call this just before we destroy the command pool and VkDevice
@@ -226,12 +233,16 @@
             for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
                 fSemaphoresToWaitOn[i]->unrefAndAbandon();
             }
+            for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
+                fSemaphoresToSignal[i]->unrefAndAbandon();
+            }
             fCopyManager.abandonResources();
 
             // must call this just before we destroy the command pool and VkDevice
             fResourceProvider.abandonResources();
         }
         fSemaphoresToWaitOn.reset();
+        fSemaphoresToSignal.reset();
 #ifdef SK_ENABLE_VK_LAYERS
         fCallback = VK_NULL_HANDLE;
 #endif
@@ -249,17 +260,20 @@
     return new GrVkGpuCommandBuffer(this, colorInfo, stencilInfo);
 }
 
-void GrVkGpu::submitCommandBuffer(SyncQueue sync,
-                                  const GrVkSemaphore::Resource* signalSemaphore) {
+void GrVkGpu::submitCommandBuffer(SyncQueue sync) {
     SkASSERT(fCurrentCmdBuffer);
     fCurrentCmdBuffer->end(this);
 
-    fCurrentCmdBuffer->submitToQueue(this, fQueue, sync, signalSemaphore, fSemaphoresToWaitOn);
+    fCurrentCmdBuffer->submitToQueue(this, fQueue, sync, fSemaphoresToSignal, fSemaphoresToWaitOn);
 
     for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
         fSemaphoresToWaitOn[i]->unref(this);
     }
     fSemaphoresToWaitOn.reset();
+    for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
+        fSemaphoresToSignal[i]->unref(this);
+    }
+    fSemaphoresToSignal.reset();
 
     fResourceProvider.checkCommandBuffers();
 
@@ -1937,15 +1951,25 @@
     VK_CALL(DestroyFence(this->device(), (VkFence)fence, nullptr));
 }
 
-sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrVkGpu::makeSemaphore() {
-    return GrVkSemaphore::Make(this);
+sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrVkGpu::makeSemaphore(bool isOwned) {
+    return GrVkSemaphore::Make(this, isOwned);
 }
 
-void GrVkGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore, bool /*flush*/) {
+sk_sp<GrSemaphore> GrVkGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+                                                 GrWrapOwnership ownership) {
+    return GrVkSemaphore::MakeWrapped(this, semaphore.vkSemaphore(), ownership);
+}
+
+void GrVkGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) {
     GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore.get());
 
-    // We *always* flush, so ignore that parameter
-    this->submitCommandBuffer(kSkip_SyncQueue, vkSem->getResource());
+    const GrVkSemaphore::Resource* resource = vkSem->getResource();
+    resource->ref();
+    fSemaphoresToSignal.push_back(resource);
+
+    if (flush) {
+        this->submitCommandBuffer(kSkip_SyncQueue);
+    }
 }
 
 void GrVkGpu::waitSemaphore(sk_sp<GrSemaphore> semaphore) {
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index f81daea..236b34a 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -131,7 +131,9 @@
     bool waitFence(GrFence, uint64_t timeout) override;
     void deleteFence(GrFence) const override;
 
-    sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore() override;
+    sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override;
+    sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+                                            GrWrapOwnership ownership) override;
     void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override;
     void waitSemaphore(sk_sp<GrSemaphore> semaphore) override;
 
@@ -208,12 +210,11 @@
 
     // Ends and submits the current command buffer to the queue and then creates a new command
     // buffer and begins it. If sync is set to kForce_SyncQueue, the function will wait for all
-    // work in the queue to finish before returning. If the signalSemaphore is not VK_NULL_HANDLE,
-    // we will signal the semaphore at the end of this command buffer. If this GrVkGpu object has
-    // any semaphores in fSemaphoresToWaitOn, we will add those wait semaphores to this command
-    // buffer when submitting.
-    void submitCommandBuffer(SyncQueue sync,
-                             const GrVkSemaphore::Resource* signalSemaphore = nullptr);
+    // work in the queue to finish before returning. If this GrVkGpu object has any semaphores in
+    // fSemaphoreToSignal, we will add those signal semaphores to the submission of this command
+    // buffer. If this GrVkGpu object has any semaphores in fSemaphoresToWaitOn, we will add those
+    // wait semaphores to the submission of this command buffer.
+    void submitCommandBuffer(SyncQueue sync);
 
     void internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit);
 
@@ -267,6 +268,7 @@
     GrVkPrimaryCommandBuffer*                    fCurrentCmdBuffer;
 
     SkSTArray<1, const GrVkSemaphore::Resource*> fSemaphoresToWaitOn;
+    SkSTArray<1, const GrVkSemaphore::Resource*> fSemaphoresToSignal;
 
     VkPhysicalDeviceMemoryProperties             fPhysDevMemProps;
 
diff --git a/src/gpu/vk/GrVkSemaphore.cpp b/src/gpu/vk/GrVkSemaphore.cpp
index d84635f..d201458 100644
--- a/src/gpu/vk/GrVkSemaphore.cpp
+++ b/src/gpu/vk/GrVkSemaphore.cpp
@@ -7,6 +7,7 @@
 
 #include "GrVkSemaphore.h"
 
+#include "GrBackendSemaphore.h"
 #include "GrVkGpu.h"
 #include "GrVkUtil.h"
 
@@ -15,7 +16,7 @@
 #undef CreateSemaphore
 #endif
 
-sk_sp<GrVkSemaphore> GrVkSemaphore::Make(const GrVkGpu* gpu) {
+sk_sp<GrVkSemaphore> GrVkSemaphore::Make(const GrVkGpu* gpu, bool isOwned) {
     VkSemaphoreCreateInfo createInfo;
     memset(&createInfo, 0, sizeof(VkFenceCreateInfo));
     createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@@ -25,11 +26,22 @@
     GR_VK_CALL_ERRCHECK(gpu->vkInterface(),
                         CreateSemaphore(gpu->device(), &createInfo, nullptr, &semaphore));
 
-    return sk_sp<GrVkSemaphore>(new GrVkSemaphore(gpu, semaphore));
+    return sk_sp<GrVkSemaphore>(new GrVkSemaphore(gpu, semaphore, isOwned));
 }
 
-GrVkSemaphore::GrVkSemaphore(const GrVkGpu* gpu, VkSemaphore semaphore) : INHERITED(gpu) {
-    fResource = new Resource(semaphore);
+sk_sp<GrVkSemaphore> GrVkSemaphore::MakeWrapped(const GrVkGpu* gpu,
+                                                VkSemaphore semaphore,
+                                                GrWrapOwnership ownership) {
+    if (VK_NULL_HANDLE == semaphore) {
+        return nullptr;
+    }
+    return sk_sp<GrVkSemaphore>(new GrVkSemaphore(gpu, semaphore,
+                                                  kBorrow_GrWrapOwnership != ownership));
+}
+
+GrVkSemaphore::GrVkSemaphore(const GrVkGpu* gpu, VkSemaphore semaphore, bool isOwned)
+        : INHERITED(gpu) {
+    fResource = new Resource(semaphore, isOwned);
 }
 
 GrVkSemaphore::~GrVkSemaphore() {
@@ -41,7 +53,13 @@
 }
 
 void GrVkSemaphore::Resource::freeGPUData(const GrVkGpu* gpu) const {
-    GR_VK_CALL(gpu->vkInterface(),
-               DestroySemaphore(gpu->device(), fSemaphore, nullptr));
+    if (fIsOwned) {
+        GR_VK_CALL(gpu->vkInterface(),
+                   DestroySemaphore(gpu->device(), fSemaphore, nullptr));
+    }
+}
+
+void GrVkSemaphore::setBackendSemaphore(GrBackendSemaphore* backendSemaphore) const {
+    backendSemaphore->initVulkan(fResource->semaphore());
 }
 
diff --git a/src/gpu/vk/GrVkSemaphore.h b/src/gpu/vk/GrVkSemaphore.h
index 0a3bc17..b99eb94 100644
--- a/src/gpu/vk/GrVkSemaphore.h
+++ b/src/gpu/vk/GrVkSemaphore.h
@@ -13,17 +13,23 @@
 
 #include "vk/GrVkTypes.h"
 
+class GrBackendSemaphore;
 class GrVkGpu;
 
 class GrVkSemaphore : public GrSemaphore {
 public:
-    static sk_sp<GrVkSemaphore> Make(const GrVkGpu* gpu);
+    static sk_sp<GrVkSemaphore> Make(const GrVkGpu* gpu, bool isOwned);
+
+    static sk_sp<GrVkSemaphore> MakeWrapped(const GrVkGpu* gpu,
+                                            VkSemaphore semaphore,
+                                            GrWrapOwnership);
 
     ~GrVkSemaphore() override;
 
     class Resource : public GrVkResource {
     public:
-        Resource(VkSemaphore semaphore) : INHERITED(), fSemaphore(semaphore) {}
+        Resource(VkSemaphore semaphore, bool isOwned)
+                : INHERITED(), fSemaphore(semaphore), fIsOwned(isOwned) {}
 
         ~Resource() override {}
 
@@ -38,6 +44,7 @@
         void freeGPUData(const GrVkGpu* gpu) const override;
 
         VkSemaphore fSemaphore;
+        bool        fIsOwned;
 
         typedef GrVkResource INHERITED;
     };
@@ -45,7 +52,9 @@
     const Resource* getResource() const { return fResource; }
 
 private:
-    GrVkSemaphore(const GrVkGpu* gpu, VkSemaphore semaphore);
+    GrVkSemaphore(const GrVkGpu* gpu, VkSemaphore semaphore, bool isOwned);
+
+    void setBackendSemaphore(GrBackendSemaphore*) const override;
 
     const Resource* fResource;
 
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index cd2a5f1..fbd9f83 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -184,7 +184,19 @@
 }
 
 void SkSurface::prepareForExternalIO() {
-  asSB(this)->onPrepareForExternalIO();
+    this->flush();
+}
+
+void SkSurface::flush() {
+    asSB(this)->onFlush(0, nullptr);
+}
+
+void SkSurface::flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
+    return asSB(this)->onFlush(numSemaphores, signalSemaphores);
+}
+
+void SkSurface::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
+    asSB(this)->onWait(numSemaphores, waitSemaphores);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkSurface_Base.h b/src/image/SkSurface_Base.h
index 1b0f9ff..264a86f 100644
--- a/src/image/SkSurface_Base.h
+++ b/src/image/SkSurface_Base.h
@@ -77,8 +77,17 @@
 
     /**
      * Issue any pending surface IO to the current backend 3D API and resolve any surface MSAA.
+     * Inserts the requested number of semaphores for the gpu to signal when work is complete on the
+     * gpu and inits the array of GrBackendSemaphores with the signaled semaphores.
      */
-    virtual void onPrepareForExternalIO() {}
+    virtual void onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {}
+
+    /**
+     * Caused the current backend 3D API to wait on the passed in semaphores before executing new
+     * commands on the gpu. Any previously submitting commands will not be blocked by these
+     * semaphores.
+     */
+    virtual void onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {}
 
     inline SkCanvas* getCachedCanvas();
     inline sk_sp<SkImage> refCachedImage();
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index d558887..0f4b2cb 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -166,8 +166,12 @@
     fDevice->accessRenderTargetContext()->discard();
 }
 
-void SkSurface_Gpu::onPrepareForExternalIO() {
-    fDevice->flush();
+void SkSurface_Gpu::onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
+    fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
+}
+
+void SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
+    fDevice->wait(numSemaphores, waitSemaphores);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkSurface_Gpu.h b/src/image/SkSurface_Gpu.h
index cc8b87d..e22ae10 100644
--- a/src/image/SkSurface_Gpu.h
+++ b/src/image/SkSurface_Gpu.h
@@ -26,7 +26,8 @@
     sk_sp<SkImage> onNewImageSnapshot() override;
     void onCopyOnWrite(ContentChangeMode) override;
     void onDiscard() override;
-    void onPrepareForExternalIO() override;
+    void onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) override;
+    void onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) override;
 
     SkGpuDevice* getDevice() { return fDevice.get(); }