Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrMtlCommandBuffer.mm
Go to the documentation of this file.
1/*
2 * Copyright 2019 Google Inc.
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
17
18#if !__has_feature(objc_arc)
19#error This file must be compiled with Arc. Use -fobjc-arc flag
20#endif
21
22GR_NORETAIN_BEGIN
23
25 id<MTLCommandBuffer> mtlCommandBuffer;
26#if GR_METAL_SDK_VERSION >= 230
27 if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
28 MTLCommandBufferDescriptor* desc = [[MTLCommandBufferDescriptor alloc] init];
29 desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
30 mtlCommandBuffer = [queue commandBufferWithDescriptor:desc];
31 } else {
32 mtlCommandBuffer = [queue commandBuffer];
33 }
34#else
35 mtlCommandBuffer = [queue commandBuffer];
36#endif
37 if (nil == mtlCommandBuffer) {
38 return nullptr;
39 }
40
41#ifdef SK_ENABLE_MTL_DEBUG_INFO
42 mtlCommandBuffer.label = @"GrMtlCommandBuffer::Make";
43#endif
44
45 return sk_sp<GrMtlCommandBuffer>(new GrMtlCommandBuffer(mtlCommandBuffer));
46}
47
49 this->endAllEncoding();
50 this->releaseResources();
52
53 fCmdBuffer = nil;
54}
55
57 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
58
59 fTrackedResources.clear();
60 fTrackedGrBuffers.clear();
61 fTrackedGrSurfaces.clear();
62}
63
64id<MTLBlitCommandEncoder> GrMtlCommandBuffer::getBlitCommandEncoder() {
65 if (fActiveBlitCommandEncoder) {
66 return fActiveBlitCommandEncoder;
67 }
68
69 this->endAllEncoding();
70 if (fCmdBuffer.status != MTLCommandBufferStatusNotEnqueued) {
71 NSLog(@"GrMtlCommandBuffer: tried to create MTLBlitCommandEncoder while in invalid state.");
72 return nullptr;
73 }
74 fActiveBlitCommandEncoder = [fCmdBuffer blitCommandEncoder];
75 fHasWork = true;
76
77 return fActiveBlitCommandEncoder;
78}
79
80static bool compatible(const MTLRenderPassAttachmentDescriptor* first,
81 const MTLRenderPassAttachmentDescriptor* second,
82 const GrMtlPipelineState* pipelineState) {
83 // From the Metal Best Practices Guide:
84 // Check to see if the previous descriptor is compatible with the new one.
85 // They are compatible if:
86 // * they share the same rendertargets
87 // * the first's store actions are either Store or DontCare
88 // * the second's load actions are either Load or DontCare
89 // * the second doesn't sample from any rendertargets in the first
90 bool renderTargetsMatch = (first.texture == second.texture);
91 bool storeActionsValid = first.storeAction == MTLStoreActionStore ||
92 first.storeAction == MTLStoreActionDontCare;
93 bool loadActionsValid = second.loadAction == MTLLoadActionLoad ||
94 second.loadAction == MTLLoadActionDontCare;
95 bool secondDoesntSampleFirst = (!pipelineState ||
96 pipelineState->doesntSampleAttachment(first));
97
98 // Since we are trying to use the same encoder rather than merging two,
99 // we have to check to see if both store actions are mutually compatible.
100 bool secondStoreValid = true;
101 if (second.storeAction == MTLStoreActionDontCare) {
102 secondStoreValid = (first.storeAction == MTLStoreActionDontCare);
103 // TODO: if first.storeAction is Store and second.loadAction is Load,
104 // we could reset the active RenderCommandEncoder's store action to DontCare
105 } else if (second.storeAction == MTLStoreActionStore) {
106 if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) {
107 secondStoreValid = (first.storeAction == MTLStoreActionStore ||
108 first.storeAction == MTLStoreActionStoreAndMultisampleResolve);
109 } else {
110 secondStoreValid = (first.storeAction == MTLStoreActionStore);
111 }
112 // TODO: if the first store action is DontCare we could reset the active
113 // RenderCommandEncoder's store action to Store, but it's not clear if it's worth it.
114 } else if (second.storeAction == MTLStoreActionMultisampleResolve) {
115 if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) {
116 secondStoreValid = (first.resolveTexture == second.resolveTexture) &&
117 (first.storeAction == MTLStoreActionMultisampleResolve ||
118 first.storeAction == MTLStoreActionStoreAndMultisampleResolve);
119 } else {
120 secondStoreValid = (first.resolveTexture == second.resolveTexture) &&
121 (first.storeAction == MTLStoreActionMultisampleResolve);
122 }
123 // When we first check whether store actions are valid we don't consider resolves,
124 // so we need to reset that here.
125 storeActionsValid = secondStoreValid;
126 } else {
127 if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) {
128 if (second.storeAction == MTLStoreActionStoreAndMultisampleResolve) {
129 secondStoreValid = (first.resolveTexture == second.resolveTexture) &&
130 (first.storeAction == MTLStoreActionStoreAndMultisampleResolve);
131 // TODO: if the first store action is simply MultisampleResolve we could reset
132 // the active RenderCommandEncoder's store action to StoreAndMultisampleResolve,
133 // but it's not clear if it's worth it.
134
135 // When we first check whether store actions are valid we don't consider resolves,
136 // so we need to reset that here.
137 storeActionsValid = secondStoreValid;
138 }
139 }
140 }
141
142 return renderTargetsMatch &&
143 (nil == first.texture ||
144 (storeActionsValid && loadActionsValid && secondDoesntSampleFirst && secondStoreValid));
145}
146
148 MTLRenderPassDescriptor* descriptor, const GrMtlPipelineState* pipelineState,
149 GrMtlOpsRenderPass* opsRenderPass) {
150 if (nil != fPreviousRenderPassDescriptor) {
151 if (compatible(fPreviousRenderPassDescriptor.colorAttachments[0],
152 descriptor.colorAttachments[0], pipelineState) &&
153 compatible(fPreviousRenderPassDescriptor.stencilAttachment,
154 descriptor.stencilAttachment, pipelineState)) {
155 return fActiveRenderCommandEncoder.get();
156 }
157 }
158
159 return this->getRenderCommandEncoder(descriptor, opsRenderPass);
160}
161
163 MTLRenderPassDescriptor* descriptor,
164 GrMtlOpsRenderPass* opsRenderPass) {
165 this->endAllEncoding();
166 if (fCmdBuffer.status != MTLCommandBufferStatusNotEnqueued) {
167 NSLog(@"GrMtlCommandBuffer: tried to create MTLRenderCommandEncoder while in bad state.");
168 return nullptr;
169 }
170 fActiveRenderCommandEncoder = GrMtlRenderCommandEncoder::Make(
171 [fCmdBuffer renderCommandEncoderWithDescriptor:descriptor]);
172 if (opsRenderPass) {
173 opsRenderPass->initRenderState(fActiveRenderCommandEncoder.get());
174 }
175 fPreviousRenderPassDescriptor = descriptor;
176 fHasWork = true;
177
178 return fActiveRenderCommandEncoder.get();
179}
180
181bool GrMtlCommandBuffer::commit(bool waitUntilCompleted) {
182 this->endAllEncoding();
183 if ([fCmdBuffer status] != MTLCommandBufferStatusNotEnqueued) {
184 NSLog(@"GrMtlCommandBuffer: Tried to commit command buffer while in invalid state.\n");
185 return false;
186 }
187 [fCmdBuffer commit];
188 if (waitUntilCompleted) {
189 this->waitUntilCompleted();
190#if defined(SK_BUILD_FOR_IOS) && defined(SK_METAL_WAIT_UNTIL_SCHEDULED)
191 // If iOS goes into the background we need to make sure all command buffers are scheduled first.
192 // We don't have a way of detecting background transition so this guarantees it.
193 } else {
194 [fCmdBuffer waitUntilScheduled];
195#endif
196 }
197
198 if ([fCmdBuffer status] == MTLCommandBufferStatusError) {
199 SkDebugf("Error submitting command buffer.\n");
200 if (NSError* error = [fCmdBuffer error]) {
201 NSLog(@"%@", error);
202 }
203 }
204
205 return ([fCmdBuffer status] != MTLCommandBufferStatusError);
206}
207
208void GrMtlCommandBuffer::endAllEncoding() {
209 if (fActiveRenderCommandEncoder) {
210 fActiveRenderCommandEncoder->endEncoding();
211 fActiveRenderCommandEncoder.reset();
212 fPreviousRenderPassDescriptor = nil;
213 }
214 if (fActiveBlitCommandEncoder) {
215 [fActiveBlitCommandEncoder endEncoding];
216 fActiveBlitCommandEncoder = nil;
217 }
218}
219
221 SkASSERT(fCmdBuffer);
222 this->endAllEncoding(); // ensure we don't have any active command encoders
223 if (@available(macOS 10.14, iOS 12.0, tvOS 12.0, *)) {
224 [fCmdBuffer encodeSignalEvent:event->mtlEvent() value:eventValue];
225 this->addResource(std::move(event));
226 }
227 fHasWork = true;
228}
229
231 SkASSERT(fCmdBuffer);
232 this->endAllEncoding(); // ensure we don't have any active command encoders
233 // TODO: not sure if needed but probably
234 if (@available(macOS 10.14, iOS 12.0, tvOS 12.0, *)) {
235 [fCmdBuffer encodeWaitForEvent:event->mtlEvent() value:eventValue];
236 this->addResource(std::move(event));
237 }
238 fHasWork = true;
239}
240
241GR_NORETAIN_END
static bool compatible(const MTLRenderPassAttachmentDescriptor *first, const MTLRenderPassAttachmentDescriptor *second, const GrMtlPipelineState *pipelineState)
#define SkASSERT(cond)
Definition SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define TRACE_FUNC
GrMtlRenderCommandEncoder * getRenderCommandEncoder(MTLRenderPassDescriptor *, const GrMtlPipelineState *, GrMtlOpsRenderPass *opsRenderPass)
void addResource(const sk_sp< const GrManagedResource > &resource)
id< MTLBlitCommandEncoder > getBlitCommandEncoder()
void encodeWaitForEvent(sk_sp< GrMtlEvent >, uint64_t value)
static sk_sp< GrMtlCommandBuffer > Make(id< MTLCommandQueue > queue)
bool commit(bool waitUntilCompleted)
void encodeSignalEvent(sk_sp< GrMtlEvent >, uint64_t value)
void initRenderState(GrMtlRenderCommandEncoder *)
bool doesntSampleAttachment(const MTLRenderPassAttachmentDescriptor *) const
static std::unique_ptr< GrMtlRenderCommandEncoder > Make(id< MTLRenderCommandEncoder > encoder)
VkQueue queue
Definition main.cc:55
FlKeyEvent * event
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
#define TRACE_EVENT0(category_group, name)