Add return to surface semaphore calls to indicate when we don't support them

Bug: skia:
Change-Id: I00118637bf6555278ca61707275ed60372de581d
Reviewed-on: https://skia-review.googlesource.com/20061
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 6fad217..08e558c 100644
--- a/include/core/SkSurface.h
+++ b/include/core/SkSurface.h
@@ -341,15 +341,22 @@
      * signalSemaphores with the info on the semaphores we submitted. The client is reposonsible for
      * allocating enough space in signalSemaphores to handle numSemaphores of GrBackendSemaphores.
      * The client will also take ownership of the returned underlying backend semaphores.
+     *
+     * 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, we will still flush
+     * any pending surface IO.
      */
-    void flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores);
+    bool flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores);
 
     /**
      * Inserts a list of GPU semaphores that the current backend 3D API must wait on before
      * executing any more commands on the GPU for this surface. Skia will take ownership of the
      * underlying semaphores and delete them once they have been signaled and waited on.
+     *
+     * If this call returns false, then the GPU backend will not wait on any passed in semaphores,
+     * and the client will still own the semaphores.
      */
-    void wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
+    bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
 
 protected:
     SkSurface(int width, int height, const SkSurfaceProps*);
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 2a04b1e..56aac99 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -1431,13 +1431,18 @@
     this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
 }
 
-void GrRenderTargetContext::prepareForExternalIO(int numSemaphores,
+bool GrRenderTargetContext::prepareForExternalIO(int numSemaphores,
                                                  GrBackendSemaphore* backendSemaphores) {
     ASSERT_SINGLE_OWNER
-    RETURN_IF_ABANDONED
+    RETURN_FALSE_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::prepareForExternalIO");
 
+    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) {
         semaphores.push_back(fContext->resourceProvider()->makeSemaphore(false));
@@ -1451,17 +1456,22 @@
     for (int i = 0; i < numSemaphores; ++i) {
         semaphores[i]->setBackendSemaphore(&backendSemaphores[i]);
     }
+    return true;
 }
 
-void GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
+bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
                                              const GrBackendSemaphore* waitSemaphores) {
     ASSERT_SINGLE_OWNER
-    RETURN_IF_ABANDONED
+    RETURN_FALSE_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::waitOnSemaphores");
 
     AutoCheckFlush acf(this->drawingManager());
 
+    if (numSemaphores && !this->caps()->fenceSyncSupport()) {
+        return false;
+    }
+
     SkTArray<sk_sp<GrSemaphore>> semaphores(numSemaphores);
     for (int i = 0; i < numSemaphores; ++i) {
         sk_sp<GrSemaphore> sema = fContext->resourceProvider()->wrapBackendSemaphore(
@@ -1469,6 +1479,7 @@
         std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(sema, fRenderTargetProxy.get()));
         this->getOpList()->addOp(std::move(waitOp), *this->caps());
     }
+    return true;
 }
 
 // Can 'path' be drawn as a pair of filled nested rectangles?
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index a2369dd..8cb4432 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -303,13 +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(int numSemaphores, GrBackendSemaphore* backendSemaphores);
+    bool 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);
+    bool waitOnSemaphores(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
 
     GrFSAAType fsaaType() const { return fRenderTargetProxy->fsaaType(); }
     const GrCaps* caps() const { return fContext->caps(); }
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index ee6e88d..301adc1 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1736,17 +1736,17 @@
     this->flushAndSignalSemaphores(0, nullptr);
 }
 
-void SkGpuDevice::flushAndSignalSemaphores(int numSemaphores,
+bool SkGpuDevice::flushAndSignalSemaphores(int numSemaphores,
                                            GrBackendSemaphore* signalSemaphores) {
     ASSERT_SINGLE_OWNER
 
-    fRenderTargetContext->prepareForExternalIO(numSemaphores, signalSemaphores);
+    return fRenderTargetContext->prepareForExternalIO(numSemaphores, signalSemaphores);
 }
 
-void SkGpuDevice::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
+bool SkGpuDevice::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
     ASSERT_SINGLE_OWNER
 
-    fRenderTargetContext->waitOnSemaphores(numSemaphores, waitSemaphores);
+    return fRenderTargetContext->waitOnSemaphores(numSemaphores, waitSemaphores);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index 317533d..b5133f4 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -118,8 +118,8 @@
     sk_sp<SkSpecialImage> snapSpecial() override;
 
     void flush() override;
-    void flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores);
-    void wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
+    bool 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 d401600..e5e8841 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -4273,6 +4273,7 @@
 }
 
 GrFence SK_WARN_UNUSED_RESULT GrGLGpu::insertFence() {
+    SkASSERT(this->caps()->fenceSyncSupport());
     GrGLsync sync;
     GL_CALL_RET(sync, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
     GR_STATIC_ASSERT(sizeof(GrFence) >= sizeof(GrGLsync));
@@ -4290,11 +4291,13 @@
 }
 
 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrGLGpu::makeSemaphore(bool isOwned) {
+    SkASSERT(this->caps()->fenceSyncSupport());
     return GrGLSemaphore::Make(this, isOwned);
 }
 
 sk_sp<GrSemaphore> GrGLGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
                                                  GrWrapOwnership ownership) {
+    SkASSERT(this->caps()->fenceSyncSupport());
     return GrGLSemaphore::MakeWrapped(this, semaphore.glSync(), ownership);
 }
 
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index fbd9f83..57d419c 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -191,12 +191,12 @@
     asSB(this)->onFlush(0, nullptr);
 }
 
-void SkSurface::flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
+bool 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);
+bool SkSurface::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
+    return asSB(this)->onWait(numSemaphores, waitSemaphores);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkSurface_Base.h b/src/image/SkSurface_Base.h
index 264a86f..93528b8 100644
--- a/src/image/SkSurface_Base.h
+++ b/src/image/SkSurface_Base.h
@@ -80,14 +80,18 @@
      * 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 onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {}
+    virtual bool onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
+        return false;
+    }
 
     /**
      * 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) {}
+    virtual bool onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
+        return false;
+    }
 
     inline SkCanvas* getCachedCanvas();
     inline sk_sp<SkImage> refCachedImage();
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 0f4b2cb..13c89d4 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -166,12 +166,12 @@
     fDevice->accessRenderTargetContext()->discard();
 }
 
-void SkSurface_Gpu::onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
-    fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
+bool SkSurface_Gpu::onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
+    return fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
 }
 
-void SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
-    fDevice->wait(numSemaphores, waitSemaphores);
+bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
+    return fDevice->wait(numSemaphores, waitSemaphores);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkSurface_Gpu.h b/src/image/SkSurface_Gpu.h
index e22ae10..2bc9210 100644
--- a/src/image/SkSurface_Gpu.h
+++ b/src/image/SkSurface_Gpu.h
@@ -26,8 +26,8 @@
     sk_sp<SkImage> onNewImageSnapshot() override;
     void onCopyOnWrite(ContentChangeMode) override;
     void onDiscard() override;
-    void onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) override;
-    void onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) override;
+    bool onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) override;
+    bool onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) override;
 
     SkGpuDevice* getDevice() { return fDevice.get(); }