[graphite] Introduce ComputePipeline
* Added the ComputePipelineDesc, ComputePipeline and MtlComputePipeline
classes as the compute stage equivalents of GraphicsPipelineDesc,
GraphicsPipeline, and MtlGraphicsPipeline.
* Implemented rudimentary resource tracking for compute pipeline objects
using a name string that is provided during construction.
* A compute pipeline currently must be constructed with a unique name
and the complete SkSL program text directly. This is temporary until
there is a more sophisticated way to represent compute programs.
Bug: b/240604572
Change-Id: I228db6887ce9c9b5feeeb69df21577c05a6ff516
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/563517
Commit-Queue: Arman Uguray <armansito@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
diff --git a/gn/graphite.gni b/gn/graphite.gni
index 068e7b0..a582940 100644
--- a/gn/graphite.gni
+++ b/gn/graphite.gni
@@ -32,6 +32,8 @@
"$_src/CommandBuffer.cpp",
"$_src/CommandBuffer.h",
"$_src/CommandTypes.h",
+ "$_src/ComputePipeline.cpp",
+ "$_src/ComputePipeline.h",
"$_src/Context.cpp",
"$_src/ContextPriv.cpp",
"$_src/ContextPriv.h",
@@ -160,6 +162,8 @@
"$_src/mtl/MtlCaps.mm",
"$_src/mtl/MtlCommandBuffer.h",
"$_src/mtl/MtlCommandBuffer.mm",
+ "$_src/mtl/MtlComputePipeline.h",
+ "$_src/mtl/MtlComputePipeline.mm",
"$_src/mtl/MtlGpu.h",
"$_src/mtl/MtlGpu.mm",
"$_src/mtl/MtlGraphicsPipeline.h",
diff --git a/src/gpu/graphite/Caps.h b/src/gpu/graphite/Caps.h
index 68491e2..3e67deb 100644
--- a/src/gpu/graphite/Caps.h
+++ b/src/gpu/graphite/Caps.h
@@ -23,6 +23,7 @@
namespace skgpu::graphite {
struct ContextOptions;
+class ComputePipelineDesc;
class GraphicsPipelineDesc;
class GraphiteResourceKey;
struct RenderPassDesc;
@@ -47,6 +48,7 @@
virtual UniqueKey makeGraphicsPipelineKey(const GraphicsPipelineDesc&,
const RenderPassDesc&) const = 0;
+ virtual UniqueKey makeComputePipelineKey(const ComputePipelineDesc&) const = 0;
bool areColorTypeAndTextureInfoCompatible(SkColorType, const TextureInfo&) const;
diff --git a/src/gpu/graphite/ComputePipeline.cpp b/src/gpu/graphite/ComputePipeline.cpp
new file mode 100644
index 0000000..89d8694
--- /dev/null
+++ b/src/gpu/graphite/ComputePipeline.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2022 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/graphite/ComputePipeline.h"
+
+namespace skgpu::graphite {
+
+ComputePipeline::ComputePipeline(const Gpu* gpu)
+ : Resource(gpu, Ownership::kOwned, SkBudgeted::kYes) {}
+
+} // namespace skgpu::graphite
diff --git a/src/gpu/graphite/ComputePipeline.h b/src/gpu/graphite/ComputePipeline.h
new file mode 100644
index 0000000..d5a3787
--- /dev/null
+++ b/src/gpu/graphite/ComputePipeline.h
@@ -0,0 +1,38 @@
+/*
+ * 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_graphite_ComputePipeline_DEFINED
+#define skgpu_graphite_ComputePipeline_DEFINED
+
+#include "src/gpu/graphite/Resource.h"
+
+namespace skgpu::graphite {
+
+class Gpu;
+
+/**
+ * ComputePipeline corresponds to a backend specific pipeline used for compute (vs rendering),
+ * e.g. MTLComputePipelineState (Metal),
+ * CreateComputePipeline (Dawn),
+ * CreateComputePipelineState (D3D12),
+ * or VkComputePipelineCreateInfo (Vulkan).
+ */
+class ComputePipeline : public Resource {
+public:
+ ~ComputePipeline() override = default;
+
+ // TODO(b/240615224): The pipeline should return an optional effective local workgroup
+ // size if the value was statically assigned in the shader (when it's not possible to assign
+ // them via specialization constants).
+
+protected:
+ explicit ComputePipeline(const Gpu*);
+};
+
+} // namespace skgpu::graphite
+
+#endif // skgpu_graphite_ComputePipeline_DEFINED
diff --git a/src/gpu/graphite/ComputePipelineDesc.h b/src/gpu/graphite/ComputePipelineDesc.h
new file mode 100644
index 0000000..053889b
--- /dev/null
+++ b/src/gpu/graphite/ComputePipelineDesc.h
@@ -0,0 +1,66 @@
+/*
+ * 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_graphite_ComputePipelineDesc_DEFINED
+#define skgpu_graphite_ComputePipelineDesc_DEFINED
+
+#include "include/core/SkSpan.h"
+#include "include/private/SkOpts_spi.h"
+
+#include <array>
+#include <string>
+
+namespace skgpu::graphite {
+
+/**
+ * ComputePipelineDesc represents the state needed to create a backend specific ComputePipeline.
+ */
+class ComputePipelineDesc {
+public:
+ ComputePipelineDesc() = default;
+
+ SkSpan<const uint32_t> asKey() const {
+ return SkSpan(reinterpret_cast<const uint32_t*>(fName.data()),
+ this->keySize() / sizeof(uint32_t));
+ }
+
+ bool operator==(const ComputePipelineDesc& that) const { return this->fName == that.fName; }
+
+ bool operator!=(const ComputePipelineDesc& other) const { return !(*this == other); }
+
+ // TODO(b/240604614): Until we have a more sophisticated way to dynamically construct compute
+ // shader programs, this currently directly takes the entire program SkSL text as input. The
+ // caching scheme is based entirely on the name and could be improved.
+ const std::string& sksl() const { return fSkSL; }
+ const std::string& name() const { return fName; }
+
+ void setProgram(std::string sksl, std::string name) {
+ SkASSERT(!sksl.empty());
+ SkASSERT(name.size() >= sizeof(uint32_t));
+
+ fSkSL = std::move(sksl);
+ fName = std::move(name);
+ }
+
+ struct Hash {
+ uint32_t operator()(const ComputePipelineDesc& desc) const {
+ return SkOpts::hash_fn(desc.fName.data(), desc.keySize(), 0);
+ }
+ };
+
+private:
+ size_t keySize() const {
+ size_t nameLength = fName.length();
+ return nameLength - (nameLength % sizeof(uint32_t));
+ }
+
+ std::string fSkSL;
+ std::string fName;
+};
+
+} // namespace skgpu::graphite
+
+#endif // skgpu_graphite_ComputePipelineDesc_DEFINED
diff --git a/src/gpu/graphite/ContextUtils.cpp b/src/gpu/graphite/ContextUtils.cpp
index 225cf91..5506e3e 100644
--- a/src/gpu/graphite/ContextUtils.cpp
+++ b/src/gpu/graphite/ContextUtils.cpp
@@ -14,6 +14,7 @@
#include "src/core/SkKeyContext.h"
#include "src/core/SkPipelineData.h"
#include "src/core/SkShaderCodeDictionary.h"
+#include "src/gpu/graphite/GraphicsPipelineDesc.h"
#include "src/gpu/graphite/PaintParams.h"
#include "src/gpu/graphite/RecorderPriv.h"
#include "src/gpu/graphite/Renderer.h"
diff --git a/src/gpu/graphite/ResourceProvider.cpp b/src/gpu/graphite/ResourceProvider.cpp
index 2a09ceb..399a29b 100644
--- a/src/gpu/graphite/ResourceProvider.cpp
+++ b/src/gpu/graphite/ResourceProvider.cpp
@@ -10,10 +10,12 @@
#include "src/gpu/graphite/Buffer.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/CommandBuffer.h"
+#include "src/gpu/graphite/ComputePipeline.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/GlobalCache.h"
#include "src/gpu/graphite/Gpu.h"
#include "src/gpu/graphite/GraphicsPipeline.h"
+#include "src/gpu/graphite/GraphicsPipelineDesc.h"
#include "src/gpu/graphite/ResourceCache.h"
#include "src/gpu/graphite/Sampler.h"
#include "src/gpu/graphite/Texture.h"
@@ -28,19 +30,25 @@
, fGlobalCache(std::move(globalCache)) {
SkASSERT(fResourceCache);
fGraphicsPipelineCache.reset(new GraphicsPipelineCache(this));
+ fComputePipelineCache.reset(new ComputePipelineCache(this));
}
ResourceProvider::~ResourceProvider() {
fGraphicsPipelineCache.release();
+ fComputePipelineCache.release();
fResourceCache->shutdown();
}
sk_sp<GraphicsPipeline> ResourceProvider::findOrCreateGraphicsPipeline(
- const GraphicsPipelineDesc& pipelineDesc,
- const RenderPassDesc& renderPassDesc) {
+ const GraphicsPipelineDesc& pipelineDesc, const RenderPassDesc& renderPassDesc) {
return fGraphicsPipelineCache->refPipeline(fGpu->caps(), pipelineDesc, renderPassDesc);
}
+sk_sp<ComputePipeline> ResourceProvider::findOrCreateComputePipeline(
+ const ComputePipelineDesc& pipelineDesc) {
+ return fComputePipelineCache->refPipeline(fGpu->caps(), pipelineDesc);
+}
+
SkShaderCodeDictionary* ResourceProvider::shaderCodeDictionary() const {
return fGlobalCache->shaderCodeDictionary();
}
@@ -54,8 +62,8 @@
};
ResourceProvider::GraphicsPipelineCache::GraphicsPipelineCache(ResourceProvider* resourceProvider)
- : fMap(16) // TODO: find a good value for this
- , fResourceProvider(resourceProvider) {}
+ : fMap(16) // TODO: find a good value for this
+ , fResourceProvider(resourceProvider) {}
ResourceProvider::GraphicsPipelineCache::~GraphicsPipelineCache() {
SkASSERT(0 == fMap.count());
@@ -71,7 +79,7 @@
const RenderPassDesc& renderPassDesc) {
UniqueKey pipelineKey = caps->makeGraphicsPipelineKey(pipelineDesc, renderPassDesc);
- std::unique_ptr<Entry>* entry = fMap.find(pipelineKey);
+ std::unique_ptr<Entry>* entry = fMap.find(pipelineKey);
if (!entry) {
auto pipeline = fResourceProvider->onCreateGraphicsPipeline(pipelineDesc, renderPassDesc);
@@ -83,6 +91,36 @@
return (*entry)->fPipeline;
}
+struct ResourceProvider::ComputePipelineCache::Entry {
+ Entry(sk_sp<ComputePipeline> pipeline) : fPipeline(std::move(pipeline)) {}
+
+ sk_sp<ComputePipeline> fPipeline;
+};
+
+ResourceProvider::ComputePipelineCache::ComputePipelineCache(ResourceProvider* resourceProvider)
+ : fMap(16) // TODO: find a good value for this
+ , fResourceProvider(resourceProvider) {}
+
+ResourceProvider::ComputePipelineCache::~ComputePipelineCache() { SkASSERT(0 == fMap.count()); }
+
+void ResourceProvider::ComputePipelineCache::release() { fMap.reset(); }
+
+sk_sp<ComputePipeline> ResourceProvider::ComputePipelineCache::refPipeline(
+ const Caps* caps, const ComputePipelineDesc& pipelineDesc) {
+ UniqueKey pipelineKey = caps->makeComputePipelineKey(pipelineDesc);
+
+ std::unique_ptr<Entry>* entry = fMap.find(pipelineKey);
+
+ if (!entry) {
+ auto pipeline = fResourceProvider->onCreateComputePipeline(pipelineDesc);
+ if (!pipeline) {
+ return nullptr;
+ }
+ entry = fMap.insert(pipelineKey, std::unique_ptr<Entry>(new Entry(std::move(pipeline))));
+ }
+ return (*entry)->fPipeline;
+}
+
sk_sp<Texture> ResourceProvider::findOrCreateScratchTexture(SkISize dimensions,
const TextureInfo& info,
SkBudgeted budgeted) {
@@ -201,4 +239,4 @@
fRuntimeEffectDictionary.reset();
}
-} // namespace skgpu::graphite
+} // namespace skgpu::graphite
diff --git a/src/gpu/graphite/ResourceProvider.h b/src/gpu/graphite/ResourceProvider.h
index 042dac0..6133772 100644
--- a/src/gpu/graphite/ResourceProvider.h
+++ b/src/gpu/graphite/ResourceProvider.h
@@ -14,7 +14,6 @@
#include "src/core/SkRuntimeEffectDictionary.h"
#include "src/gpu/ResourceKey.h"
#include "src/gpu/graphite/CommandBuffer.h"
-#include "src/gpu/graphite/GraphicsPipelineDesc.h"
#include "src/gpu/graphite/ResourceTypes.h"
struct SkSamplingOptions;
@@ -29,9 +28,12 @@
class BackendTexture;
class Buffer;
class Caps;
+class ComputePipeline;
+class ComputePipelineDesc;
class GlobalCache;
class Gpu;
class GraphicsPipeline;
+class GraphicsPipelineDesc;
class GraphiteResourceKey;
class ResourceCache;
class Sampler;
@@ -47,6 +49,8 @@
sk_sp<GraphicsPipeline> findOrCreateGraphicsPipeline(const GraphicsPipelineDesc&,
const RenderPassDesc&);
+ sk_sp<ComputePipeline> findOrCreateComputePipeline(const ComputePipelineDesc&);
+
sk_sp<Texture> findOrCreateScratchTexture(SkISize, const TextureInfo&, SkBudgeted);
virtual sk_sp<Texture> createWrappedTexture(const BackendTexture&) = 0;
@@ -81,6 +85,7 @@
private:
virtual sk_sp<GraphicsPipeline> onCreateGraphicsPipeline(const GraphicsPipelineDesc&,
const RenderPassDesc&) = 0;
+ virtual sk_sp<ComputePipeline> onCreateComputePipeline(const ComputePipelineDesc&) = 0;
virtual sk_sp<Texture> createTexture(SkISize, const TextureInfo&, SkBudgeted) = 0;
virtual sk_sp<Buffer> createBuffer(size_t size, BufferType type, PrioritizeGpuReads) = 0;
@@ -115,12 +120,31 @@
ResourceProvider* fResourceProvider;
};
+ class ComputePipelineCache {
+ public:
+ ComputePipelineCache(ResourceProvider* resourceProvider);
+ ~ComputePipelineCache();
+
+ void release();
+ sk_sp<ComputePipeline> refPipeline(const Caps* caps, const ComputePipelineDesc&);
+
+ private:
+ struct Entry;
+ struct KeyHash {
+ uint32_t operator()(const UniqueKey& key) const { return key.hash(); }
+ };
+ SkLRUCache<UniqueKey, std::unique_ptr<Entry>, KeyHash> fMap;
+
+ ResourceProvider* fResourceProvider;
+ };
+
sk_sp<ResourceCache> fResourceCache;
sk_sp<GlobalCache> fGlobalCache;
// Cache of GraphicsPipelines
- // TODO: Move this onto GlobalCache
+ // TODO: Move these onto GlobalCache
std::unique_ptr<GraphicsPipelineCache> fGraphicsPipelineCache;
+ std::unique_ptr<ComputePipelineCache> fComputePipelineCache;
SkRuntimeEffectDictionary fRuntimeEffectDictionary;
};
diff --git a/src/gpu/graphite/mtl/MtlCaps.h b/src/gpu/graphite/mtl/MtlCaps.h
index e5fca2d..d0ab9a7 100644
--- a/src/gpu/graphite/mtl/MtlCaps.h
+++ b/src/gpu/graphite/mtl/MtlCaps.h
@@ -35,6 +35,7 @@
UniqueKey makeGraphicsPipelineKey(const GraphicsPipelineDesc&,
const RenderPassDesc&) const override;
+ UniqueKey makeComputePipelineKey(const ComputePipelineDesc&) const override;
bool isMac() const { return fGPUFamily == GPUFamily::kMac; }
bool isApple()const { return fGPUFamily == GPUFamily::kApple; }
diff --git a/src/gpu/graphite/mtl/MtlCaps.mm b/src/gpu/graphite/mtl/MtlCaps.mm
index c8535e2..8a1d00c 100644
--- a/src/gpu/graphite/mtl/MtlCaps.mm
+++ b/src/gpu/graphite/mtl/MtlCaps.mm
@@ -10,6 +10,7 @@
#include "include/gpu/graphite/TextureInfo.h"
#include "include/gpu/graphite/mtl/MtlTypes.h"
#include "src/gpu/graphite/CommandBuffer.h"
+#include "src/gpu/graphite/ComputePipelineDesc.h"
#include "src/gpu/graphite/GraphicsPipelineDesc.h"
#include "src/gpu/graphite/GraphiteResourceKey.h"
#include "src/gpu/graphite/mtl/MtlUtils.h"
@@ -617,6 +618,27 @@
return pipelineKey;
}
+UniqueKey MtlCaps::makeComputePipelineKey(const ComputePipelineDesc& pipelineDesc) const {
+ UniqueKey pipelineKey;
+ {
+ static const skgpu::UniqueKey::Domain kComputePipelineDomain = UniqueKey::GenerateDomain();
+ SkSpan<const uint32_t> pipelineDescKey = pipelineDesc.asKey();
+ UniqueKey::Builder builder(
+ &pipelineKey, kComputePipelineDomain, pipelineDescKey.size(), "ComputePipeline");
+ // Add ComputePipelineDesc key
+ for (unsigned int i = 0; i < pipelineDescKey.size(); ++i) {
+ builder[i] = pipelineDescKey[i];
+ }
+
+ // TODO(b/240615224): The local work group size may need to factor into the key on platforms
+ // that don't support specialization constants and require the workgroup/threadgroup size to
+ // be specified in the shader text (D3D12, Vulkan 1.0, and OpenGL).
+
+ builder.finish();
+ }
+ return pipelineKey;
+}
+
bool MtlCaps::onIsTexturable(const TextureInfo& info) const {
if (!(info.mtlTextureSpec().fUsage & MTLTextureUsageShaderRead)) {
return false;
diff --git a/src/gpu/graphite/mtl/MtlComputePipeline.h b/src/gpu/graphite/mtl/MtlComputePipeline.h
new file mode 100644
index 0000000..2298be4
--- /dev/null
+++ b/src/gpu/graphite/mtl/MtlComputePipeline.h
@@ -0,0 +1,44 @@
+/*
+ * 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_graphite_MtlComputePipeline_DEFINED
+#define skgpu_graphite_MtlComputePipeline_DEFINED
+
+#include "include/core/SkRefCnt.h"
+#include "include/ports/SkCFObject.h"
+#include "src/gpu/graphite/ComputePipeline.h"
+
+#import <Metal/Metal.h>
+
+namespace skgpu::graphite {
+
+class ComputePipelineDesc;
+class MtlGpu;
+class MtlResourceProvider;
+
+class MtlComputePipeline final : public ComputePipeline {
+public:
+ static sk_sp<MtlComputePipeline> Make(MtlResourceProvider*,
+ const MtlGpu*,
+ const ComputePipelineDesc&);
+ ~MtlComputePipeline() override = default;
+
+ id<MTLComputePipelineState> mtlPipelineState() const { return fPipelineState.get(); }
+
+private:
+ MtlComputePipeline(const Gpu* gpu, sk_cfp<id<MTLComputePipelineState>> pso)
+ : ComputePipeline(gpu)
+ , fPipelineState(std::move(pso)) {}
+
+ void freeGpuData() override;
+
+ sk_cfp<id<MTLComputePipelineState>> fPipelineState;
+};
+
+} // namespace skgpu::graphite
+
+#endif // skgpu_graphite_MtlComputePipeline_DEFINED
diff --git a/src/gpu/graphite/mtl/MtlComputePipeline.mm b/src/gpu/graphite/mtl/MtlComputePipeline.mm
new file mode 100644
index 0000000..e20c9a4
--- /dev/null
+++ b/src/gpu/graphite/mtl/MtlComputePipeline.mm
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2022 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/graphite/mtl/MtlComputePipeline.h"
+
+#include "include/gpu/ShaderErrorHandler.h"
+#include "src/gpu/graphite/ComputePipelineDesc.h"
+#include "src/gpu/graphite/Log.h"
+#include "src/gpu/graphite/mtl/MtlGpu.h"
+#include "src/gpu/graphite/mtl/MtlUtils.h"
+
+namespace skgpu::graphite {
+
+// static
+sk_sp<MtlComputePipeline> MtlComputePipeline::Make(MtlResourceProvider* resourceProvider,
+ const MtlGpu* gpu,
+ const ComputePipelineDesc& pipelineDesc) {
+ sk_cfp<MTLComputePipelineDescriptor*> psoDescriptor([MTLComputePipelineDescriptor new]);
+
+ std::string msl;
+ SkSL::Program::Inputs inputs;
+ SkSL::ProgramSettings settings;
+
+ ShaderErrorHandler* errorHandler = gpu->caps()->shaderErrorHandler();
+ if (!SkSLToMSL(gpu,
+ pipelineDesc.sksl(),
+ SkSL::ProgramKind::kCompute,
+ settings,
+ &msl,
+ &inputs,
+ errorHandler)) {
+ return nullptr;
+ }
+
+ sk_cfp<id<MTLLibrary>> shaderLibrary = MtlCompileShaderLibrary(gpu, msl, errorHandler);
+ if (!shaderLibrary) {
+ return nullptr;
+ }
+
+ (*psoDescriptor).label = @(pipelineDesc.name().c_str());
+ (*psoDescriptor).computeFunction = [shaderLibrary.get() newFunctionWithName:@"computeMain"];
+
+ // TODO(b/240604614): Populate input data attribute and buffer layout descriptors using the
+ // `stageInputDescriptor` property based on the contents of `pipelineDesc` (on iOS 10+ or
+ // macOS 10.12+).
+
+ // TODO(b/240604614): Define input buffer mutability using the `buffers` property based on
+ // the contents of `pipelineDesc` (on iOS 11+ or macOS 10.13+).
+
+ // TODO(b/240615224): Metal docs claim that setting the
+ // `threadGroupSizeIsMultipleOfThreadExecutionWidth` to YES may improve performance, IF we can
+ // guarantee that the thread group size used in a dispatch command is a multiple of
+ // `threadExecutionWidth` property of the pipeline state object (otherwise this will cause UB).
+
+ NSError* error;
+ sk_cfp<id<MTLComputePipelineState>> pso([gpu->device()
+ newComputePipelineStateWithDescriptor:psoDescriptor.get()
+ options:MTLPipelineOptionNone
+ reflection:NULL
+ error:&error]);
+ if (!pso) {
+ SKGPU_LOG_E("Compute pipeline creation failure:\n%s", error.debugDescription.UTF8String);
+ return nullptr;
+ }
+
+ return sk_sp<MtlComputePipeline>(new MtlComputePipeline(gpu, std::move(pso)));
+}
+
+void MtlComputePipeline::freeGpuData() { fPipelineState.reset(); }
+
+} // namespace skgpu::graphite
diff --git a/src/gpu/graphite/mtl/MtlGraphicsPipeline.mm b/src/gpu/graphite/mtl/MtlGraphicsPipeline.mm
index 5616358..6eb8935 100644
--- a/src/gpu/graphite/mtl/MtlGraphicsPipeline.mm
+++ b/src/gpu/graphite/mtl/MtlGraphicsPipeline.mm
@@ -357,7 +357,7 @@
[gpu->device() newRenderPipelineStateWithDescriptor:psoDescriptor.get()
error:&error]);
if (!pso) {
- SKGPU_LOG_E("Pipeline creation failure:\n%s", error.debugDescription.UTF8String);
+ SKGPU_LOG_E("Render pipeline creation failure:\n%s", error.debugDescription.UTF8String);
return nullptr;
}
diff --git a/src/gpu/graphite/mtl/MtlResourceProvider.h b/src/gpu/graphite/mtl/MtlResourceProvider.h
index cd27223..d57e9ec 100644
--- a/src/gpu/graphite/mtl/MtlResourceProvider.h
+++ b/src/gpu/graphite/mtl/MtlResourceProvider.h
@@ -36,6 +36,7 @@
sk_sp<CommandBuffer> createCommandBuffer() override;
sk_sp<GraphicsPipeline> onCreateGraphicsPipeline(const GraphicsPipelineDesc&,
const RenderPassDesc&) override;
+ sk_sp<ComputePipeline> onCreateComputePipeline(const ComputePipelineDesc&) override;
sk_sp<Texture> createTexture(SkISize, const TextureInfo&, SkBudgeted) override;
sk_sp<Buffer> createBuffer(size_t size, BufferType type, PrioritizeGpuReads) override;
diff --git a/src/gpu/graphite/mtl/MtlResourceProvider.mm b/src/gpu/graphite/mtl/MtlResourceProvider.mm
index 572fbc3..e488a22 100644
--- a/src/gpu/graphite/mtl/MtlResourceProvider.mm
+++ b/src/gpu/graphite/mtl/MtlResourceProvider.mm
@@ -12,6 +12,7 @@
#include "src/gpu/graphite/GraphicsPipelineDesc.h"
#include "src/gpu/graphite/mtl/MtlBuffer.h"
#include "src/gpu/graphite/mtl/MtlCommandBuffer.h"
+#include "src/gpu/graphite/mtl/MtlComputePipeline.h"
#include "src/gpu/graphite/mtl/MtlGpu.h"
#include "src/gpu/graphite/mtl/MtlGraphicsPipeline.h"
#include "src/gpu/graphite/mtl/MtlSampler.h"
@@ -44,6 +45,11 @@
renderPassDesc);
}
+sk_sp<ComputePipeline> MtlResourceProvider::onCreateComputePipeline(
+ const ComputePipelineDesc& pipelineDesc) {
+ return MtlComputePipeline::Make(this, this->mtlGpu(), pipelineDesc);
+}
+
sk_sp<Texture> MtlResourceProvider::createTexture(SkISize dimensions,
const TextureInfo& info,
SkBudgeted budgeted) {