Reland "Refactor GL and Metal FinishCallback into a helper object."

This is a reland of b641ddbba0

Original change's description:
> Refactor GL and Metal FinishCallback into a helper object.
> 
> Change-Id: I52ede0363016459976e453ef71cafbcc6775f22e
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/283496
> Commit-Queue: Stephen White <senorblanco@chromium.org>
> Reviewed-by: Greg Daniel <egdaniel@google.com>

Change-Id: Ia77c05c0358b6ccab1e8c0f0c06212786f415cb1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/284042
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Stephen White 2020-04-16 14:14:13 -04:00 committed by Skia Commit-Bot
parent 0b406736c1
commit b353c9bdd3
14 changed files with 150 additions and 93 deletions

View File

@ -89,6 +89,8 @@ skia_gpu_sources = [
"$_src/gpu/GrDynamicAtlas.cpp",
"$_src/gpu/GrDynamicAtlas.h",
"$_src/gpu/GrEagerVertexAllocator.h",
"$_src/gpu/GrFinishCallbacks.cpp",
"$_src/gpu/GrFinishCallbacks.h",
"$_src/gpu/GrFixedClip.cpp",
"$_src/gpu/GrFixedClip.h",
"$_src/gpu/GrFragmentProcessor.cpp",

View File

@ -0,0 +1,44 @@
/*
* Copyright 2020 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/GrFinishCallbacks.h"
#include "src/gpu/GrGpu.h"
GrFinishCallbacks::GrFinishCallbacks(GrGpu* gpu) : fGpu(gpu) {}
GrFinishCallbacks::~GrFinishCallbacks() {
this->callAll(true);
}
void GrFinishCallbacks::add(GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext) {
SkASSERT(finishedProc);
FinishCallback callback;
callback.fCallback = finishedProc;
callback.fContext = finishedContext;
callback.fFence = fGpu->insertFence();
fCallbacks.push_back(callback);
}
void GrFinishCallbacks::check() {
// Bail after the first unfinished sync since we expect they signal in the order inserted.
while (!fCallbacks.empty() && fGpu->waitFence(fCallbacks.front().fFence)) {
fCallbacks.front().fCallback(fCallbacks.front().fContext);
fGpu->deleteFence(fCallbacks.front().fFence);
fCallbacks.pop_front();
}
}
void GrFinishCallbacks::callAll(bool doDelete) {
while (!fCallbacks.empty()) {
fCallbacks.front().fCallback(fCallbacks.front().fContext);
if (doDelete) {
fGpu->deleteFence(fCallbacks.front().fFence);
}
fCallbacks.pop_front();
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 2020 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrFinishCallbacks_DEFINED
#define GrFinishCallbacks_DEFINED
#include "include/gpu/GrTypes.h"
#include "include/private/GrTypesPriv.h"
#include <list>
class GrGpu;
/**
* Maintains a list of callbacks to be called when work on the GPU is complete.
*/
class GrFinishCallbacks {
public:
GrFinishCallbacks(GrGpu* gpu);
~GrFinishCallbacks();
/**
* Call all the callbacks in the list. This will block until all work is done.
*
* @param doDelete delete the contained fence object.
*/
void callAll(bool doDelete);
/**
* Add a new callback to the list.
*
* @param finishedProc The function to call when GPU work is complete.
* @param finishedContext The context object to pass back to the callback.
*/
void add(GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext);
/**
* Check if any GPU work is complete, and call the associated callbacks.
* This call is non-blocking.
*/
void check();
/**
* Returns true if the callback list is empty.
*/
bool empty() const { return fCallbacks.empty(); }
private:
struct FinishCallback {
GrGpuFinishedProc fCallback;
GrGpuFinishedContext fContext;
GrFence fFence;
};
GrGpu* fGpu;
std::list<FinishCallback> fCallbacks;
};
#endif

View File

@ -369,7 +369,7 @@ public:
virtual void submit(GrOpsRenderPass*) = 0;
virtual GrFence SK_WARN_UNUSED_RESULT insertFence() = 0;
virtual bool waitFence(GrFence, uint64_t timeout = 1000) = 0;
virtual bool waitFence(GrFence) = 0;
virtual void deleteFence(GrFence) const = 0;
virtual std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(

View File

@ -62,7 +62,7 @@ public:
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override { return 0; }
bool waitFence(GrFence, uint64_t) override { return true; }
bool waitFence(GrFence) override { return true; }
void deleteFence(GrFence) const override {}
std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override {

View File

@ -558,7 +558,7 @@ GrFence SK_WARN_UNUSED_RESULT GrDawnGpu::insertFence() {
return GrFence();
}
bool GrDawnGpu::waitFence(GrFence fence, uint64_t timeout) {
bool GrDawnGpu::waitFence(GrFence fence) {
SkASSERT(!"unimplemented");
return false;
}

View File

@ -85,7 +85,7 @@ public:
void submit(GrOpsRenderPass*) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override;
bool waitFence(GrFence, uint64_t timeout) override;
bool waitFence(GrFence) override;
void deleteFence(GrFence) const override;
std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned = true) override;

View File

@ -330,7 +330,8 @@ GrGLGpu::GrGLGpu(std::unique_ptr<GrGLContext> ctx, GrContext* context)
, fHWProgramID(0)
, fTempSrcFBOID(0)
, fTempDstFBOID(0)
, fStencilClearFBOID(0) {
, fStencilClearFBOID(0)
, fFinishCallbacks(this) {
SkASSERT(fGLContext);
GrGLClearErr(this->glInterface());
fCaps = sk_ref_sp(fGLContext->caps());
@ -401,11 +402,7 @@ GrGLGpu::~GrGLGpu() {
fSamplerObjectCache.reset();
while (!fFinishCallbacks.empty()) {
fFinishCallbacks.front().fCallback(fFinishCallbacks.front().fContext);
this->deleteSync(fFinishCallbacks.front().fSync);
fFinishCallbacks.pop_front();
}
fFinishCallbacks.callAll(true);
}
void GrGLGpu::disconnect(DisconnectType type) {
@ -465,14 +462,7 @@ void GrGLGpu::disconnect(DisconnectType type) {
if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
this->glPathRendering()->disconnect(type);
}
while (!fFinishCallbacks.empty()) {
fFinishCallbacks.front().fCallback(fFinishCallbacks.front().fContext);
if (DisconnectType::kCleanup == type) {
this->deleteSync(fFinishCallbacks.front().fSync);
}
fFinishCallbacks.pop_front();
}
fFinishCallbacks.callAll(DisconnectType::kCleanup == type);
}
///////////////////////////////////////////////////////////////////////////////
@ -3786,16 +3776,7 @@ GrGLAttribArrayState* GrGLGpu::HWVertexArrayState::bindInternalVertexArray(GrGLG
void GrGLGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext) {
SkASSERT(finishedProc);
FinishCallback callback;
callback.fCallback = finishedProc;
callback.fContext = finishedContext;
if (this->caps()->fenceSyncSupport()) {
callback.fSync = (GrGLsync)this->insertFence();
} else {
callback.fSync = 0;
}
fFinishCallbacks.push_back(callback);
fFinishCallbacks.add(finishedProc, finishedContext);
}
void GrGLGpu::flush(FlushType flushType) {
@ -3808,20 +3789,11 @@ void GrGLGpu::flush(FlushType flushType) {
bool GrGLGpu::onSubmitToGpu(bool syncCpu) {
if (syncCpu || (!fFinishCallbacks.empty() && !this->caps()->fenceSyncSupport())) {
GL_CALL(Finish());
// After a finish everything previously sent to GL is done.
for (const auto& cb : fFinishCallbacks) {
cb.fCallback(cb.fContext);
if (cb.fSync) {
this->deleteSync(cb.fSync);
} else {
SkASSERT(!this->caps()->fenceSyncSupport());
}
}
fFinishCallbacks.clear();
fFinishCallbacks.callAll(true);
} else {
this->flush();
// See if any previously inserted finish procs are good to go.
this->checkFinishProcs();
fFinishCallbacks.check();
}
return true;
}
@ -3833,7 +3805,9 @@ void GrGLGpu::submit(GrOpsRenderPass* renderPass) {
}
GrFence SK_WARN_UNUSED_RESULT GrGLGpu::insertFence() {
SkASSERT(this->caps()->fenceSyncSupport());
if (!this->caps()->fenceSyncSupport()) {
return 0;
}
GrGLsync sync;
if (this->glCaps().fenceType() == GrGLCaps::FenceType::kNVFence) {
static_assert(sizeof(GrGLsync) >= sizeof(GrGLuint));
@ -3873,12 +3847,17 @@ bool GrGLGpu::waitSync(GrGLsync sync, uint64_t timeout, bool flush) {
}
}
bool GrGLGpu::waitFence(GrFence fence, uint64_t timeout) {
return this->waitSync((GrGLsync)fence, timeout, /* flush = */ true);
bool GrGLGpu::waitFence(GrFence fence) {
if (!this->caps()->fenceSyncSupport()) {
return true;
}
return this->waitSync(reinterpret_cast<GrGLsync>(fence), 0, false);
}
void GrGLGpu::deleteFence(GrFence fence) const {
this->deleteSync((GrGLsync)fence);
if (this->caps()->fenceSyncSupport()) {
this->deleteSync(reinterpret_cast<GrGLsync>(fence));
}
}
std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrGLGpu::makeSemaphore(bool isOwned) {
@ -3910,13 +3889,7 @@ void GrGLGpu::waitSemaphore(GrSemaphore* semaphore) {
}
void GrGLGpu::checkFinishProcs() {
// Bail after the first unfinished sync since we expect they signal in the order inserted.
while (!fFinishCallbacks.empty() && this->waitSync(fFinishCallbacks.front().fSync,
/* timeout = */ 0, /* flush = */ false)) {
fFinishCallbacks.front().fCallback(fFinishCallbacks.front().fContext);
this->deleteSync(fFinishCallbacks.front().fSync);
fFinishCallbacks.pop_front();
}
fFinishCallbacks.check();
}
void GrGLGpu::deleteSync(GrGLsync sync) const {

View File

@ -8,10 +8,10 @@
#ifndef GrGLGpu_DEFINED
#define GrGLGpu_DEFINED
#include <list>
#include "include/core/SkTypes.h"
#include "include/private/SkTArray.h"
#include "src/core/SkLRUCache.h"
#include "src/gpu/GrFinishCallbacks.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrNativeRect.h"
#include "src/gpu/GrProgramDesc.h"
@ -163,7 +163,7 @@ public:
void submit(GrOpsRenderPass* renderPass) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override;
bool waitFence(GrFence, uint64_t timeout) override;
bool waitFence(GrFence) override;
void deleteFence(GrFence) const override;
std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override;
@ -707,13 +707,7 @@ private:
std::unique_ptr<SamplerObjectCache> fSamplerObjectCache;
std::unique_ptr<GrGLOpsRenderPass> fCachedOpsRenderPass;
struct FinishCallback {
GrGpuFinishedProc fCallback;
GrGpuFinishedContext fContext;
GrGLsync fSync;
};
std::list<FinishCallback> fFinishCallbacks;
GrFinishCallbacks fFinishCallbacks;
// If we've called a command that requires us to call glFlush than this will be set to true
// since we defer calling flush until submit time. When we call submitToGpu if this is true then

View File

@ -31,7 +31,7 @@ public:
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override { return 0; }
bool waitFence(GrFence, uint64_t) override { return true; }
bool waitFence(GrFence) override { return true; }
void deleteFence(GrFence) const override {}
std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override {

View File

@ -8,7 +8,7 @@
#ifndef GrMtlGpu_DEFINED
#define GrMtlGpu_DEFINED
#include <list>
#include "src/gpu/GrFinishCallbacks.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrRenderTarget.h"
#include "src/gpu/GrSemaphore.h"
@ -89,7 +89,7 @@ public:
void submit(GrOpsRenderPass* renderPass) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override;
bool waitFence(GrFence, uint64_t) override;
bool waitFence(GrFence) override;
void deleteFence(GrFence) const override;
std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override;
@ -246,12 +246,7 @@ private:
bool fDisconnected;
struct FinishCallback {
GrGpuFinishedProc fCallback;
GrGpuFinishedContext fContext;
GrFence fFence;
};
std::list<FinishCallback> fFinishCallbacks;
GrFinishCallbacks fFinishCallbacks;
typedef GrGpu INHERITED;
};

View File

@ -119,7 +119,8 @@ GrMtlGpu::GrMtlGpu(GrContext* context, const GrContextOptions& options,
, fCmdBuffer(nullptr)
, fCompiler(new SkSL::Compiler())
, fResourceProvider(this)
, fDisconnected(false) {
, fDisconnected(false)
, fFinishCallbacks(this) {
fMtlCaps.reset(new GrMtlCaps(options, fDevice, featureSet));
fCaps = fMtlCaps;
}
@ -189,23 +190,13 @@ void GrMtlGpu::submitCommandBuffer(SyncQueue sync) {
void GrMtlGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext) {
SkASSERT(finishedProc);
SkASSERT(this->caps()->fenceSyncSupport());
FinishCallback callback;
callback.fCallback = finishedProc;
callback.fContext = finishedContext;
callback.fFence = this->insertFence();
fFinishCallbacks.push_back(callback);
fFinishCallbacks.add(finishedProc, finishedContext);
}
bool GrMtlGpu::onSubmitToGpu(bool syncCpu) {
if (syncCpu) {
this->submitCommandBuffer(kForce_SyncQueue);
for (const auto& cb : fFinishCallbacks) {
cb.fCallback(cb.fContext);
this->deleteFence(cb.fFence);
}
fFinishCallbacks.clear();
fFinishCallbacks.callAll(true);
} else {
this->submitCommandBuffer(kSkip_SyncQueue);
}
@ -213,13 +204,7 @@ bool GrMtlGpu::onSubmitToGpu(bool syncCpu) {
}
void GrMtlGpu::checkFinishProcs() {
// Bail after the first unfinished sync since we expect they signal in the order inserted.
while (!fFinishCallbacks.empty() && this->waitFence(fFinishCallbacks.front().fFence,
/* timeout = */ 0)) {
fFinishCallbacks.front().fCallback(fFinishCallbacks.front().fContext);
this->deleteFence(fFinishCallbacks.front().fFence);
fFinishCallbacks.pop_front();
}
fFinishCallbacks.check();
}
std::unique_ptr<GrSemaphore> GrMtlGpu::prepareTextureForCrossContextUsage(GrTexture*) {
@ -1324,11 +1309,11 @@ GrFence SK_WARN_UNUSED_RESULT GrMtlGpu::insertFence() {
return (GrFence) cfFence;
}
bool GrMtlGpu::waitFence(GrFence fence, uint64_t timeout) {
bool GrMtlGpu::waitFence(GrFence fence) {
const void* cfFence = (const void*) fence;
dispatch_semaphore_t semaphore = (__bridge dispatch_semaphore_t)cfFence;
long result = dispatch_semaphore_wait(semaphore, timeout);
long result = dispatch_semaphore_wait(semaphore, 0);
return !result;
}

View File

@ -2655,11 +2655,11 @@ GrFence SK_WARN_UNUSED_RESULT GrVkGpu::insertFence() {
return (GrFence)fence;
}
bool GrVkGpu::waitFence(GrFence fence, uint64_t timeout) {
bool GrVkGpu::waitFence(GrFence fence) {
SkASSERT(VK_NULL_HANDLE != (VkFence)fence);
VkResult result;
VK_CALL_RET(result, WaitForFences(this->device(), 1, (VkFence*)&fence, VK_TRUE, timeout));
VK_CALL_RET(result, WaitForFences(this->device(), 1, (VkFence*)&fence, VK_TRUE, 0));
return (VK_SUCCESS == result);
}

View File

@ -124,7 +124,7 @@ public:
void submit(GrOpsRenderPass*) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override;
bool waitFence(GrFence, uint64_t timeout) override;
bool waitFence(GrFence) override;
void deleteFence(GrFence) const override;
std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override;