| /* | |
| * 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 | |