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 8#include "src/gpu/mtl/GrMtlCommandBuffer.h" 9 10#include "src/gpu/mtl/GrMtlGpu.h" 11#include "src/gpu/mtl/GrMtlOpsRenderPass.h" 12#include "src/gpu/mtl/GrMtlPipelineState.h" 13 14#if !__has_feature(objc_arc) 15#error This file must be compiled with Arc. Use -fobjc-arc flag 16#endif 17 18GR_NORETAIN_BEGIN 19 20sk_sp<GrMtlCommandBuffer> GrMtlCommandBuffer::Make(id<MTLCommandQueue> queue) { 21 id<MTLCommandBuffer> mtlCommandBuffer; 22 mtlCommandBuffer = [queue commandBuffer]; 23 if (nil == mtlCommandBuffer) { 24 return nullptr; 25 } 26 27 mtlCommandBuffer.label = @"GrMtlCommandBuffer::Create"; 28 29 return sk_sp<GrMtlCommandBuffer>(new GrMtlCommandBuffer(mtlCommandBuffer)); 30} 31 32GrMtlCommandBuffer::~GrMtlCommandBuffer() { 33 this->endAllEncoding(); 34 fTrackedGrBuffers.reset(); 35 this->callFinishedCallbacks(); 36 37 fCmdBuffer = nil; 38} 39 40id<MTLBlitCommandEncoder> GrMtlCommandBuffer::getBlitCommandEncoder() { 41 if (fActiveBlitCommandEncoder) { 42 return fActiveBlitCommandEncoder; 43 } 44 45 this->endAllEncoding(); 46 fActiveBlitCommandEncoder = [fCmdBuffer blitCommandEncoder]; 47 fHasWork = true; 48 49 return fActiveBlitCommandEncoder; 50} 51 52static bool compatible(const MTLRenderPassAttachmentDescriptor* first, 53 const MTLRenderPassAttachmentDescriptor* second, 54 const GrMtlPipelineState* pipelineState) { 55 // Check to see if the previous descriptor is compatible with the new one. 56 // They are compatible if: 57 // * they share the same rendertargets 58 // * the first's store actions are either Store or DontCare 59 // * the second's load actions are either Load or DontCare 60 // * the second doesn't sample from any rendertargets in the first 61 bool renderTargetsMatch = (first.texture == second.texture); 62 bool storeActionsValid = first.storeAction == MTLStoreActionStore || 63 first.storeAction == MTLStoreActionDontCare; 64 bool loadActionsValid = second.loadAction == MTLLoadActionLoad || 65 second.loadAction == MTLLoadActionDontCare; 66 bool secondDoesntSampleFirst = (!pipelineState || 67 pipelineState->doesntSampleAttachment(first)) && 68 second.storeAction != MTLStoreActionMultisampleResolve; 69 70 return renderTargetsMatch && 71 (nil == first.texture || 72 (storeActionsValid && loadActionsValid && secondDoesntSampleFirst)); 73} 74 75id<MTLRenderCommandEncoder> GrMtlCommandBuffer::getRenderCommandEncoder( 76 MTLRenderPassDescriptor* descriptor, const GrMtlPipelineState* pipelineState, 77 GrMtlOpsRenderPass* opsRenderPass) { 78 if (nil != fPreviousRenderPassDescriptor) { 79 if (compatible(fPreviousRenderPassDescriptor.colorAttachments[0], 80 descriptor.colorAttachments[0], pipelineState) && 81 compatible(fPreviousRenderPassDescriptor.stencilAttachment, 82 descriptor.stencilAttachment, pipelineState)) { 83 return fActiveRenderCommandEncoder; 84 } 85 } 86 87 this->endAllEncoding(); 88 fActiveRenderCommandEncoder = [fCmdBuffer renderCommandEncoderWithDescriptor:descriptor]; 89 if (opsRenderPass) { 90 opsRenderPass->initRenderState(fActiveRenderCommandEncoder); 91 } 92 fPreviousRenderPassDescriptor = descriptor; 93 fHasWork = true; 94 95 return fActiveRenderCommandEncoder; 96} 97 98bool GrMtlCommandBuffer::commit(bool waitUntilCompleted) { 99 this->endAllEncoding(); 100 [fCmdBuffer commit]; 101 if (waitUntilCompleted) { 102 this->waitUntilCompleted(); 103 } 104 105 if (fCmdBuffer.status == MTLCommandBufferStatusError) { 106 NSString* description = fCmdBuffer.error.localizedDescription; 107 const char* errorString = [description UTF8String]; 108 SkDebugf("Error submitting command buffer: %s\n", errorString); 109 } 110 111 return (fCmdBuffer.status != MTLCommandBufferStatusError); 112} 113 114void GrMtlCommandBuffer::endAllEncoding() { 115 if (fActiveRenderCommandEncoder) { 116 [fActiveRenderCommandEncoder endEncoding]; 117 fActiveRenderCommandEncoder = nil; 118 fPreviousRenderPassDescriptor = nil; 119 } 120 if (fActiveBlitCommandEncoder) { 121 [fActiveBlitCommandEncoder endEncoding]; 122 fActiveBlitCommandEncoder = nil; 123 } 124} 125 126void GrMtlCommandBuffer::encodeSignalEvent(id<MTLEvent> event, uint64_t eventValue) { 127 SkASSERT(fCmdBuffer); 128 this->endAllEncoding(); // ensure we don't have any active command encoders 129 if (@available(macOS 10.14, iOS 12.0, *)) { 130 [fCmdBuffer encodeSignalEvent:event value:eventValue]; 131 } 132 fHasWork = true; 133} 134 135void GrMtlCommandBuffer::encodeWaitForEvent(id<MTLEvent> event, uint64_t eventValue) { 136 SkASSERT(fCmdBuffer); 137 this->endAllEncoding(); // ensure we don't have any active command encoders 138 // TODO: not sure if needed but probably 139 if (@available(macOS 10.14, iOS 12.0, *)) { 140 [fCmdBuffer encodeWaitForEvent:event value:eventValue]; 141 } 142 fHasWork = true; 143} 144 145GR_NORETAIN_END 146