• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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