diff --git a/src/gpu/GrBackendTextureImageGenerator.cpp b/src/gpu/GrBackendTextureImageGenerator.cpp index 186ca52446..420020b0b6 100644 --- a/src/gpu/GrBackendTextureImageGenerator.cpp +++ b/src/gpu/GrBackendTextureImageGenerator.cpp @@ -114,7 +114,8 @@ sk_sp GrBackendTextureImageGenerator::onGenerateTexture( } else { // Wait on a semaphore when a new context has just started borrowing the texture. This // is conservative, but shouldn't be too expensive. - if (fSemaphore && fLastBorrowingContextID != context->uniqueID()) { + if (fSemaphore && !fSemaphore->hasSubmittedWait() && + fLastBorrowingContextID != context->uniqueID()) { context->getGpu()->waitSemaphore(fSemaphore); fLastBorrowingContextID = context->uniqueID(); } diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index 5b338cdfa0..3a095517b5 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -488,7 +488,8 @@ GrSemaphoresSubmitted GrGpu::finishFlush(int numSemaphores, sk_sp semaphore; if (backendSemaphores[i].isInitialized()) { semaphore = fContext->resourceProvider()->wrapBackendSemaphore( - backendSemaphores[i], kBorrow_GrWrapOwnership); + backendSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillSignal, + kBorrow_GrWrapOwnership); } else { semaphore = fContext->resourceProvider()->makeSemaphore(false); } @@ -513,3 +514,49 @@ void GrGpu::dumpJSON(SkJSONWriter* writer) const { writer->endObject(); } + +void GrGpu::insertSemaphore(sk_sp semaphore, bool flush) { + if (!semaphore) { + return; + } + + SkASSERT(!semaphore->fSignaled); + if (semaphore->fSignaled) { + this->onInsertSemaphore(nullptr, flush); + return; + } + this->onInsertSemaphore(semaphore, flush); + semaphore->fSignaled = true; +} + +void GrGpu::waitSemaphore(sk_sp semaphore) { + if (!semaphore) { + return; + } + + SkASSERT(!semaphore->fWaitedOn); + if (!semaphore->fWaitedOn) { + this->onWaitSemaphore(semaphore); + semaphore->fWaitedOn = true; + } +} + +sk_sp GrGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore, + GrResourceProvider::SemaphoreWrapType wrapType, + GrWrapOwnership ownership) { + sk_sp grSema = this->onWrapBackendSemaphore(semaphore, ownership); + if (GrResourceProvider::SemaphoreWrapType::kWillSignal == wrapType) { + // This is a safety check to make sure we never try to wait on this semaphore since we + // assume the client will wait on it themselves if they've asked us to signal it. + grSema->fWaitedOn = true; + } else { + SkASSERT(GrResourceProvider::SemaphoreWrapType::kWillWait == wrapType); + // This is a safety check to make sure we never try to signal this semaphore since we assume + // the client will signal it themselves if they've asked us wait on it. + grSema->fSignaled = true; + } + + SkASSERT(this->caps()->fenceSyncSupport()); + return grSema; +} + diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 3f3610898a..e8e0ab9141 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -377,10 +377,11 @@ public: virtual void deleteFence(GrFence) const = 0; virtual sk_sp SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned = true) = 0; - virtual sk_sp wrapBackendSemaphore(const GrBackendSemaphore& semaphore, - GrWrapOwnership ownership) = 0; - virtual void insertSemaphore(sk_sp semaphore, bool flush = false) = 0; - virtual void waitSemaphore(sk_sp semaphore) = 0; + sk_sp wrapBackendSemaphore(const GrBackendSemaphore& semaphore, + GrResourceProvider::SemaphoreWrapType wrapType, + GrWrapOwnership ownership); + void insertSemaphore(sk_sp semaphore, bool flush = false); + void waitSemaphore(sk_sp semaphore); /** * Put this texture in a safe and known state for use across multiple GrContexts. Depending on @@ -605,6 +606,11 @@ private: virtual void onFinishFlush(bool insertedSemaphores) = 0; + virtual void onInsertSemaphore(sk_sp semaphore, bool flush = false) = 0; + virtual void onWaitSemaphore(sk_sp semaphore) = 0; + virtual sk_sp onWrapBackendSemaphore(const GrBackendSemaphore& semaphore, + GrWrapOwnership ownership) = 0; + virtual void onDumpJSON(SkJSONWriter*) const {} void resetContext() { diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index c2b25d8c33..c985e964e8 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -1428,7 +1428,8 @@ bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores, SkTArray> semaphores(numSemaphores); for (int i = 0; i < numSemaphores; ++i) { sk_sp sema = fContext->resourceProvider()->wrapBackendSemaphore( - waitSemaphores[i], kAdopt_GrWrapOwnership); + waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait, + kAdopt_GrWrapOwnership); std::unique_ptr waitOp(GrSemaphoreOp::MakeWait(sema, fRenderTargetProxy.get())); this->getRTOpList()->addOp(std::move(waitOp), *this->caps()); } diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp index 0112b5c15c..048b87fc4e 100644 --- a/src/gpu/GrResourceProvider.cpp +++ b/src/gpu/GrResourceProvider.cpp @@ -472,9 +472,12 @@ sk_sp SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool } sk_sp GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore, + SemaphoreWrapType wrapType, GrWrapOwnership ownership) { ASSERT_SINGLE_OWNER - return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore, ownership); + return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore, + wrapType, + ownership); } void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp semaphore) { diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h index 08da9ae0b0..bf7f28e93d 100644 --- a/src/gpu/GrResourceProvider.h +++ b/src/gpu/GrResourceProvider.h @@ -228,7 +228,13 @@ public: sk_sp SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned = true); + enum class SemaphoreWrapType { + kWillSignal, + kWillWait, + }; + sk_sp wrapBackendSemaphore(const GrBackendSemaphore&, + SemaphoreWrapType wrapType, GrWrapOwnership = kBorrow_GrWrapOwnership); // Takes the GrSemaphore and sets the ownership of the semaphore to the GrGpu object used by diff --git a/src/gpu/GrSemaphore.h b/src/gpu/GrSemaphore.h index fbc5a6df56..20556d27ac 100644 --- a/src/gpu/GrSemaphore.h +++ b/src/gpu/GrSemaphore.h @@ -13,7 +13,15 @@ class GrBackendSemaphore; class GrGpu; +/* + * Wrapper around a semaphore object which must be implemented on each backend. This semaphores can + * at most be signaled once and waited upon once. + */ class GrSemaphore : public SkRefCnt { +public: + bool hasSubmittedSignal() const { return fSignaled; } + bool hasSubmittedWait() const { return fWaitedOn; } + private: // This function should only be used in the case of exporting and importing a GrSemaphore object // from one GrContext to another. When exporting, the GrSemaphore should be set to a null GrGpu, @@ -26,6 +34,9 @@ private: // internal semaphore. virtual void setBackendSemaphore(GrBackendSemaphore*) const = 0; + bool fSignaled = false; + bool fWaitedOn = false; + protected: explicit GrSemaphore(const GrGpu* gpu) : fGpu(gpu) {} diff --git a/src/gpu/ddl/GrDDLGpu.h b/src/gpu/ddl/GrDDLGpu.h index aa708bd02b..e97a2abf4a 100644 --- a/src/gpu/ddl/GrDDLGpu.h +++ b/src/gpu/ddl/GrDDLGpu.h @@ -72,17 +72,6 @@ public: SkASSERT(0); return nullptr; } - sk_sp wrapBackendSemaphore(const GrBackendSemaphore& semaphore, - GrWrapOwnership ownership) override { - SkASSERT(0); - return nullptr; - } - void insertSemaphore(sk_sp semaphore, bool flush) override { - SkASSERT(0); - } - void waitSemaphore(sk_sp semaphore) override { - SkASSERT(0); - } sk_sp prepareTextureForCrossContextUsage(GrTexture*) override { SkASSERT(0); return nullptr; @@ -158,6 +147,18 @@ private: void onFinishFlush(bool insertedSemaphores) override { SkASSERT(0); } + sk_sp onWrapBackendSemaphore(const GrBackendSemaphore& semaphore, + GrWrapOwnership ownership) override { + SkASSERT(0); + return nullptr; + } + void onInsertSemaphore(sk_sp semaphore, bool flush) override { + SkASSERT(0); + } + void onWaitSemaphore(sk_sp semaphore) override { + SkASSERT(0); + } + GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*, int width, int height) override; diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 7b66bcc8a1..fb82a54448 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -4569,26 +4569,29 @@ sk_sp SK_WARN_UNUSED_RESULT GrGLGpu::makeSemaphore(bool isOwned) { return GrGLSemaphore::Make(this, isOwned); } -sk_sp GrGLGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore, - GrWrapOwnership ownership) { +sk_sp GrGLGpu::onWrapBackendSemaphore(const GrBackendSemaphore& semaphore, + GrWrapOwnership ownership) { SkASSERT(this->caps()->fenceSyncSupport()); return GrGLSemaphore::MakeWrapped(this, semaphore.glSync(), ownership); } -void GrGLGpu::insertSemaphore(sk_sp semaphore, bool flush) { +void GrGLGpu::onInsertSemaphore(sk_sp semaphore, bool flush) { GrGLSemaphore* glSem = static_cast(semaphore.get()); - GrGLsync sync; - GL_CALL_RET(sync, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); - glSem->setSync(sync); + if (glSem) { + GrGLsync sync; + GL_CALL_RET(sync, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); + glSem->setSync(sync); + } if (flush) { GL_CALL(Flush()); } } -void GrGLGpu::waitSemaphore(sk_sp semaphore) { +void GrGLGpu::onWaitSemaphore(sk_sp semaphore) { GrGLSemaphore* glSem = static_cast(semaphore.get()); + SkASSERT(glSem); GL_CALL(WaitSync(glSem->sync(), 0, GR_GL_TIMEOUT_IGNORED)); } diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 4559d38e4a..2087356f04 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -173,10 +173,6 @@ public: void deleteFence(GrFence) const override; sk_sp SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override; - sk_sp wrapBackendSemaphore(const GrBackendSemaphore& semaphore, - GrWrapOwnership ownership) override; - void insertSemaphore(sk_sp semaphore, bool flush) override; - void waitSemaphore(sk_sp semaphore) override; sk_sp prepareTextureForCrossContextUsage(GrTexture*) override; @@ -290,6 +286,11 @@ private: void onFinishFlush(bool insertedSemaphores) override; + void onInsertSemaphore(sk_sp semaphore, bool flush) override; + void onWaitSemaphore(sk_sp semaphore) override; + sk_sp onWrapBackendSemaphore(const GrBackendSemaphore& semaphore, + GrWrapOwnership ownership) override; + bool hasExtension(const char* ext) const { return fGLContext->hasExtension(ext); } bool copySurfaceAsDraw(GrSurface* dst, GrSurfaceOrigin dstOrigin, diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h index 4567505546..359782f0c9 100644 --- a/src/gpu/mock/GrMockGpu.h +++ b/src/gpu/mock/GrMockGpu.h @@ -58,10 +58,6 @@ public: sk_sp SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override { return nullptr; } - sk_sp wrapBackendSemaphore(const GrBackendSemaphore& semaphore, - GrWrapOwnership ownership) override { return nullptr; } - void insertSemaphore(sk_sp semaphore, bool flush) override {} - void waitSemaphore(sk_sp semaphore) override {} sk_sp prepareTextureForCrossContextUsage(GrTexture*) override { return nullptr; } void submitCommandBuffer(const GrMockGpuRTCommandBuffer*); @@ -124,6 +120,11 @@ private: void onFinishFlush(bool insertedSemaphores) override {} + sk_sp onWrapBackendSemaphore(const GrBackendSemaphore& semaphore, + GrWrapOwnership ownership) override { return nullptr; } + void onInsertSemaphore(sk_sp semaphore, bool flush) override {} + void onWaitSemaphore(sk_sp semaphore) 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 9c5ba8299a..61cbc62f71 100644 --- a/src/gpu/mtl/GrMtlGpu.h +++ b/src/gpu/mtl/GrMtlGpu.h @@ -67,10 +67,6 @@ public: sk_sp SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override { return nullptr; } - sk_sp wrapBackendSemaphore(const GrBackendSemaphore& semaphore, - GrWrapOwnership ownership) override { return nullptr; } - void insertSemaphore(sk_sp semaphore, bool flush) override {} - void waitSemaphore(sk_sp semaphore) override {} sk_sp prepareTextureForCrossContextUsage(GrTexture*) override { return nullptr; } private: @@ -133,6 +129,11 @@ private: void onFinishFlush(bool insertedSemaphores) override {} + sk_sp onWrapBackendSemaphore(const GrBackendSemaphore& semaphore, + GrWrapOwnership ownership) override { return nullptr; } + void onInsertSemaphore(sk_sp semaphore, bool flush) override {} + void onWaitSemaphore(sk_sp semaphore) override {} + GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*, int width, int height) override { diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index baf022185f..e1be99e872 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -2162,25 +2162,28 @@ sk_sp SK_WARN_UNUSED_RESULT GrVkGpu::makeSemaphore(bool isOwned) { return GrVkSemaphore::Make(this, isOwned); } -sk_sp GrVkGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore, - GrWrapOwnership ownership) { +sk_sp GrVkGpu::onWrapBackendSemaphore(const GrBackendSemaphore& semaphore, + GrWrapOwnership ownership) { return GrVkSemaphore::MakeWrapped(this, semaphore.vkSemaphore(), ownership); } -void GrVkGpu::insertSemaphore(sk_sp semaphore, bool flush) { +void GrVkGpu::onInsertSemaphore(sk_sp semaphore, bool flush) { GrVkSemaphore* vkSem = static_cast(semaphore.get()); - const GrVkSemaphore::Resource* resource = vkSem->getResource(); - resource->ref(); - fSemaphoresToSignal.push_back(resource); + if (vkSem) { + const GrVkSemaphore::Resource* resource = vkSem->getResource(); + resource->ref(); + fSemaphoresToSignal.push_back(resource); + } if (flush) { this->submitCommandBuffer(kSkip_SyncQueue); } } -void GrVkGpu::waitSemaphore(sk_sp semaphore) { +void GrVkGpu::onWaitSemaphore(sk_sp semaphore) { GrVkSemaphore* vkSem = static_cast(semaphore.get()); + SkASSERT(vkSem); const GrVkSemaphore::Resource* resource = vkSem->getResource(); resource->ref(); diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h index 95d96b1196..e3055945bc 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -135,11 +135,6 @@ public: void deleteFence(GrFence) const override; sk_sp SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override; - sk_sp wrapBackendSemaphore(const GrBackendSemaphore& semaphore, - GrWrapOwnership ownership) override; - void insertSemaphore(sk_sp semaphore, bool flush) override; - void waitSemaphore(sk_sp semaphore) override; - sk_sp prepareTextureForCrossContextUsage(GrTexture*) override; void generateMipmap(GrVkTexture* tex, GrSurfaceOrigin texOrigin); @@ -209,6 +204,11 @@ private: void onFinishFlush(bool insertedSemaphores) override; + void onInsertSemaphore(sk_sp semaphore, bool flush) override; + void onWaitSemaphore(sk_sp semaphore) override; + sk_sp onWrapBackendSemaphore(const GrBackendSemaphore& semaphore, + GrWrapOwnership ownership) 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