diff --git a/experimental/graphite/include/BUILD.bazel b/experimental/graphite/include/BUILD.bazel index ee64026273..b9bc366ffd 100644 --- a/experimental/graphite/include/BUILD.bazel +++ b/experimental/graphite/include/BUILD.bazel @@ -30,7 +30,10 @@ generated_cc_atom( name = "GraphiteTypes_hdr", hdrs = ["GraphiteTypes.h"], visibility = ["//:__subpackages__"], - deps = ["//include/core:SkTypes_hdr"], + deps = [ + "//include/core:SkTypes_hdr", + "//include/gpu:GpuTypes_hdr", + ], ) generated_cc_atom( diff --git a/experimental/graphite/include/GraphiteTypes.h b/experimental/graphite/include/GraphiteTypes.h index 16c9a3f0f4..4e472b17ea 100644 --- a/experimental/graphite/include/GraphiteTypes.h +++ b/experimental/graphite/include/GraphiteTypes.h @@ -9,6 +9,7 @@ #define skgpu_GraphiteTypes_DEFINED #include "include/core/SkTypes.h" +#include "include/gpu/GpuTypes.h" #include @@ -17,8 +18,16 @@ namespace skgpu { class Recording; using GpuFinishedContext = void*; -using GpuFinishedProc = void (*)(GpuFinishedContext finishedContext); +using GpuFinishedProc = void (*)(GpuFinishedContext finishedContext, CallbackResult); +/** + * The fFinishedProc is called when the Recording has been submitted and finished on the GPU, or + * when there is a failure that caused it not to be submitted. The callback will always be called + * and the caller can use the callback to know it is safe to free any resources associated with + * the Recording that they may be holding onto. If the Recording is successfully submitted to the + * GPU the callback will be called with CallbackResult::kSuccess once the GPU has finished. All + * other cases where some failure occured it will be called with CallbackResult::kFailed. + */ struct InsertRecordingInfo { Recording* fRecording = nullptr; GpuFinishedContext fFinishedContext = nullptr; diff --git a/experimental/graphite/src/CommandBuffer.cpp b/experimental/graphite/src/CommandBuffer.cpp index 1950ca34a9..d8a8272691 100644 --- a/experimental/graphite/src/CommandBuffer.cpp +++ b/experimental/graphite/src/CommandBuffer.cpp @@ -37,7 +37,12 @@ void CommandBuffer::addFinishedProc(sk_sp finishedProc) { fFinishedProcs.push_back(std::move(finishedProc)); } -void CommandBuffer::callFinishedProcs() { +void CommandBuffer::callFinishedProcs(bool success) { + if (!success) { + for (int i = 0; i < fFinishedProcs.count(); ++i) { + fFinishedProcs[i]->setFailureResult(); + } + } fFinishedProcs.reset(); } diff --git a/experimental/graphite/src/CommandBuffer.h b/experimental/graphite/src/CommandBuffer.h index a3be958796..f6186bd28d 100644 --- a/experimental/graphite/src/CommandBuffer.h +++ b/experimental/graphite/src/CommandBuffer.h @@ -77,7 +77,7 @@ public: void trackResource(sk_sp resource); void addFinishedProc(sk_sp finishedProc); - void callFinishedProcs(); + void callFinishedProcs(bool success); bool beginRenderPass(const RenderPassDesc&, sk_sp colorTexture, diff --git a/experimental/graphite/src/Context.cpp b/experimental/graphite/src/Context.cpp index 5cd3cd953b..d420a6931d 100644 --- a/experimental/graphite/src/Context.cpp +++ b/experimental/graphite/src/Context.cpp @@ -60,6 +60,9 @@ void Context::insertRecording(const InsertRecordingInfo& info) { SkASSERT(info.fRecording); if (!info.fRecording) { + if (callback) { + callback->setFailureResult(); + } return; } diff --git a/experimental/graphite/src/GpuWorkSubmission.cpp b/experimental/graphite/src/GpuWorkSubmission.cpp index 1d0467d82b..c1a18a2f0f 100644 --- a/experimental/graphite/src/GpuWorkSubmission.cpp +++ b/experimental/graphite/src/GpuWorkSubmission.cpp @@ -15,7 +15,7 @@ GpuWorkSubmission::GpuWorkSubmission(sk_sp cmdBuffer) : fCommandBuffer(std::move(cmdBuffer)) {} GpuWorkSubmission::~GpuWorkSubmission() { - fCommandBuffer->callFinishedProcs(); + fCommandBuffer->callFinishedProcs(/*success=*/true); } } // namespace skgpu diff --git a/experimental/graphite/src/mtl/MtlGpu.mm b/experimental/graphite/src/mtl/MtlGpu.mm index db8b0e35b5..7360621c3e 100644 --- a/experimental/graphite/src/mtl/MtlGpu.mm +++ b/experimental/graphite/src/mtl/MtlGpu.mm @@ -59,7 +59,7 @@ std::unique_ptr Gpu::makeResourceProvider( class WorkSubmission final : public skgpu::GpuWorkSubmission { public: - WorkSubmission(sk_sp cmdBuffer) + WorkSubmission(sk_sp cmdBuffer) : GpuWorkSubmission(std::move(cmdBuffer)) {} ~WorkSubmission() override {} @@ -76,12 +76,13 @@ private: skgpu::Gpu::OutstandingSubmission Gpu::onSubmit(sk_sp commandBuffer) { SkASSERT(commandBuffer); - sk_sp& mtlCmdBuffer = (sk_sp&)(commandBuffer); + CommandBuffer* mtlCmdBuffer = static_cast(commandBuffer.get()); if (!mtlCmdBuffer->commit()) { + commandBuffer->callFinishedProcs(/*success=*/false); return nullptr; } - std::unique_ptr submission(new WorkSubmission(mtlCmdBuffer)); + std::unique_ptr submission(new WorkSubmission(std::move(commandBuffer))); return submission; } diff --git a/gn/gpu.gni b/gn/gpu.gni index 3df0de44d4..b2acbfb88f 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -801,6 +801,7 @@ skia_native_gpu_sources = [ ] skia_shared_gpu_sources = [ + "$_include/gpu/GpuTypes.h", "$_include/gpu/ShaderErrorHandler.h", "$_include/private/SingleOwner.h", "$_src/gpu/Blend.h", diff --git a/include/gpu/BUILD.bazel b/include/gpu/BUILD.bazel index a2f278dae8..dfe47b4476 100644 --- a/include/gpu/BUILD.bazel +++ b/include/gpu/BUILD.bazel @@ -167,3 +167,10 @@ generated_cc_atom( visibility = ["//:__subpackages__"], deps = ["//include/core:SkTypes_hdr"], ) + +generated_cc_atom( + name = "GpuTypes_hdr", + hdrs = ["GpuTypes.h"], + visibility = ["//:__subpackages__"], + deps = ["//include/core:SkTypes_hdr"], +) diff --git a/include/gpu/GpuTypes.h b/include/gpu/GpuTypes.h new file mode 100644 index 0000000000..0c8ffa276f --- /dev/null +++ b/include/gpu/GpuTypes.h @@ -0,0 +1,32 @@ +/* + * 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_GpuTypes_DEFINED +#define skgpu_GpuTypes_DEFINED + +#include "include/core/SkTypes.h" + +/** + * This file includes numerous public types that are used by all of our gpu backends. + */ + +namespace skgpu { + +/** + * Value passed into various callbacks to tell the client the result of operations connected to a + * specific callback. The actual interpretation of kFailed and kSuccess are dependent on the + * specific callbacks and are documented with the callback itself. + */ +enum class CallbackResult : bool { + kFailed = true, + kSuccess = true, +}; + + +} // namespace skgpu + +#endif // skgpu_GpuTypes_DEFINED diff --git a/src/gpu/BUILD.bazel b/src/gpu/BUILD.bazel index 60eab2c0d8..25ed2d91aa 100644 --- a/src/gpu/BUILD.bazel +++ b/src/gpu/BUILD.bazel @@ -3564,5 +3564,8 @@ generated_cc_atom( name = "RefCntedCallback_hdr", hdrs = ["RefCntedCallback.h"], visibility = ["//:__subpackages__"], - deps = ["//include/core:SkRefCnt_hdr"], + deps = [ + "//include/core:SkRefCnt_hdr", + "//include/gpu:GpuTypes_hdr", + ], ) diff --git a/src/gpu/RefCntedCallback.h b/src/gpu/RefCntedCallback.h index cb3d0aa8c5..081df0ffd4 100644 --- a/src/gpu/RefCntedCallback.h +++ b/src/gpu/RefCntedCallback.h @@ -9,6 +9,7 @@ #define skgpu_RefCntedCallback_DEFINED #include "include/core/SkRefCnt.h" +#include "include/gpu/GpuTypes.h" namespace skgpu { /** @@ -18,6 +19,7 @@ class RefCntedCallback : public SkNVRefCnt { public: using Context = void*; using Callback = void (*)(Context); + using ResultCallback = void (*)(Context, CallbackResult); static sk_sp Make(Callback proc, Context ctx) { if (!proc) { @@ -26,19 +28,45 @@ public: return sk_sp(new RefCntedCallback(proc, ctx)); } - ~RefCntedCallback() { fReleaseProc(fReleaseCtx); } + static sk_sp Make(ResultCallback proc, Context ctx) { + if (!proc) { + return nullptr; + } + return sk_sp(new RefCntedCallback(proc, ctx)); + } + + ~RefCntedCallback() { + if (fReleaseProc) { + SkASSERT(!fResultReleaseProc); + fReleaseProc(fReleaseCtx); + } else { + SkASSERT(fResultReleaseProc); + fResultReleaseProc(fReleaseCtx, fResult); + } + } Context context() const { return fReleaseCtx; } + void setFailureResult() { + SkASSERT(fResultReleaseProc); + // Shouldn't really be calling this multiple times. + SkASSERT(fResult == CallbackResult::kSuccess); + fResult = CallbackResult::kFailed; + } + private: RefCntedCallback(Callback proc, Context ctx) : fReleaseProc(proc), fReleaseCtx(ctx) {} + RefCntedCallback(ResultCallback proc, Context ctx) + : fResultReleaseProc(proc), fReleaseCtx(ctx) {} RefCntedCallback(const RefCntedCallback&) = delete; RefCntedCallback(RefCntedCallback&&) = delete; RefCntedCallback& operator=(const RefCntedCallback&) = delete; RefCntedCallback& operator=(RefCntedCallback&&) = delete; - Callback fReleaseProc; + Callback fReleaseProc = nullptr; + ResultCallback fResultReleaseProc = nullptr; Context fReleaseCtx; + CallbackResult fResult = CallbackResult::kSuccess; }; } // namespace skgpu diff --git a/tools/gpu/BUILD.bazel b/tools/gpu/BUILD.bazel index dbcfc76d48..cff5df1eac 100644 --- a/tools/gpu/BUILD.bazel +++ b/tools/gpu/BUILD.bazel @@ -98,7 +98,10 @@ generated_cc_atom( name = "FlushFinishTracker_hdr", hdrs = ["FlushFinishTracker.h"], visibility = ["//:__subpackages__"], - deps = ["//include/core:SkRefCnt_hdr"], + deps = [ + "//include/core:SkRefCnt_hdr", + "//include/gpu:GpuTypes_hdr", + ], ) generated_cc_atom( diff --git a/tools/gpu/FlushFinishTracker.h b/tools/gpu/FlushFinishTracker.h index 715ffb3d65..bd9b55228b 100644 --- a/tools/gpu/FlushFinishTracker.h +++ b/tools/gpu/FlushFinishTracker.h @@ -9,6 +9,7 @@ #define FlushFinishTracker_DEFINED #include "include/core/SkRefCnt.h" +#include "include/gpu/GpuTypes.h" class GrDirectContext; @@ -26,6 +27,10 @@ public: tracker->unref(); } + static void FlushFinishedResult(void* finishedContext, skgpu::CallbackResult) { + FlushFinished(finishedContext); + } + FlushFinishTracker(GrDirectContext* context) : fContext(context) {} #ifdef SK_GRAPHITE_ENABLED FlushFinishTracker(skgpu::Context* context) : fGraphiteContext(context) {} diff --git a/tools/graphite/GraphiteTestContext.cpp b/tools/graphite/GraphiteTestContext.cpp index 9b94003691..df8b369c42 100644 --- a/tools/graphite/GraphiteTestContext.cpp +++ b/tools/graphite/GraphiteTestContext.cpp @@ -38,7 +38,7 @@ void GraphiteTestContext::submitRecordingAndWaitOnSync(skgpu::Context* context, skgpu::InsertRecordingInfo info; info.fRecording = recording; info.fFinishedContext = fFinishTrackers[fCurrentFlushIdx].get(); - info.fFinishedProc = sk_gpu_test::FlushFinishTracker::FlushFinished; + info.fFinishedProc = sk_gpu_test::FlushFinishTracker::FlushFinishedResult; context->insertRecording(info); context->submit(skgpu::SyncToCpu::kNo);