blob: fa1ded0fb92b64dd90b500a153e624b900c75252 [file] [log] [blame] [edit]
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_RefCntedCallback_DEFINED
#define skgpu_RefCntedCallback_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/gpu/GpuTypes.h"
namespace skgpu {
/**
* Move-only type that calls a callback from its destructor.
*/
class AutoCallback {
public:
using Context = void*;
using Callback = void (*)(Context);
using CallbackWithStats = void (*)(Context, const GpuStats&);
using ResultCallback = void (*)(Context, CallbackResult);
using ResultCallbackWithStats = void (*)(Context, CallbackResult, const GpuStats&);
AutoCallback() = default;
AutoCallback(const AutoCallback&) = delete;
AutoCallback(AutoCallback&& that) { *this = std::move(that); }
AutoCallback(Callback proc, Context ctx) : fReleaseProc(proc), fReleaseCtx(ctx) {}
AutoCallback(CallbackWithStats proc, Context ctx)
: fReleaseWithStatsProc(proc), fReleaseCtx(ctx) {}
AutoCallback(ResultCallback proc, Context ctx) : fResultReleaseProc(proc), fReleaseCtx(ctx) {}
AutoCallback(ResultCallbackWithStats proc, Context ctx)
: fResultReleaseWithStatsProc(proc), fReleaseCtx(ctx) {}
~AutoCallback() {
SkASSERT(this->operator bool() || true); // run assert in the operator
if (fResultReleaseWithStatsProc) {
fResultReleaseWithStatsProc(fReleaseCtx, fResult, fGpuStats);
} else if (fReleaseWithStatsProc) {
fReleaseWithStatsProc(fReleaseCtx, fGpuStats);
} else if (fResultReleaseProc) {
fResultReleaseProc(fReleaseCtx, fResult);
} else if (fReleaseProc) {
fReleaseProc(fReleaseCtx);
}
}
AutoCallback& operator=(const AutoCallback&) = delete;
AutoCallback& operator=(AutoCallback&& that) {
fReleaseCtx = that.fReleaseCtx;
fReleaseProc = that.fReleaseProc;
fReleaseWithStatsProc = that.fReleaseWithStatsProc;
fResultReleaseProc = that.fResultReleaseProc;
fResultReleaseWithStatsProc = that.fResultReleaseWithStatsProc;
fResult = that.fResult;
fGpuStats = that.fGpuStats;
that.fReleaseProc = nullptr;
that.fReleaseWithStatsProc = nullptr;
that.fResultReleaseProc = nullptr;
that.fResultReleaseWithStatsProc = nullptr;
return *this;
}
Context context() const { return fReleaseCtx; }
bool receivesGpuStats() const { return fReleaseWithStatsProc || fResultReleaseWithStatsProc; }
void setFailureResult() {
SkASSERT(fResultReleaseProc || fResultReleaseWithStatsProc);
// Shouldn't really be calling this multiple times.
SkASSERT(fResult == CallbackResult::kSuccess);
fResult = CallbackResult::kFailed;
}
void setStats(const GpuStats& stats) {
SkASSERT(this->receivesGpuStats());
fGpuStats = stats;
}
explicit operator bool() const {
auto toInt = [](auto p) { return p ? 1U : 0U; };
auto total = toInt(fReleaseProc) + toInt(fReleaseWithStatsProc) + toInt(fResultReleaseProc);
SkASSERT(total <= 1);
return total == 1;
}
private:
Callback fReleaseProc = nullptr;
CallbackWithStats fReleaseWithStatsProc = nullptr;
ResultCallback fResultReleaseProc = nullptr;
ResultCallbackWithStats fResultReleaseWithStatsProc = nullptr;
Context fReleaseCtx = nullptr;
CallbackResult fResult = CallbackResult::kSuccess;
GpuStats fGpuStats = {};
};
/**
* Ref-counted object that calls a callback from its destructor.
*/
class RefCntedCallback : public SkNVRefCnt<RefCntedCallback> {
public:
using Context = AutoCallback::Context;
using Callback = AutoCallback::Callback;
using CallbackWithStats = AutoCallback::CallbackWithStats;
using ResultCallback = AutoCallback::ResultCallback;
using ResultCallbackWithStats = AutoCallback::ResultCallbackWithStats;
static sk_sp<RefCntedCallback> Make(Callback proc, Context ctx) { return MakeImpl(proc, ctx); }
static sk_sp<RefCntedCallback> Make(CallbackWithStats proc, Context ctx) {
return MakeImpl(proc, ctx);
}
static sk_sp<RefCntedCallback> Make(ResultCallback proc, Context ctx) {
return MakeImpl(proc, ctx);
}
static sk_sp<RefCntedCallback> Make(ResultCallbackWithStats proc, Context ctx) {
return MakeImpl(proc, ctx);
}
static sk_sp<RefCntedCallback> Make(AutoCallback&& callback) {
if (!callback) {
return nullptr;
}
return sk_sp<RefCntedCallback>(new RefCntedCallback(std::move(callback)));
}
Context context() const { return fCallback.context(); }
bool receivesGpuStats() const { return fCallback.receivesGpuStats(); }
void setFailureResult() { fCallback.setFailureResult(); }
void setStats(const GpuStats& stats) { fCallback.setStats(stats); }
private:
template <typename R, typename... Args>
static sk_sp<RefCntedCallback> MakeImpl(R proc(Args...), Context ctx) {
if (!proc) {
return nullptr;
}
return sk_sp<RefCntedCallback>(new RefCntedCallback({proc, ctx}));
}
RefCntedCallback(AutoCallback callback) : fCallback(std::move(callback)) {}
AutoCallback fCallback;
};
} // namespace skgpu
#endif // skgpu_RefCntedCallback_DEFINED