Revert "Revert "Add support for semaphores to be inserted on GrContext flush""

This reverts commit 8724b4609996eb6369b454611e31b065f3d8d2cf.

Reason for revert: Creating a test CL to see what happens on the bots

Original change's description:
> Revert "Add support for semaphores to be inserted on GrContext flush"
> 
> This reverts commit cd1416efbc7af6f115dbaa09dce48e075d1d96ca.
> 
> Reason for revert: speculative, to try to fix roll see gpu_tests.pixel_integration_test.PixelIntegrationTest.Pixel_GpuRasterization_ConcavePaths
> 
> Original change's description:
> > Add support for semaphores to be inserted on GrContext flush
> > 
> > This also moves the logic of inserting semaphores down into GrDrawingManager
> > and finishFlush on GrGpu. With it being on finishFlush, there should be no
> > issues when the DrawingManager starts respecting the proxy passed in assuming
> > it always calls finishFlush at the end (which it should).
> > 
> > Bug: skia:
> > Change-Id: I925c2a289dcbbb9159b9120878af1d34f21a2dc7
> > Reviewed-on: https://skia-review.googlesource.com/25641
> > Reviewed-by: Brian Salomon <bsalomon@google.com>
> > Commit-Queue: Greg Daniel <egdaniel@google.com>
> 
> TBR=egdaniel@google.com,bsalomon@google.com,robertphillips@google.com
> 
> Change-Id: I9c5b9cf8c060193e1861dbb8f0c10fb11dfb5249
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:
> Reviewed-on: https://skia-review.googlesource.com/25980
> Reviewed-by: Mike Reed <reed@google.com>
> Commit-Queue: Mike Reed <reed@google.com>

TBR=egdaniel@google.com,bsalomon@google.com,robertphillips@google.com,reed@google.com

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: skia:
Change-Id: I5edbeaa0769670ee58f362f0ccaa78319410aa6c
Reviewed-on: https://skia-review.googlesource.com/26160
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/include/core/SkSurface.h b/include/core/SkSurface.h
index 4a8d812..a531c42 100644
--- a/include/core/SkSurface.h
+++ b/include/core/SkSurface.h
@@ -12,6 +12,8 @@
 #include "SkImage.h"
 #include "SkSurfaceProps.h"
 
+#include "GrTypes.h"
+
 class SkCanvas;
 class SkPaint;
 class GrBackendRenderTarget;
@@ -329,16 +331,21 @@
      * If it is not initialized, a new semaphore is created and the GrBackendSemaphore object
      * is initialized with that semaphore.
      *
+     * The client will own and be responsible for deleting the underlying semaphores that are stored
+     * and returned in initialized GrBackendSemaphore objects. The GrBackendSemaphore objects
+     * themselves can be deleted as soon as this function returns.
+     *
      * If the backend API is OpenGL only uninitialized GrBackendSemaphores are supported.
      * If the backend API is Vulkan either initialized or unitialized semaphores are supported.
      * If unitialized, the semaphores which are created will be valid for use only with the VkDevice
      * with which they were created.
      *
-     * If this call returns false, the GPU backend will not have created or added any semaphores to
-     * signal. Thus the array of semaphores will remain uninitialized. However, any pending surface
-     * IO will still be flush.
+     * If this call returns GrSemaphoresSubmited::kNo, the GPU backend will not have created or
+     * added any semaphores to signal on the GPU. Thus the client should not have the GPU wait on
+     * any of the semaphores. However, any pending surface IO will still be flushed.
      */
-    bool flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores);
+    GrSemaphoresSubmitted flushAndSignalSemaphores(int numSemaphores,
+                                                   GrBackendSemaphore signalSemaphores[]);
 
     /**
      * Inserts a list of GPU semaphores that the current backend 3D API must wait on before
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index b5d2f74..7a14a7d 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -17,6 +17,7 @@
 #include "../private/GrSingleOwner.h"
 
 class GrAtlasGlyphCache;
+class GrBackendSemaphore;
 struct GrContextOptions;
 class GrContextPriv;
 class GrContextThreadSafeProxy;
@@ -252,12 +253,35 @@
     // Misc.
 
     /**
-     * Call to ensure all drawing to the context has been issued to the
-     * underlying 3D API.
+     * Call to ensure all drawing to the context has been issued to the underlying 3D API.
      */
     void flush();
 
     /**
+     * Call to ensure all drawing to the context has been issued to the underlying 3D API. After
+     * issuing all commands, numSemaphore semaphores will be signaled by the gpu. The client passes
+     * in an array of numSemaphores GrBackendSemaphores. In general these GrBackendSemaphore's can
+     * be either initialized or not. If they are initialized, the backend uses the passed in
+     * semaphore. If it is not initialized, a new semaphore is created and the GrBackendSemaphore
+     * object is initialized with that semaphore.
+     *
+     * The client will own and be responsible for deleting the underlying semaphores that are stored
+     * and returned in initialized GrBackendSemaphore objects. The GrBackendSemaphore objects
+     * themselves can be deleted as soon as this function returns.
+     *
+     * If the backend API is OpenGL only uninitialized GrBackendSemaphores are supported.
+     * If the backend API is Vulkan either initialized or unitialized semaphores are supported.
+     * If unitialized, the semaphores which are created will be valid for use only with the VkDevice
+     * with which they were created.
+     *
+     * If this call returns GrSemaphoresSubmited::kNo, the GPU backend will not have created or
+     * added any semaphores to signal on the GPU. Thus the client should not have the GPU wait on
+     * any of the semaphores. However, any pending commands to the context will still be flushed.
+     */
+    GrSemaphoresSubmitted flushAndSignalSemaphores(int numSemaphores,
+                                                   GrBackendSemaphore signalSemaphores[]);
+
+    /**
      * An ID associated with this context, guaranteed to be unique.
      */
     uint32_t uniqueID() { return fUniqueID; }
diff --git a/include/gpu/GrTypes.h b/include/gpu/GrTypes.h
index 572aa52..68c5327 100644
--- a/include/gpu/GrTypes.h
+++ b/include/gpu/GrTypes.h
@@ -705,4 +705,12 @@
  */
 static const uint32_t kAll_GrBackendState = 0xffffffff;
 
+// Enum used as return value when flush with semaphores so the client knows whether the
+// semaphores were submitted to GPU or not.
+enum class GrSemaphoresSubmitted : int {
+    kNo,
+    kYes,
+};
+
+
 #endif
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 347f0b5..a0cf5f5 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "GrBackendSemaphore.h"
 #include "GrContext.h"
 #include "GrClip.h"
 #include "GrContextOptions.h"
@@ -334,6 +335,14 @@
     fDrawingManager->flush(nullptr);
 }
 
+GrSemaphoresSubmitted GrContext::flushAndSignalSemaphores(int numSemaphores,
+                                                          GrBackendSemaphore signalSemaphores[]) {
+    ASSERT_SINGLE_OWNER
+    if (fDrawingManager->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; }
+
+    return fDrawingManager->flush(nullptr, numSemaphores, signalSemaphores);
+}
+
 void GrContextPriv::flush(GrSurfaceProxy* proxy) {
     ASSERT_SINGLE_OWNER_PRIV
     RETURN_IF_ABANDONED_PRIV
@@ -668,7 +677,7 @@
     RETURN_IF_ABANDONED_PRIV
     SkASSERT(proxy);
     ASSERT_OWNED_PROXY_PRIV(proxy);
-    fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy);
+    fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy, 0, nullptr);
 }
 
 void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) {
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index eeb1071..9e7372c 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -7,6 +7,7 @@
 
 #include "GrDrawingManager.h"
 
+#include "GrBackendSemaphore.h"
 #include "GrContext.h"
 #include "GrGpu.h"
 #include "GrOnFlushResourceProvider.h"
@@ -83,11 +84,14 @@
 }
 
 // MDB TODO: make use of the 'proxy' parameter.
-void GrDrawingManager::internalFlush(GrSurfaceProxy*, GrResourceCache::FlushType type) {
+GrSemaphoresSubmitted GrDrawingManager::internalFlush(GrSurfaceProxy*,
+                                                      GrResourceCache::FlushType type,
+                                                      int numSemaphores,
+                                                      GrBackendSemaphore backendSemaphores[]) {
     GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawingManager", "internalFlush", fContext);
 
     if (fFlushing || this->wasAbandoned()) {
-        return;
+        return GrSemaphoresSubmitted::kNo;
     }
     fFlushing = true;
     bool flushed = false;
@@ -190,7 +194,8 @@
 
     SkASSERT(fFlushState.nextDrawToken() == fFlushState.nextTokenToFlush());
 
-    fContext->getGpu()->finishFlush();
+    GrSemaphoresSubmitted result = fContext->getGpu()->finishFlush(numSemaphores,
+                                                                   backendSemaphores);
 
     fFlushState.reset();
     // We always have to notify the cache when it requested a flush so it can reset its state.
@@ -201,20 +206,24 @@
         onFlushCBObject->postFlush();
     }
     fFlushing = false;
+
+    return result;
 }
 
-void GrDrawingManager::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
+GrSemaphoresSubmitted GrDrawingManager::prepareSurfaceForExternalIO(
+        GrSurfaceProxy* proxy, int numSemaphores, GrBackendSemaphore backendSemaphores[]) {
     if (this->wasAbandoned()) {
-        return;
+        return GrSemaphoresSubmitted::kNo;
     }
     SkASSERT(proxy);
 
-    if (proxy->priv().hasPendingIO()) {
-        this->flush(proxy);
+    GrSemaphoresSubmitted result;
+    if (proxy->priv().hasPendingIO() || numSemaphores) {
+        result = this->flush(proxy, numSemaphores, backendSemaphores);
     }
 
     if (!proxy->instantiate(fContext->resourceProvider())) {
-        return;
+        return result;
     }
 
     GrSurface* surface = proxy->priv().peekSurface();
@@ -222,6 +231,7 @@
     if (fContext->getGpu() && surface->asRenderTarget()) {
         fContext->getGpu()->resolveRenderTarget(surface->asRenderTarget());
     }
+    return result;
 }
 
 void GrDrawingManager::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
diff --git a/src/gpu/GrDrawingManager.h b/src/gpu/GrDrawingManager.h
index e7995fd..6a1ad19 100644
--- a/src/gpu/GrDrawingManager.h
+++ b/src/gpu/GrDrawingManager.h
@@ -64,13 +64,15 @@
 
     void flushIfNecessary() {
         if (fContext->getResourceCache()->requestsFlush()) {
-            this->internalFlush(nullptr, GrResourceCache::kCacheRequested);
+            this->internalFlush(nullptr, GrResourceCache::kCacheRequested, 0, nullptr);
         }
     }
 
     static bool ProgramUnitTest(GrContext* context, int maxStages, int maxLevels);
 
-    void prepareSurfaceForExternalIO(GrSurfaceProxy*);
+    GrSemaphoresSubmitted prepareSurfaceForExternalIO(GrSurfaceProxy*,
+                                                      int numSemaphores,
+                                                      GrBackendSemaphore backendSemaphores[]);
 
     void addOnFlushCallbackObject(GrOnFlushCallbackObject*);
     void testingOnly_removeOnFlushCallbackObject(GrOnFlushCallbackObject*);
@@ -93,10 +95,16 @@
     void abandon();
     void cleanup();
     void reset();
-    void flush(GrSurfaceProxy* proxy) {
-        this->internalFlush(proxy, GrResourceCache::FlushType::kExternal);
+    GrSemaphoresSubmitted flush(GrSurfaceProxy* proxy,
+                                int numSemaphores = 0,
+                                GrBackendSemaphore backendSemaphores[] = nullptr) {
+        return this->internalFlush(proxy, GrResourceCache::FlushType::kExternal,
+                                   numSemaphores, backendSemaphores);
     }
-    void internalFlush(GrSurfaceProxy*, GrResourceCache::FlushType);
+    GrSemaphoresSubmitted internalFlush(GrSurfaceProxy*,
+                                        GrResourceCache::FlushType,
+                                        int numSemaphores,
+                                        GrBackendSemaphore backendSemaphores[]);
 
     friend class GrContext;  // for access to: ctor, abandon, reset & flush
     friend class GrContextPriv; // access to: flush
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 3487f6f..f237cce 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -8,6 +8,7 @@
 
 #include "GrGpu.h"
 
+#include "GrBackendSemaphore.h"
 #include "GrBackendSurface.h"
 #include "GrBuffer.h"
 #include "GrCaps.h"
@@ -19,6 +20,7 @@
 #include "GrRenderTargetPriv.h"
 #include "GrResourceCache.h"
 #include "GrResourceProvider.h"
+#include "GrSemaphore.h"
 #include "GrStencilAttachment.h"
 #include "GrStencilSettings.h"
 #include "GrSurfacePriv.h"
@@ -513,3 +515,26 @@
     }
     return false; // Equal.
 }
+
+GrSemaphoresSubmitted GrGpu::finishFlush(int numSemaphores,
+                                         GrBackendSemaphore backendSemaphores[]) {
+    if (this->caps()->fenceSyncSupport()) {
+        for (int i = 0; i < numSemaphores; ++i) {
+            sk_sp<GrSemaphore> semaphore;
+            if (backendSemaphores[i].isInitialized()) {
+                semaphore = fContext->resourceProvider()->wrapBackendSemaphore(
+                        backendSemaphores[i], kBorrow_GrWrapOwnership);
+            } else {
+                semaphore = fContext->resourceProvider()->makeSemaphore(false);
+            }
+            this->insertSemaphore(semaphore, false);
+
+            if (!backendSemaphores[i].isInitialized()) {
+                semaphore->setBackendSemaphore(&backendSemaphores[i]);
+            }
+        }
+    }
+    this->onFinishFlush((numSemaphores > 0 && this->caps()->fenceSyncSupport()));
+    return this->caps()->fenceSyncSupport() ? GrSemaphoresSubmitted::kYes
+                                            : GrSemaphoresSubmitted::kNo;
+}
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 27a2d79..1da8d0e 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -375,8 +375,10 @@
             const GrGpuCommandBuffer::LoadAndStoreInfo& stencilInfo) = 0;
 
     // Called by GrDrawingManager when flushing.
-    // Provides a hook for post-flush actions (e.g. Vulkan command buffer submits).
-    virtual void finishFlush() {}
+    // Provides a hook for post-flush actions (e.g. Vulkan command buffer submits). This will also
+    // insert any numSemaphore semaphores on the gpu and set the backendSemaphores to match the
+    // inserted semaphores.
+    GrSemaphoresSubmitted finishFlush(int numSemaphores, GrBackendSemaphore backendSemaphores[]);
 
     virtual GrFence SK_WARN_UNUSED_RESULT insertFence() = 0;
     virtual bool waitFence(GrFence, uint64_t timeout = 1000) = 0;
@@ -614,6 +616,8 @@
     virtual void onQueryMultisampleSpecs(GrRenderTarget*, const GrStencilSettings&,
                                          int* effectiveSampleCnt, SamplePattern*) = 0;
 
+    virtual void onFinishFlush(bool insertedSemaphores) = 0;
+
     void resetContext() {
         this->onResetContext(fResetBits);
         fResetBits = 0;
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 66a707b..d54b084 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -1409,42 +1409,16 @@
     this->addDrawOp(clip, std::move(op));
 }
 
-bool GrRenderTargetContext::prepareForExternalIO(int numSemaphores,
-                                                 GrBackendSemaphore* backendSemaphores) {
+GrSemaphoresSubmitted GrRenderTargetContext::prepareForExternalIO(
+        int numSemaphores, GrBackendSemaphore backendSemaphores[]) {
     ASSERT_SINGLE_OWNER
-    RETURN_FALSE_IF_ABANDONED
+    if (this->drawingManager()->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; }
     SkDEBUGCODE(this->validate();)
     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "prepareForExternalIO", fContext);
 
-    if (numSemaphores && !this->caps()->fenceSyncSupport()) {
-        this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get());
-        return false;
-    }
-
-    SkTArray<sk_sp<GrSemaphore>> semaphores(numSemaphores);
-    for (int i = 0; i < numSemaphores; ++i) {
-        if (backendSemaphores[i].isInitialized()) {
-            semaphores.push_back(fContext->resourceProvider()->wrapBackendSemaphore(
-                    backendSemaphores[i], kBorrow_GrWrapOwnership));
-        } else {
-            semaphores.push_back(fContext->resourceProvider()->makeSemaphore(false));
-        }
-        // Create signal semaphore ops and force the final one to call flush.
-        bool forceFlush = (i == (numSemaphores - 1));
-        std::unique_ptr<GrOp> signalOp(GrSemaphoreOp::MakeSignal(semaphores.back(),
-                                                                 fRenderTargetProxy.get(),
-                                                                 forceFlush));
-        this->getRTOpList()->addOp(std::move(signalOp), *this->caps());
-    }
-
-    this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get());
-
-    for (int i = 0; i < numSemaphores; ++i) {
-        if (!backendSemaphores[i].isInitialized()) {
-            semaphores[i]->setBackendSemaphore(&backendSemaphores[i]);
-        }
-    }
-    return true;
+    return this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get(),
+                                                               numSemaphores,
+                                                               backendSemaphores);
 }
 
 bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index 1958ed7..964d9e9 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -303,7 +303,8 @@
      * 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.
      */
-    bool prepareForExternalIO(int numSemaphores, GrBackendSemaphore* backendSemaphores);
+    GrSemaphoresSubmitted prepareForExternalIO(int numSemaphores,
+                                               GrBackendSemaphore backendSemaphores[]);
 
     /**
      *  The next time this GrRenderTargetContext is flushed, the gpu will wait on the passed in
diff --git a/src/gpu/GrSemaphore.h b/src/gpu/GrSemaphore.h
index f6148b0..fbc5a6d 100644
--- a/src/gpu/GrSemaphore.h
+++ b/src/gpu/GrSemaphore.h
@@ -29,6 +29,7 @@
 protected:
     explicit GrSemaphore(const GrGpu* gpu) : fGpu(gpu) {}
 
+    friend class GrGpu; // setBackendSemaphore
     friend class GrRenderTargetContext; // setBackendSemaphore
     friend class GrResourceProvider; // resetGpu
 
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 57b2d41..607165c 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1734,8 +1734,8 @@
     this->flushAndSignalSemaphores(0, nullptr);
 }
 
-bool SkGpuDevice::flushAndSignalSemaphores(int numSemaphores,
-                                           GrBackendSemaphore* signalSemaphores) {
+GrSemaphoresSubmitted SkGpuDevice::flushAndSignalSemaphores(int numSemaphores,
+                                                            GrBackendSemaphore signalSemaphores[]) {
     ASSERT_SINGLE_OWNER
 
     return fRenderTargetContext->prepareForExternalIO(numSemaphores, signalSemaphores);
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index 3fc3807..f1bd937 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -118,7 +118,8 @@
     sk_sp<SkSpecialImage> snapSpecial() override;
 
     void flush() override;
-    bool flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores);
+    GrSemaphoresSubmitted flushAndSignalSemaphores(int numSemaphores,
+                                                   GrBackendSemaphore signalSemaphores[]);
     bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
 
     bool onAccessPixels(SkPixmap*) override;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 6247850..a126e1a 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -4337,6 +4337,13 @@
     return false;
 }
 
+void GrGLGpu::onFinishFlush(bool insertedSemaphore) {
+    // If we inserted semaphores during the flush, we need to call GLFlush.
+    if (insertedSemaphore) {
+        GL_CALL(Flush());
+    }
+}
+
 GrFence SK_WARN_UNUSED_RESULT GrGLGpu::insertFence() {
     SkASSERT(this->caps()->fenceSyncSupport());
     GrGLsync sync;
@@ -4366,7 +4373,6 @@
     return GrGLSemaphore::MakeWrapped(this, semaphore.glSync(), ownership);
 }
 
-
 void GrGLGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) {
     GrGLSemaphore* glSem = static_cast<GrGLSemaphore*>(semaphore.get());
 
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 5acf806..f8f4a6e 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -286,6 +286,8 @@
 
     void flushBlend(const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle&);
 
+    void onFinishFlush(bool insertedSemaphores) override;
+
     bool hasExtension(const char* ext) const { return fGLContext->hasExtension(ext); }
 
     bool copySurfaceAsDraw(GrSurface* dst,
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index a56c201..f5a187e 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -124,6 +124,8 @@
 
     void onResolveRenderTarget(GrRenderTarget* target) override { return; }
 
+    void onFinishFlush(bool insertedSemaphores) override {}
+
     GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
                                                                 int width,
                                                                 int height) override;
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index 53c2149..c812843 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -130,6 +130,8 @@
 
     void onResolveRenderTarget(GrRenderTarget* target) override { return; }
 
+    void onFinishFlush(bool insertedSemaphores) override {}
+
     GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
                                                                 int width,
                                                                 int height) override {
diff --git a/src/gpu/vk/GrVkCopyManager.cpp b/src/gpu/vk/GrVkCopyManager.cpp
index 938596f..040d742 100644
--- a/src/gpu/vk/GrVkCopyManager.cpp
+++ b/src/gpu/vk/GrVkCopyManager.cpp
@@ -160,7 +160,7 @@
 
     if (gpu->vkCaps().newCBOnPipelineChange()) {
         // We bind a new pipeline here for the copy so we must start a new command buffer.
-        gpu->finishFlush();
+        gpu->finishFlush(0, nullptr);
     }
 
     GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(dst->asRenderTarget());
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 31e55de..6da40e5 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1468,8 +1468,9 @@
                                        barrier);
 }
 
-void GrVkGpu::finishFlush() {
-    // Submit the current command buffer to the Queue
+void GrVkGpu::onFinishFlush(bool insertedSemaphore) {
+    // Submit the current command buffer to the Queue. Whether we inserted semaphores or not does
+    // not effect what we do here.
     this->submitCommandBuffer(kSkip_SyncQueue);
 }
 
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 7e95ca4..2a44785 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -127,8 +127,6 @@
                                       GrVkRenderTarget*,
                                       const SkIRect& bounds);
 
-    void finishFlush() override;
-
     GrFence SK_WARN_UNUSED_RESULT insertFence() override;
     bool waitFence(GrFence, uint64_t timeout) override;
     void deleteFence(GrFence) const override;
@@ -212,6 +210,8 @@
                           GrPixelConfig config, GrBuffer* transferBuffer,
                           size_t offset, size_t rowBytes) override;
 
+    void onFinishFlush(bool insertedSemaphores) override;
+
     // 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 this GrVkGpu object has any semaphores in
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index 29068b2..ead0062 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -200,7 +200,8 @@
     asSB(this)->onFlush(0, nullptr);
 }
 
-bool SkSurface::flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
+GrSemaphoresSubmitted SkSurface::flushAndSignalSemaphores(int numSemaphores,
+                                                          GrBackendSemaphore signalSemaphores[]) {
     return asSB(this)->onFlush(numSemaphores, signalSemaphores);
 }
 
diff --git a/src/image/SkSurface_Base.h b/src/image/SkSurface_Base.h
index 93528b8..8cf75b6 100644
--- a/src/image/SkSurface_Base.h
+++ b/src/image/SkSurface_Base.h
@@ -80,8 +80,9 @@
      * 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 bool onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
-        return false;
+    virtual GrSemaphoresSubmitted onFlush(int numSemaphores,
+                                          GrBackendSemaphore signalSemaphores[]) {
+        return GrSemaphoresSubmitted::kNo;
     }
 
     /**
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 37aa07a..9f469e3 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -149,7 +149,8 @@
     fDevice->accessRenderTargetContext()->discard();
 }
 
-bool SkSurface_Gpu::onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
+GrSemaphoresSubmitted SkSurface_Gpu::onFlush(int numSemaphores,
+                                             GrBackendSemaphore signalSemaphores[]) {
     return fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
 }
 
diff --git a/src/image/SkSurface_Gpu.h b/src/image/SkSurface_Gpu.h
index 2bc9210..ebf7d4e 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;
-    bool onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) override;
+    GrSemaphoresSubmitted onFlush(int numSemaphores,
+                                  GrBackendSemaphore signalSemaphores[]) override;
     bool onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) override;
 
     SkGpuDevice* getDevice() { return fDevice.get(); }
diff --git a/tests/SurfaceSemaphoreTest.cpp b/tests/SurfaceSemaphoreTest.cpp
index cd3b8e5..bb726c2 100644
--- a/tests/SurfaceSemaphoreTest.cpp
+++ b/tests/SurfaceSemaphoreTest.cpp
@@ -108,7 +108,8 @@
 void surface_semaphore_test(skiatest::Reporter* reporter,
                             const sk_gpu_test::ContextInfo& mainInfo,
                             const sk_gpu_test::ContextInfo& childInfo1,
-                            const sk_gpu_test::ContextInfo& childInfo2) {
+                            const sk_gpu_test::ContextInfo& childInfo2,
+                            bool flushContext) {
     GrContext* mainCtx = mainInfo.grContext();
     if (!mainCtx->caps()->fenceSyncSupport()) {
         return;
@@ -143,7 +144,11 @@
     }
 #endif
 
-    mainSurface->flushAndSignalSemaphores(2, semaphores.get());
+    if (flushContext) {
+        mainCtx->flushAndSignalSemaphores(2, semaphores.get());
+    } else {
+        mainSurface->flushAndSignalSemaphores(2, semaphores.get());
+    }
 
     sk_sp<SkImage> mainImage = mainSurface->makeImageSnapshot();
     GrBackendObject backendImage = mainImage->getTextureHandle(false);
@@ -171,31 +176,35 @@
 #endif
 
     for (int typeInt = 0; typeInt < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++typeInt) {
-        sk_gpu_test::GrContextFactory::ContextType contextType =
-                (sk_gpu_test::GrContextFactory::ContextType) typeInt;
-        // Use "native" instead of explicitly trying OpenGL and OpenGL ES. Do not use GLES on
-        // desktop since tests do not account for not fixing http://skbug.com/2809
-        if (contextType == sk_gpu_test::GrContextFactory::kGL_ContextType ||
-            contextType == sk_gpu_test::GrContextFactory::kGLES_ContextType) {
-            if (contextType != kNativeGLType) {
+        for (auto flushContext : { false, true }) {
+            sk_gpu_test::GrContextFactory::ContextType contextType =
+                    (sk_gpu_test::GrContextFactory::ContextType) typeInt;
+            // Use "native" instead of explicitly trying OpenGL and OpenGL ES. Do not use GLES on
+            // desktop since tests do not account for not fixing http://skbug.com/2809
+            if (contextType == sk_gpu_test::GrContextFactory::kGL_ContextType ||
+                contextType == sk_gpu_test::GrContextFactory::kGLES_ContextType) {
+                if (contextType != kNativeGLType) {
+                    continue;
+                }
+            }
+            sk_gpu_test::ContextInfo ctxInfo = factory->getContextInfo(
+                    contextType, sk_gpu_test::GrContextFactory::ContextOverrides::kDisableNVPR);
+            if (!sk_gpu_test::GrContextFactory::IsRenderingContext(contextType)) {
                 continue;
             }
-        }
-        sk_gpu_test::ContextInfo ctxInfo = factory->getContextInfo(
-                contextType, sk_gpu_test::GrContextFactory::ContextOverrides::kDisableNVPR);
-        if (!sk_gpu_test::GrContextFactory::IsRenderingContext(contextType)) {
-            continue;
-        }
-        skiatest::ReporterContext ctx(
-                reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType)));
-        if (ctxInfo.grContext()) {
-            sk_gpu_test::ContextInfo child1 = factory->getSharedContextInfo(ctxInfo.grContext(), 0);
-            sk_gpu_test::ContextInfo child2 = factory->getSharedContextInfo(ctxInfo.grContext(), 1);
-            if (!child1.grContext() || !child2.grContext()) {
-                continue;
-            }
+            skiatest::ReporterContext ctx(
+                   reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType)));
+            if (ctxInfo.grContext()) {
+                sk_gpu_test::ContextInfo child1 = factory->getSharedContextInfo(ctxInfo.grContext(),
+                                                                                0);
+                sk_gpu_test::ContextInfo child2 = factory->getSharedContextInfo(ctxInfo.grContext(),
+                                                                                1);
+                if (!child1.grContext() || !child2.grContext()) {
+                    continue;
+                }
 
-            surface_semaphore_test(reporter, ctxInfo, child1, child2);
+                surface_semaphore_test(reporter, ctxInfo, child1, child2, flushContext);
+            }
         }
     }
 }
@@ -217,7 +226,8 @@
     mainSurface->flush();
 
     GrBackendSemaphore semaphore;
-    REPORTER_ASSERT(reporter, mainSurface->flushAndSignalSemaphores(1, &semaphore));
+    GrSemaphoresSubmitted submitted = mainSurface->flushAndSignalSemaphores(1, &semaphore);
+    REPORTER_ASSERT(reporter, GrSemaphoresSubmitted::kYes == submitted);
 
     if (kOpenGL_GrBackend == ctxInfo.backend()) {
         GrGLGpu* gpu = static_cast<GrGLGpu*>(ctx->getGpu());