Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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;
111
113 const RuntimeEffectDictionary* runtimeDict,
114 const GraphicsPipelineDesc& pipelineDesc,
115 const RenderPassDesc& renderPassDesc) {
116 std::string vsMSL, fsMSL;
117 SkSL::Program::Interface vsInterface, fsInterface;
118 SkSL::ProgramSettings settings;
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);
198
200 const ComputePipelineDesc& pipelineDesc) {
201 sk_cfp<id<MTLLibrary>> library;
202 std::string entryPointName;
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;
218 SkSL::ProgramSettings settings;
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)});
245 return MtlTexture::Make(this->mtlSharedContext(), dimensions, info, budgeted);
247
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(),
255 texture.dimensions(),
256 texture.info(),
257 std::move(mtlTexture));
259
262 AccessPattern accessPattern,
263 std::string_view label) {
264 return MtlBuffer::Make(this->mtlSharedContext(), size, type, accessPattern, std::move(label));
266
268 return MtlSampler::Make(this->mtlSharedContext(),
269 samplerDesc.samplingOptions(),
270 samplerDesc.tileModeX(),
271 samplerDesc.tileModeY());
272}
273
274namespace {
275MTLCompareFunction compare_op_to_mtl(CompareOp op) {
276 switch (op) {
278 return MTLCompareFunctionAlways;
280 return MTLCompareFunctionNever;
282 return MTLCompareFunctionGreater;
284 return MTLCompareFunctionGreaterEqual;
285 case CompareOp::kLess:
286 return MTLCompareFunctionLess;
288 return MTLCompareFunctionLessEqual;
290 return MTLCompareFunctionEqual;
292 return MTLCompareFunctionNotEqual;
293 }
294}
295
296MTLStencilOperation stencil_op_to_mtl(StencilOp op) {
297 switch (op) {
298 case StencilOp::kKeep:
299 return MTLStencilOperationKeep;
300 case StencilOp::kZero:
301 return MTLStencilOperationZero;
303 return MTLStencilOperationReplace;
305 return MTLStencilOperationInvert;
307 return MTLStencilOperationIncrementWrap;
309 return MTLStencilOperationDecrementWrap;
311 return MTLStencilOperationIncrementClamp;
313 return MTLStencilOperationDecrementClamp;
314 }
315}
316
317MTLStencilDescriptor* stencil_face_to_mtl(DepthStencilSettings::Face face) {
318 MTLStencilDescriptor* result = [[MTLStencilDescriptor alloc] init];
319 result.stencilCompareFunction = compare_op_to_mtl(face.fCompareOp);
320 result.readMask = face.fReadMask;
321 result.writeMask = face.fWriteMask;
322 result.depthStencilPassOperation = stencil_op_to_mtl(face.fDepthStencilPassOp);
323 result.stencilFailureOperation = stencil_op_to_mtl(face.fStencilFailOp);
324 return result;
325}
326} // anonymous namespace
327
328sk_cfp<id<MTLDepthStencilState>> MtlResourceProvider::findOrCreateCompatibleDepthStencilState(
329 const DepthStencilSettings& depthStencilSettings) {
330 sk_cfp<id<MTLDepthStencilState>>* depthStencilState;
331 depthStencilState = fDepthStencilStates.find(depthStencilSettings);
332 if (!depthStencilState) {
333 MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init];
334 SkASSERT(depthStencilSettings.fDepthTestEnabled ||
335 depthStencilSettings.fDepthCompareOp == CompareOp::kAlways);
336 desc.depthCompareFunction = compare_op_to_mtl(depthStencilSettings.fDepthCompareOp);
337 if (depthStencilSettings.fDepthTestEnabled) {
338 desc.depthWriteEnabled = depthStencilSettings.fDepthWriteEnabled;
339 }
340 if (depthStencilSettings.fStencilTestEnabled) {
341 desc.frontFaceStencil = stencil_face_to_mtl(depthStencilSettings.fFrontStencil);
342 desc.backFaceStencil = stencil_face_to_mtl(depthStencilSettings.fBackStencil);
343 }
344
345 sk_cfp<id<MTLDepthStencilState>> dss(
346 [this->mtlSharedContext()->device() newDepthStencilStateWithDescriptor: desc]);
347 depthStencilState = fDepthStencilStates.set(depthStencilSettings, std::move(dss));
348 }
349
350 SkASSERT(depthStencilState);
351 return *depthStencilState;
353
355 const TextureInfo& info) {
356 sk_cfp<id<MTLTexture>> texture = MtlTexture::MakeMtlTexture(this->mtlSharedContext(),
357 dimensions,
358 info);
359 if (!texture) {
360 return {};
361 }
362 return BackendTexture(dimensions, (CFTypeRef)texture.release());
364
366 SkASSERT(texture.backend() == BackendApi::kMetal);
367 CFTypeRef texHandle = texture.getMtlTexture();
368 SkCFSafeRelease(texHandle);
369}
370
371} // 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
const char * c_str() const
Definition SkString.h:133
skgpu::ShaderErrorHandler * shaderErrorHandler() const
Definition Caps.h:266
const ResourceBindingRequirements & resourceBindingRequirements() const
Definition Caps.h:143
bool storageBufferPreferred() const
Definition Caps.h:232
const SkSL::ShaderCaps * shaderCaps() const
Definition Caps.h:74
const ComputeStep * computeStep() const
virtual NativeShaderSource nativeShaderSource(NativeShaderFormat) const
const char * name() const
UniquePaintParamsID paintParamsID() const
static sk_sp< Buffer > Make(const MtlSharedContext *, size_t size, BufferType type, AccessPattern, std::string_view label)
Definition MtlBuffer.mm:31
uint64_t getRenderPassDescKey(const RenderPassDesc &) const
Definition MtlCaps.mm:1055
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< GraphicsPipeline > createGraphicsPipeline(const RuntimeEffectDictionary *, const GraphicsPipelineDesc &, const RenderPassDesc &) override
sk_sp< Buffer > createBuffer(size_t size, BufferType type, AccessPattern, std::string_view label) override
sk_sp< Texture > createTexture(SkISize, const TextureInfo &, skgpu::Budgeted) override
sk_sp< Sampler > createSampler(const SamplerDesc &) override
void onDeleteBackendTexture(const BackendTexture &) override
sk_sp< MtlGraphicsPipeline > findOrCreateLoadMSAAPipeline(const RenderPassDesc &)
BackendTexture onCreateBackendTexture(SkISize dimensions, const TextureInfo &) override
sk_sp< Texture > createWrappedTexture(const BackendTexture &) override
MtlResourceProvider(SharedContext *sharedContext, SingleOwner *, uint32_t recorderID, size_t resourceBudget)
sk_sp< ComputePipeline > createComputePipeline(const ComputePipelineDesc &) override
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)
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 > >)
const RenderStep * lookup(uint32_t uniqueID) const
const Caps * caps() const
ShaderCodeDictionary * shaderCodeDictionary()
const RendererProvider * rendererProvider() const
VkDevice device
Definition main.cc:53
GAsyncResult * result
FlTexture * texture
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)
Budgeted
Definition GpuTypes.h:35
init(device_serial, adb_binary)
Definition _adb_path.py:12
SkTileMode tileModeX() const
SkSamplingOptions samplingOptions() const
SkTileMode tileModeY() const