Update GrSemaphore to allow it to only be used once for signaling and once for waiting.

This is required for Vulkan which doesn't allow a semaphore to be waited on by
multiple things at once or signaled from multiple places.

Bug: skia:
Change-Id: Iac0cb782a6662167c2cab1fd6a2c80378834a480
Reviewed-on: https://skia-review.googlesource.com/92601
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
Greg Daniel 2018-01-09 13:55:33 -05:00 committed by Skia Commit-Bot
parent e48eb337e1
commit 17b7c05433
14 changed files with 135 additions and 50 deletions

View File

@ -114,7 +114,8 @@ sk_sp<GrTextureProxy> 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();
}

View File

@ -488,7 +488,8 @@ GrSemaphoresSubmitted GrGpu::finishFlush(int numSemaphores,
sk_sp<GrSemaphore> 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<GrSemaphore> 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<GrSemaphore> semaphore) {
if (!semaphore) {
return;
}
SkASSERT(!semaphore->fWaitedOn);
if (!semaphore->fWaitedOn) {
this->onWaitSemaphore(semaphore);
semaphore->fWaitedOn = true;
}
}
sk_sp<GrSemaphore> GrGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrResourceProvider::SemaphoreWrapType wrapType,
GrWrapOwnership ownership) {
sk_sp<GrSemaphore> 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;
}

View File

@ -377,10 +377,11 @@ public:
virtual void deleteFence(GrFence) const = 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;
sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrResourceProvider::SemaphoreWrapType wrapType,
GrWrapOwnership ownership);
void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush = false);
void waitSemaphore(sk_sp<GrSemaphore> 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<GrSemaphore> semaphore, bool flush = false) = 0;
virtual void onWaitSemaphore(sk_sp<GrSemaphore> semaphore) = 0;
virtual sk_sp<GrSemaphore> onWrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) = 0;
virtual void onDumpJSON(SkJSONWriter*) const {}
void resetContext() {

View File

@ -1428,7 +1428,8 @@ bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
SkTArray<sk_sp<GrSemaphore>> semaphores(numSemaphores);
for (int i = 0; i < numSemaphores; ++i) {
sk_sp<GrSemaphore> sema = fContext->resourceProvider()->wrapBackendSemaphore(
waitSemaphores[i], kAdopt_GrWrapOwnership);
waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
kAdopt_GrWrapOwnership);
std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(sema, fRenderTargetProxy.get()));
this->getRTOpList()->addOp(std::move(waitOp), *this->caps());
}

View File

@ -472,9 +472,12 @@ sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool
}
sk_sp<GrSemaphore> 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<GrSemaphore> semaphore) {

View File

@ -228,7 +228,13 @@ public:
sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned = true);
enum class SemaphoreWrapType {
kWillSignal,
kWillWait,
};
sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore&,
SemaphoreWrapType wrapType,
GrWrapOwnership = kBorrow_GrWrapOwnership);
// Takes the GrSemaphore and sets the ownership of the semaphore to the GrGpu object used by

View File

@ -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) {}

View File

@ -72,17 +72,6 @@ public:
SkASSERT(0);
return nullptr;
}
sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) override {
SkASSERT(0);
return nullptr;
}
void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override {
SkASSERT(0);
}
void waitSemaphore(sk_sp<GrSemaphore> semaphore) override {
SkASSERT(0);
}
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override {
SkASSERT(0);
return nullptr;
@ -158,6 +147,18 @@ private:
void onFinishFlush(bool insertedSemaphores) override { SkASSERT(0); }
sk_sp<GrSemaphore> onWrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) override {
SkASSERT(0);
return nullptr;
}
void onInsertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override {
SkASSERT(0);
}
void onWaitSemaphore(sk_sp<GrSemaphore> semaphore) override {
SkASSERT(0);
}
GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
int width,
int height) override;

View File

@ -4569,26 +4569,29 @@ 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) {
sk_sp<GrSemaphore> GrGLGpu::onWrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) {
SkASSERT(this->caps()->fenceSyncSupport());
return GrGLSemaphore::MakeWrapped(this, semaphore.glSync(), ownership);
}
void GrGLGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) {
void GrGLGpu::onInsertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) {
GrGLSemaphore* glSem = static_cast<GrGLSemaphore*>(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<GrSemaphore> semaphore) {
void GrGLGpu::onWaitSemaphore(sk_sp<GrSemaphore> semaphore) {
GrGLSemaphore* glSem = static_cast<GrGLSemaphore*>(semaphore.get());
SkASSERT(glSem);
GL_CALL(WaitSync(glSem->sync(), 0, GR_GL_TIMEOUT_IGNORED));
}

View File

@ -173,10 +173,6 @@ public:
void deleteFence(GrFence) const 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;
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override;
@ -290,6 +286,11 @@ private:
void onFinishFlush(bool insertedSemaphores) override;
void onInsertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override;
void onWaitSemaphore(sk_sp<GrSemaphore> semaphore) override;
sk_sp<GrSemaphore> onWrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) override;
bool hasExtension(const char* ext) const { return fGLContext->hasExtension(ext); }
bool copySurfaceAsDraw(GrSurface* dst, GrSurfaceOrigin dstOrigin,

View File

@ -58,10 +58,6 @@ public:
sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override {
return nullptr;
}
sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) override { return nullptr; }
void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override {}
void waitSemaphore(sk_sp<GrSemaphore> semaphore) override {}
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override { return nullptr; }
void submitCommandBuffer(const GrMockGpuRTCommandBuffer*);
@ -124,6 +120,11 @@ private:
void onFinishFlush(bool insertedSemaphores) override {}
sk_sp<GrSemaphore> onWrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) override { return nullptr; }
void onInsertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override {}
void onWaitSemaphore(sk_sp<GrSemaphore> semaphore) override {}
GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
int width,
int height) override;

View File

@ -67,10 +67,6 @@ public:
sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override {
return nullptr;
}
sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) override { return nullptr; }
void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override {}
void waitSemaphore(sk_sp<GrSemaphore> semaphore) override {}
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override { return nullptr; }
private:
@ -133,6 +129,11 @@ private:
void onFinishFlush(bool insertedSemaphores) override {}
sk_sp<GrSemaphore> onWrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) override { return nullptr; }
void onInsertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override {}
void onWaitSemaphore(sk_sp<GrSemaphore> semaphore) override {}
GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
int width,
int height) override {

View File

@ -2162,25 +2162,28 @@ sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrVkGpu::makeSemaphore(bool isOwned) {
return GrVkSemaphore::Make(this, isOwned);
}
sk_sp<GrSemaphore> GrVkGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) {
sk_sp<GrSemaphore> GrVkGpu::onWrapBackendSemaphore(const GrBackendSemaphore& semaphore,
GrWrapOwnership ownership) {
return GrVkSemaphore::MakeWrapped(this, semaphore.vkSemaphore(), ownership);
}
void GrVkGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) {
void GrVkGpu::onInsertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) {
GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(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<GrSemaphore> semaphore) {
void GrVkGpu::onWaitSemaphore(sk_sp<GrSemaphore> semaphore) {
GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore.get());
SkASSERT(vkSem);
const GrVkSemaphore::Resource* resource = vkSem->getResource();
resource->ref();

View File

@ -135,11 +135,6 @@ public:
void deleteFence(GrFence) const 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;
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override;
void generateMipmap(GrVkTexture* tex, GrSurfaceOrigin texOrigin);
@ -209,6 +204,11 @@ private:
void onFinishFlush(bool insertedSemaphores) override;
void onInsertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override;
void onWaitSemaphore(sk_sp<GrSemaphore> semaphore) override;
sk_sp<GrSemaphore> 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