1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2019 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlCommandBuffer.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h" 11cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlGpu.h" 12cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlOpsRenderPass.h" 13cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlPipelineState.h" 14cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlRenderCommandEncoder.h" 15cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlSemaphore.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci#if !__has_feature(objc_arc) 18cb93a386Sopenharmony_ci#error This file must be compiled with Arc. Use -fobjc-arc flag 19cb93a386Sopenharmony_ci#endif 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ciGR_NORETAIN_BEGIN 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_cisk_sp<GrMtlCommandBuffer> GrMtlCommandBuffer::Make(id<MTLCommandQueue> queue) { 24cb93a386Sopenharmony_ci id<MTLCommandBuffer> mtlCommandBuffer; 25cb93a386Sopenharmony_ci mtlCommandBuffer = [queue commandBuffer]; 26cb93a386Sopenharmony_ci if (nil == mtlCommandBuffer) { 27cb93a386Sopenharmony_ci return nullptr; 28cb93a386Sopenharmony_ci } 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO 31cb93a386Sopenharmony_ci mtlCommandBuffer.label = @"GrMtlCommandBuffer::Make"; 32cb93a386Sopenharmony_ci#endif 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci return sk_sp<GrMtlCommandBuffer>(new GrMtlCommandBuffer(mtlCommandBuffer)); 35cb93a386Sopenharmony_ci} 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ciGrMtlCommandBuffer::~GrMtlCommandBuffer() { 38cb93a386Sopenharmony_ci this->endAllEncoding(); 39cb93a386Sopenharmony_ci this->releaseResources(); 40cb93a386Sopenharmony_ci this->callFinishedCallbacks(); 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci fCmdBuffer = nil; 43cb93a386Sopenharmony_ci} 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_civoid GrMtlCommandBuffer::releaseResources() { 46cb93a386Sopenharmony_ci TRACE_EVENT0("skia.gpu", TRACE_FUNC); 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci fTrackedResources.reset(); 49cb93a386Sopenharmony_ci fTrackedGrBuffers.reset(); 50cb93a386Sopenharmony_ci fTrackedGrSurfaces.reset(); 51cb93a386Sopenharmony_ci} 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ciid<MTLBlitCommandEncoder> GrMtlCommandBuffer::getBlitCommandEncoder() { 54cb93a386Sopenharmony_ci if (fActiveBlitCommandEncoder) { 55cb93a386Sopenharmony_ci return fActiveBlitCommandEncoder; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci this->endAllEncoding(); 59cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_IOS 60cb93a386Sopenharmony_ci if (GrMtlIsAppInBackground()) { 61cb93a386Sopenharmony_ci fActiveBlitCommandEncoder = nil; 62cb93a386Sopenharmony_ci NSLog(@"GrMtlCommandBuffer: tried to create MTLBlitCommandEncoder while in background."); 63cb93a386Sopenharmony_ci return nil; 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci#endif 66cb93a386Sopenharmony_ci fActiveBlitCommandEncoder = [fCmdBuffer blitCommandEncoder]; 67cb93a386Sopenharmony_ci fHasWork = true; 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci return fActiveBlitCommandEncoder; 70cb93a386Sopenharmony_ci} 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_cistatic bool compatible(const MTLRenderPassAttachmentDescriptor* first, 73cb93a386Sopenharmony_ci const MTLRenderPassAttachmentDescriptor* second, 74cb93a386Sopenharmony_ci const GrMtlPipelineState* pipelineState) { 75cb93a386Sopenharmony_ci // From the Metal Best Practices Guide: 76cb93a386Sopenharmony_ci // Check to see if the previous descriptor is compatible with the new one. 77cb93a386Sopenharmony_ci // They are compatible if: 78cb93a386Sopenharmony_ci // * they share the same rendertargets 79cb93a386Sopenharmony_ci // * the first's store actions are either Store or DontCare 80cb93a386Sopenharmony_ci // * the second's load actions are either Load or DontCare 81cb93a386Sopenharmony_ci // * the second doesn't sample from any rendertargets in the first 82cb93a386Sopenharmony_ci bool renderTargetsMatch = (first.texture == second.texture); 83cb93a386Sopenharmony_ci bool storeActionsValid = first.storeAction == MTLStoreActionStore || 84cb93a386Sopenharmony_ci first.storeAction == MTLStoreActionDontCare; 85cb93a386Sopenharmony_ci bool loadActionsValid = second.loadAction == MTLLoadActionLoad || 86cb93a386Sopenharmony_ci second.loadAction == MTLLoadActionDontCare; 87cb93a386Sopenharmony_ci bool secondDoesntSampleFirst = (!pipelineState || 88cb93a386Sopenharmony_ci pipelineState->doesntSampleAttachment(first)); 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci // Since we are trying to use the same encoder rather than merging two, 91cb93a386Sopenharmony_ci // we have to check to see if both store actions are mutually compatible. 92cb93a386Sopenharmony_ci bool secondStoreValid = true; 93cb93a386Sopenharmony_ci if (second.storeAction == MTLStoreActionDontCare) { 94cb93a386Sopenharmony_ci secondStoreValid = (first.storeAction == MTLStoreActionDontCare); 95cb93a386Sopenharmony_ci // TODO: if first.storeAction is Store and second.loadAction is Load, 96cb93a386Sopenharmony_ci // we could reset the active RenderCommandEncoder's store action to DontCare 97cb93a386Sopenharmony_ci } else if (second.storeAction == MTLStoreActionStore) { 98cb93a386Sopenharmony_ci if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) { 99cb93a386Sopenharmony_ci secondStoreValid = (first.storeAction == MTLStoreActionStore || 100cb93a386Sopenharmony_ci first.storeAction == MTLStoreActionStoreAndMultisampleResolve); 101cb93a386Sopenharmony_ci } else { 102cb93a386Sopenharmony_ci secondStoreValid = (first.storeAction == MTLStoreActionStore); 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci // TODO: if the first store action is DontCare we could reset the active 105cb93a386Sopenharmony_ci // RenderCommandEncoder's store action to Store, but it's not clear if it's worth it. 106cb93a386Sopenharmony_ci } else if (second.storeAction == MTLStoreActionMultisampleResolve) { 107cb93a386Sopenharmony_ci if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) { 108cb93a386Sopenharmony_ci secondStoreValid = (first.resolveTexture == second.resolveTexture) && 109cb93a386Sopenharmony_ci (first.storeAction == MTLStoreActionMultisampleResolve || 110cb93a386Sopenharmony_ci first.storeAction == MTLStoreActionStoreAndMultisampleResolve); 111cb93a386Sopenharmony_ci } else { 112cb93a386Sopenharmony_ci secondStoreValid = (first.resolveTexture == second.resolveTexture) && 113cb93a386Sopenharmony_ci (first.storeAction == MTLStoreActionMultisampleResolve); 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci // When we first check whether store actions are valid we don't consider resolves, 116cb93a386Sopenharmony_ci // so we need to reset that here. 117cb93a386Sopenharmony_ci storeActionsValid = secondStoreValid; 118cb93a386Sopenharmony_ci } else { 119cb93a386Sopenharmony_ci if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, *)) { 120cb93a386Sopenharmony_ci if (second.storeAction == MTLStoreActionStoreAndMultisampleResolve) { 121cb93a386Sopenharmony_ci secondStoreValid = (first.resolveTexture == second.resolveTexture) && 122cb93a386Sopenharmony_ci (first.storeAction == MTLStoreActionStoreAndMultisampleResolve); 123cb93a386Sopenharmony_ci // TODO: if the first store action is simply MultisampleResolve we could reset 124cb93a386Sopenharmony_ci // the active RenderCommandEncoder's store action to StoreAndMultisampleResolve, 125cb93a386Sopenharmony_ci // but it's not clear if it's worth it. 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci // When we first check whether store actions are valid we don't consider resolves, 128cb93a386Sopenharmony_ci // so we need to reset that here. 129cb93a386Sopenharmony_ci storeActionsValid = secondStoreValid; 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci return renderTargetsMatch && 135cb93a386Sopenharmony_ci (nil == first.texture || 136cb93a386Sopenharmony_ci (storeActionsValid && loadActionsValid && secondDoesntSampleFirst && secondStoreValid)); 137cb93a386Sopenharmony_ci} 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ciGrMtlRenderCommandEncoder* GrMtlCommandBuffer::getRenderCommandEncoder( 140cb93a386Sopenharmony_ci MTLRenderPassDescriptor* descriptor, const GrMtlPipelineState* pipelineState, 141cb93a386Sopenharmony_ci GrMtlOpsRenderPass* opsRenderPass) { 142cb93a386Sopenharmony_ci if (nil != fPreviousRenderPassDescriptor) { 143cb93a386Sopenharmony_ci if (compatible(fPreviousRenderPassDescriptor.colorAttachments[0], 144cb93a386Sopenharmony_ci descriptor.colorAttachments[0], pipelineState) && 145cb93a386Sopenharmony_ci compatible(fPreviousRenderPassDescriptor.stencilAttachment, 146cb93a386Sopenharmony_ci descriptor.stencilAttachment, pipelineState)) { 147cb93a386Sopenharmony_ci return fActiveRenderCommandEncoder.get(); 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci return this->getRenderCommandEncoder(descriptor, opsRenderPass); 152cb93a386Sopenharmony_ci} 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_ciGrMtlRenderCommandEncoder* GrMtlCommandBuffer::getRenderCommandEncoder( 155cb93a386Sopenharmony_ci MTLRenderPassDescriptor* descriptor, 156cb93a386Sopenharmony_ci GrMtlOpsRenderPass* opsRenderPass) { 157cb93a386Sopenharmony_ci this->endAllEncoding(); 158cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_IOS 159cb93a386Sopenharmony_ci if (GrMtlIsAppInBackground()) { 160cb93a386Sopenharmony_ci fActiveRenderCommandEncoder = nullptr; 161cb93a386Sopenharmony_ci NSLog(@"GrMtlCommandBuffer: tried to create MTLRenderCommandEncoder while in background."); 162cb93a386Sopenharmony_ci return nullptr; 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci#endif 165cb93a386Sopenharmony_ci fActiveRenderCommandEncoder = GrMtlRenderCommandEncoder::Make( 166cb93a386Sopenharmony_ci [fCmdBuffer renderCommandEncoderWithDescriptor:descriptor]); 167cb93a386Sopenharmony_ci if (opsRenderPass) { 168cb93a386Sopenharmony_ci opsRenderPass->initRenderState(fActiveRenderCommandEncoder.get()); 169cb93a386Sopenharmony_ci } 170cb93a386Sopenharmony_ci fPreviousRenderPassDescriptor = descriptor; 171cb93a386Sopenharmony_ci fHasWork = true; 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci return fActiveRenderCommandEncoder.get(); 174cb93a386Sopenharmony_ci} 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_cibool GrMtlCommandBuffer::commit(bool waitUntilCompleted) { 177cb93a386Sopenharmony_ci this->endAllEncoding(); 178cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_IOS 179cb93a386Sopenharmony_ci if (GrMtlIsAppInBackground()) { 180cb93a386Sopenharmony_ci NSLog(@"GrMtlCommandBuffer: Tried to commit command buffer while in background.\n"); 181cb93a386Sopenharmony_ci return false; 182cb93a386Sopenharmony_ci } 183cb93a386Sopenharmony_ci#endif 184cb93a386Sopenharmony_ci [fCmdBuffer commit]; 185cb93a386Sopenharmony_ci if (waitUntilCompleted) { 186cb93a386Sopenharmony_ci this->waitUntilCompleted(); 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci if (fCmdBuffer.status == MTLCommandBufferStatusError) { 190cb93a386Sopenharmony_ci NSString* description = fCmdBuffer.error.localizedDescription; 191cb93a386Sopenharmony_ci const char* errorString = [description UTF8String]; 192cb93a386Sopenharmony_ci SkDebugf("Error submitting command buffer: %s\n", errorString); 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci return (fCmdBuffer.status != MTLCommandBufferStatusError); 196cb93a386Sopenharmony_ci} 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_civoid GrMtlCommandBuffer::endAllEncoding() { 199cb93a386Sopenharmony_ci if (fActiveRenderCommandEncoder) { 200cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->endEncoding(); 201cb93a386Sopenharmony_ci fActiveRenderCommandEncoder.reset(); 202cb93a386Sopenharmony_ci fPreviousRenderPassDescriptor = nil; 203cb93a386Sopenharmony_ci } 204cb93a386Sopenharmony_ci if (fActiveBlitCommandEncoder) { 205cb93a386Sopenharmony_ci [fActiveBlitCommandEncoder endEncoding]; 206cb93a386Sopenharmony_ci fActiveBlitCommandEncoder = nil; 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci} 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_civoid GrMtlCommandBuffer::encodeSignalEvent(sk_sp<GrMtlEvent> event, uint64_t eventValue) { 211cb93a386Sopenharmony_ci SkASSERT(fCmdBuffer); 212cb93a386Sopenharmony_ci this->endAllEncoding(); // ensure we don't have any active command encoders 213cb93a386Sopenharmony_ci if (@available(macOS 10.14, iOS 12.0, *)) { 214cb93a386Sopenharmony_ci [fCmdBuffer encodeSignalEvent:event->mtlEvent() value:eventValue]; 215cb93a386Sopenharmony_ci this->addResource(std::move(event)); 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci fHasWork = true; 218cb93a386Sopenharmony_ci} 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_civoid GrMtlCommandBuffer::encodeWaitForEvent(sk_sp<GrMtlEvent> event, uint64_t eventValue) { 221cb93a386Sopenharmony_ci SkASSERT(fCmdBuffer); 222cb93a386Sopenharmony_ci this->endAllEncoding(); // ensure we don't have any active command encoders 223cb93a386Sopenharmony_ci // TODO: not sure if needed but probably 224cb93a386Sopenharmony_ci if (@available(macOS 10.14, iOS 12.0, *)) { 225cb93a386Sopenharmony_ci [fCmdBuffer encodeWaitForEvent:event->mtlEvent() value:eventValue]; 226cb93a386Sopenharmony_ci this->addResource(std::move(event)); 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci fHasWork = true; 229cb93a386Sopenharmony_ci} 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ciGR_NORETAIN_END 232