Flutter Engine
The Flutter Engine
MtlResourceProvider.mm
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
13
15#include "src/gpu/Blend.h"
17#include "src/gpu/Swizzle.h"
38
39#import <Metal/Metal.h>
40
41namespace skgpu::graphite {
42
44 SingleOwner* singleOwner,
45 uint32_t recorderID,
46 size_t resourceBudget)
47 : ResourceProvider(sharedContext, singleOwner, recorderID, resourceBudget) {}
48
49const MtlSharedContext* MtlResourceProvider::mtlSharedContext() {
50 return static_cast<const MtlSharedContext*>(fSharedContext);
51}
52
54 const RenderPassDesc& renderPassDesc) {
55 uint64_t renderPassKey =
56 this->mtlSharedContext()->mtlCaps().getRenderPassDescKey(renderPassDesc);
57 sk_sp<MtlGraphicsPipeline> pipeline = fLoadMSAAPipelines[renderPassKey];
58 if (!pipeline) {
59 static const char* kLoadMSAAShaderText = R"(
60 #include <metal_stdlib>
61 #include <simd/simd.h>
62 using namespace metal;
63
64 typedef struct {
65 float4 position [[position]];
66 } VertexOutput;
67
68 vertex VertexOutput vertexMain(uint vertexID [[vertex_id]]) {
69 VertexOutput out;
70 float2 position = float2(float(vertexID >> 1), float(vertexID & 1));
71 out.position = float4(2.0 * position - 1.0, 0.0, 1.0);
72 return out;
73 }
74
75 fragment float4 fragmentMain(VertexOutput in [[stage_in]],
76 texture2d<half> colorMap [[texture(0)]]) {
77 uint2 coords = uint2(in.position.x, in.position.y);
78 half4 colorSample = colorMap.read(coords);
79 return float4(colorSample);
80 }
81 )";
82
83 auto mtlLibrary = MtlCompileShaderLibrary(this->mtlSharedContext(),
84 "LoadMSAAFromResolve",
85 kLoadMSAAShaderText,
87 BlendInfo noBlend{}; // default is equivalent to kSrc blending
88 sk_cfp<id<MTLDepthStencilState>> ignoreDS =
89 this->findOrCreateCompatibleDepthStencilState({});
90
91 std::string pipelineLabel = "LoadMSAAFromResolve + ";
92 pipelineLabel += renderPassDesc.toString().c_str();
93 pipeline = MtlGraphicsPipeline::Make(this->mtlSharedContext(),
94 pipelineLabel,
95 {mtlLibrary.get(), "vertexMain"},
96 /*vertexAttrs=*/{},
97 /*instanceAttrs=*/{},
98 {mtlLibrary.get(), "fragmentMain"},
99 std::move(ignoreDS),
100 /*stencilRefValue=*/0,
101 noBlend,
102 renderPassDesc,
103 /*pipelineInfo=*/nullptr);
104 if (pipeline) {
105 fLoadMSAAPipelines.set(renderPassKey, pipeline);
106 }
107 }
108
109 return pipeline;
110}
111
112sk_sp<GraphicsPipeline> MtlResourceProvider::createGraphicsPipeline(
113 const RuntimeEffectDictionary* runtimeDict,
114 const GraphicsPipelineDesc& pipelineDesc,
115 const RenderPassDesc& renderPassDesc) {
116 std::string vsMSL, fsMSL;
117 SkSL::Program::Interface vsInterface, fsInterface;
119
120 settings.fForceNoRTFlip = true;
121
122 SkSL::Compiler skslCompiler;
124
125 const RenderStep* step =
127 const bool useStorageBuffers = fSharedContext->caps()->storageBufferPreferred();
128
129 UniquePaintParamsID paintID = pipelineDesc.paintParamsID();
132 runtimeDict,
133 step,
134 paintID,
135 useStorageBuffers,
136 renderPassDesc.fWriteSwizzle);
137 std::string& fsSkSL = fsSkSLInfo.fSkSL;
138 const BlendInfo& blendInfo = fsSkSLInfo.fBlendInfo;
139 const bool localCoordsNeeded = fsSkSLInfo.fRequiresLocalCoords;
141 fsSkSL,
143 settings,
144 &fsMSL,
145 &fsInterface,
146 errorHandler)) {
147 return nullptr;
148 }
149
150 VertSkSLInfo vsSkSLInfo = BuildVertexSkSL(fSharedContext->caps()->resourceBindingRequirements(),
151 step,
152 useStorageBuffers,
153 localCoordsNeeded);
154 const std::string& vsSkSL = vsSkSLInfo.fSkSL;
156 vsSkSL,
158 settings,
159 &vsMSL,
160 &vsInterface,
161 errorHandler)) {
162 return nullptr;
163 }
164
165 auto vsLibrary = MtlCompileShaderLibrary(
166 this->mtlSharedContext(), vsSkSLInfo.fLabel, vsMSL, errorHandler);
167 auto fsLibrary = MtlCompileShaderLibrary(
168 this->mtlSharedContext(), fsSkSLInfo.fLabel, fsMSL, errorHandler);
169
170 sk_cfp<id<MTLDepthStencilState>> dss =
171 this->findOrCreateCompatibleDepthStencilState(step->depthStencilSettings());
172
173#if defined(GRAPHITE_TEST_UTILS)
174 GraphicsPipeline::PipelineInfo pipelineInfo = {pipelineDesc.renderStepID(),
175 pipelineDesc.paintParamsID(),
176 std::move(vsSkSL),
177 std::move(fsSkSL),
178 std::move(vsMSL),
179 std::move(fsMSL) };
180 GraphicsPipeline::PipelineInfo* pipelineInfoPtr = &pipelineInfo;
181#else
182 GraphicsPipeline::PipelineInfo* pipelineInfoPtr = nullptr;
183#endif
184 std::string pipelineLabel =
185 GetPipelineLabel(fSharedContext->shaderCodeDictionary(), renderPassDesc, step, paintID);
186 return MtlGraphicsPipeline::Make(this->mtlSharedContext(),
187 pipelineLabel,
188 {vsLibrary.get(), "vertexMain"},
189 step->vertexAttributes(),
190 step->instanceAttributes(),
191 {fsLibrary.get(), "fragmentMain"},
192 std::move(dss),
193 step->depthStencilSettings().fStencilReferenceValue,
194 blendInfo,
195 renderPassDesc,
196 pipelineInfoPtr);
197}
198
199sk_sp<ComputePipeline> MtlResourceProvider::createComputePipeline(
200 const ComputePipelineDesc& pipelineDesc) {
201 sk_cfp<id<MTLLibrary>> library;
202 std::string entryPointName;
203 ShaderErrorHandler* errorHandler = fSharedContext->caps()->shaderErrorHandler();
204 if (pipelineDesc.computeStep()->supportsNativeShader()) {
205 auto nativeShader = pipelineDesc.computeStep()->nativeShaderSource(
207 library = MtlCompileShaderLibrary(this->mtlSharedContext(),
208 pipelineDesc.computeStep()->name(),
209 nativeShader.fSource,
210 errorHandler);
211 if (library == nil) {
212 return nullptr;
213 }
214 entryPointName = std::move(nativeShader.fEntryPoint);
215 } else {
216 std::string msl;
217 SkSL::Program::Interface interface;
219
220 SkSL::Compiler skslCompiler;
221 std::string sksl = BuildComputeSkSL(fSharedContext->caps(), pipelineDesc.computeStep());
223 sksl,
225 settings,
226 &msl,
227 &interface,
228 errorHandler)) {
229 return nullptr;
230 }
231 library = MtlCompileShaderLibrary(this->mtlSharedContext(),
232 pipelineDesc.computeStep()->name(),
233 msl,
234 errorHandler);
235 entryPointName = "computeMain";
236 }
237 return MtlComputePipeline::Make(this->mtlSharedContext(),
238 pipelineDesc.computeStep()->name(),
239 {library.get(), std::move(entryPointName)});
240}
241
242sk_sp<Texture> MtlResourceProvider::createTexture(SkISize dimensions,
243 const TextureInfo& info,
244 skgpu::Budgeted budgeted) {
245 return MtlTexture::Make(this->mtlSharedContext(), dimensions, info, budgeted);
246}
247
248sk_sp<Texture> MtlResourceProvider::onCreateWrappedTexture(const BackendTexture& texture) {
249 CFTypeRef mtlHandleTexture = texture.getMtlTexture();
250 if (!mtlHandleTexture) {
251 return nullptr;
252 }
253 sk_cfp<id<MTLTexture>> mtlTexture = sk_ret_cfp((id<MTLTexture>)mtlHandleTexture);
254 return MtlTexture::MakeWrapped(this->mtlSharedContext(), texture.dimensions(), texture.info(),
255 std::move(mtlTexture));
256}
257
258sk_sp<Buffer> MtlResourceProvider::createBuffer(size_t size,
260 AccessPattern accessPattern) {
261 return MtlBuffer::Make(this->mtlSharedContext(), size, type, accessPattern);
262}
263
264sk_sp<Sampler> MtlResourceProvider::createSampler(const SamplerDesc& samplerDesc) {
265 return MtlSampler::Make(this->mtlSharedContext(),
266 samplerDesc.samplingOptions(),
267 samplerDesc.tileModeX(),
268 samplerDesc.tileModeY());
269}
270
271namespace {
272MTLCompareFunction compare_op_to_mtl(CompareOp op) {
273 switch (op) {
275 return MTLCompareFunctionAlways;
277 return MTLCompareFunctionNever;
279 return MTLCompareFunctionGreater;
281 return MTLCompareFunctionGreaterEqual;
282 case CompareOp::kLess:
283 return MTLCompareFunctionLess;
285 return MTLCompareFunctionLessEqual;
287 return MTLCompareFunctionEqual;
289 return MTLCompareFunctionNotEqual;
290 }
291}
292
293MTLStencilOperation stencil_op_to_mtl(StencilOp op) {
294 switch (op) {
295 case StencilOp::kKeep:
296 return MTLStencilOperationKeep;
297 case StencilOp::kZero:
298 return MTLStencilOperationZero;
300 return MTLStencilOperationReplace;
302 return MTLStencilOperationInvert;
304 return MTLStencilOperationIncrementWrap;
306 return MTLStencilOperationDecrementWrap;
308 return MTLStencilOperationIncrementClamp;
310 return MTLStencilOperationDecrementClamp;
311 }
312}
313
314MTLStencilDescriptor* stencil_face_to_mtl(DepthStencilSettings::Face face) {
315 MTLStencilDescriptor* result = [[MTLStencilDescriptor alloc] init];
316 result.stencilCompareFunction = compare_op_to_mtl(face.fCompareOp);
317 result.readMask = face.fReadMask;
318 result.writeMask = face.fWriteMask;
319 result.depthStencilPassOperation = stencil_op_to_mtl(face.fDepthStencilPassOp);
320 result.stencilFailureOperation = stencil_op_to_mtl(face.fStencilFailOp);
321 return result;
322}
323} // anonymous namespace
324
325sk_cfp<id<MTLDepthStencilState>> MtlResourceProvider::findOrCreateCompatibleDepthStencilState(
326 const DepthStencilSettings& depthStencilSettings) {
327 sk_cfp<id<MTLDepthStencilState>>* depthStencilState;
328 depthStencilState = fDepthStencilStates.find(depthStencilSettings);
329 if (!depthStencilState) {
330 MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init];
331 SkASSERT(depthStencilSettings.fDepthTestEnabled ||
332 depthStencilSettings.fDepthCompareOp == CompareOp::kAlways);
333 desc.depthCompareFunction = compare_op_to_mtl(depthStencilSettings.fDepthCompareOp);
334 if (depthStencilSettings.fDepthTestEnabled) {
335 desc.depthWriteEnabled = depthStencilSettings.fDepthWriteEnabled;
336 }
337 if (depthStencilSettings.fStencilTestEnabled) {
338 desc.frontFaceStencil = stencil_face_to_mtl(depthStencilSettings.fFrontStencil);
339 desc.backFaceStencil = stencil_face_to_mtl(depthStencilSettings.fBackStencil);
340 }
341
342 sk_cfp<id<MTLDepthStencilState>> dss(
343 [this->mtlSharedContext()->device() newDepthStencilStateWithDescriptor: desc]);
344 depthStencilState = fDepthStencilStates.set(depthStencilSettings, std::move(dss));
345 }
346
347 SkASSERT(depthStencilState);
348 return *depthStencilState;
349}
350
351BackendTexture MtlResourceProvider::onCreateBackendTexture(SkISize dimensions,
352 const TextureInfo& info) {
353 sk_cfp<id<MTLTexture>> texture = MtlTexture::MakeMtlTexture(this->mtlSharedContext(),
354 dimensions,
355 info);
356 if (!texture) {
357 return {};
358 }
359 return BackendTexture(dimensions, (CFTypeRef)texture.release());
360}
361
362void MtlResourceProvider::onDeleteBackendTexture(const BackendTexture& texture) {
363 SkASSERT(texture.backend() == BackendApi::kMetal);
364 CFTypeRef texHandle = texture.getMtlTexture();
365 SkCFSafeRelease(texHandle);
366}
367
368} // namespace skgpu::graphite
static int step(int x, SkScalar min, SkScalar max)
Definition: BlurTest.cpp:215
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
#define SkASSERT(cond)
Definition: SkAssert.h:116
GLenum type
const char * c_str() const
Definition: SkString.h:133
skgpu::ShaderErrorHandler * shaderErrorHandler() const
Definition: Caps.h:273
const ResourceBindingRequirements & resourceBindingRequirements() const
Definition: Caps.h:150
bool storageBufferPreferred() const
Definition: Caps.h:239
const SkSL::ShaderCaps * shaderCaps() const
Definition: Caps.h:75
UniquePaintParamsID paintParamsID() const
static sk_sp< Buffer > Make(const MtlSharedContext *, size_t size, BufferType type, AccessPattern)
Definition: MtlBuffer.mm:15
uint64_t getRenderPassDescKey(const RenderPassDesc &) const
Definition: MtlCaps.mm:997
static sk_sp< MtlComputePipeline > Make(const MtlSharedContext *, const std::string &label, MSLFunction computeMain)
static sk_sp< MtlGraphicsPipeline > Make(const MtlSharedContext *, const std::string &label, MSLFunction vertexMain, SkSpan< const Attribute > vertexAttrs, SkSpan< const Attribute > instanceAttrs, MSLFunction fragmentMain, sk_cfp< id< MTLDepthStencilState > >, uint32_t stencilRefValue, const BlendInfo &blendInfo, const RenderPassDesc &, PipelineInfo *pipelineInfo)
sk_sp< MtlGraphicsPipeline > findOrCreateLoadMSAAPipeline(const RenderPassDesc &)
MtlResourceProvider(SharedContext *sharedContext, SingleOwner *, uint32_t recorderID, size_t resourceBudget)
static sk_sp< MtlSampler > Make(const MtlSharedContext *, const SkSamplingOptions &samplingOptions, SkTileMode xTileMode, SkTileMode yTileMode)
Definition: MtlSampler.mm:47
const MtlCaps & mtlCaps() const
static sk_sp< Texture > Make(const MtlSharedContext *, SkISize dimensions, const TextureInfo &, skgpu::Budgeted)
Definition: MtlTexture.mm:80
static sk_cfp< id< MTLTexture > > MakeMtlTexture(const MtlSharedContext *, SkISize dimensions, const TextureInfo &)
Definition: MtlTexture.mm:20
static sk_sp< Texture > MakeWrapped(const MtlSharedContext *, SkISize dimensions, const TextureInfo &, sk_cfp< id< MTLTexture > >)
Definition: MtlTexture.mm:96
const RenderStep * lookup(uint32_t uniqueID) const
const Caps * caps() const
Definition: SharedContext.h:39
ShaderCodeDictionary * shaderCodeDictionary()
Definition: SharedContext.h:49
const RendererProvider * rendererProvider() const
Definition: SharedContext.h:47
VkDevice device
Definition: main.cc:53
GAsyncResult * result
FlTexture * texture
static bool init()
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
VertSkSLInfo BuildVertexSkSL(const ResourceBindingRequirements &bindingReqs, const RenderStep *step, bool useStorageBuffers, bool defineLocalCoordsVarying)
std::string BuildComputeSkSL(const Caps *caps, const ComputeStep *step)
FragSkSLInfo BuildFragmentSkSL(const Caps *caps, const ShaderCodeDictionary *dict, const RuntimeEffectDictionary *rteDict, const RenderStep *step, UniquePaintParamsID paintID, bool useStorageBuffers, skgpu::Swizzle writeSwizzle)
std::string GetPipelineLabel(const ShaderCodeDictionary *dict, const RenderPassDesc &renderPassDesc, const RenderStep *renderStep, UniquePaintParamsID paintID)
sk_cfp< id< MTLLibrary > > MtlCompileShaderLibrary(const MtlSharedContext *sharedContext, std::string_view label, std::string_view msl, ShaderErrorHandler *errorHandler)
bool SkSLToMSL(const SkSL::ShaderCaps *caps, const std::string &sksl, SkSL::ProgramKind programKind, const SkSL::ProgramSettings &settings, std::string *msl, SkSL::ProgramInterface *outInterface, ShaderErrorHandler *errorHandler)
Definition: MtlUtilsPriv.h:30
Budgeted
Definition: GpuTypes.h:35
Definition: SkSize.h:16