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#include "src/gpu/mtl/GrMtlGpu.h" 10#include "src/gpu/mtl/GrMtlGpuCommandBuffer.h" 11#include "src/gpu/mtl/GrMtlPipelineState.h" 12 13#if !__has_feature(objc_arc) 14#error This file must be compiled with Arc. Use -fobjc-arc flag 15#endif 16 17GrMtlCommandBuffer* GrMtlCommandBuffer::Create(id<MTLCommandQueue> queue) { 18 id<MTLCommandBuffer> mtlCommandBuffer; 19 mtlCommandBuffer = [queue commandBuffer]; 20 if (nil == mtlCommandBuffer) { 21 return nullptr; 22 } 23 24 mtlCommandBuffer.label = @"GrMtlCommandBuffer::Create"; 25 26 return new GrMtlCommandBuffer(mtlCommandBuffer); 27} 28 29GrMtlCommandBuffer::~GrMtlCommandBuffer() { 30 this->endAllEncoding(); 31 fCmdBuffer = nil; 32} 33 34id<MTLBlitCommandEncoder> GrMtlCommandBuffer::getBlitCommandEncoder() { 35 if (nil != fActiveRenderCommandEncoder) { 36 [fActiveRenderCommandEncoder endEncoding]; 37 fActiveRenderCommandEncoder = nil; 38 } 39 40 if (nil == fActiveBlitCommandEncoder) { 41 fActiveBlitCommandEncoder = [fCmdBuffer blitCommandEncoder]; 42 } 43 fPreviousRenderPassDescriptor = nil; 44 45 return fActiveBlitCommandEncoder; 46} 47 48static bool compatible(const MTLRenderPassAttachmentDescriptor* first, 49 const MTLRenderPassAttachmentDescriptor* second, 50 const GrMtlPipelineState* pipelineState) { 51 // Check to see if the previous descriptor is compatible with the new one. 52 // They are compatible if: 53 // * they share the same rendertargets 54 // * the first's store actions are either Store or DontCare 55 // * the second's load actions are either Load or DontCare 56 // * the second doesn't sample from any rendertargets in the first 57 bool renderTargetsMatch = (first.texture == second.texture); 58 bool storeActionsValid = first.storeAction == MTLStoreActionStore || 59 first.storeAction == MTLStoreActionDontCare; 60 bool loadActionsValid = second.loadAction == MTLLoadActionLoad || 61 second.loadAction == MTLLoadActionDontCare; 62 bool secondDoesntSampleFirst = (!pipelineState || 63 pipelineState->doesntSampleAttachment(first)) && 64 second.storeAction != MTLStoreActionMultisampleResolve; 65 66 return renderTargetsMatch && 67 (nil == first.texture || 68 (storeActionsValid && loadActionsValid && secondDoesntSampleFirst)); 69} 70 71id<MTLRenderCommandEncoder> GrMtlCommandBuffer::getRenderCommandEncoder( 72 MTLRenderPassDescriptor* descriptor, const GrMtlPipelineState* pipelineState, 73 GrMtlGpuRTCommandBuffer* gpuCommandBuffer) { 74 if (nil != fPreviousRenderPassDescriptor) { 75 if (compatible(fPreviousRenderPassDescriptor.colorAttachments[0], 76 descriptor.colorAttachments[0], pipelineState) && 77 compatible(fPreviousRenderPassDescriptor.stencilAttachment, 78 descriptor.stencilAttachment, pipelineState)) { 79 return fActiveRenderCommandEncoder; 80 } 81 } 82 83 this->endAllEncoding(); 84 fActiveRenderCommandEncoder = [fCmdBuffer renderCommandEncoderWithDescriptor:descriptor]; 85 if (gpuCommandBuffer) { 86 gpuCommandBuffer->initRenderState(fActiveRenderCommandEncoder); 87 } 88 fPreviousRenderPassDescriptor = descriptor; 89 90 return fActiveRenderCommandEncoder; 91} 92 93void GrMtlCommandBuffer::commit(bool waitUntilCompleted) { 94 this->endAllEncoding(); 95 [fCmdBuffer commit]; 96 if (waitUntilCompleted) { 97 [fCmdBuffer waitUntilCompleted]; 98 } 99 100 if (MTLCommandBufferStatusError == fCmdBuffer.status) { 101 NSString* description = fCmdBuffer.error.localizedDescription; 102 const char* errorString = [description UTF8String]; 103 SkDebugf("Error submitting command buffer: %s\n", errorString); 104 } 105 106 fCmdBuffer = nil; 107} 108 109void GrMtlCommandBuffer::endAllEncoding() { 110 if (nil != fActiveRenderCommandEncoder) { 111 [fActiveRenderCommandEncoder endEncoding]; 112 fActiveRenderCommandEncoder = nil; 113 } 114 if (nil != fActiveBlitCommandEncoder) { 115 [fActiveBlitCommandEncoder endEncoding]; 116 fActiveBlitCommandEncoder = nil; 117 } 118} 119