1/*
2 * Copyright 2021 Google LLC
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#ifndef skgpu_MtlCommandBuffer_DEFINED
9#define skgpu_MtlCommandBuffer_DEFINED
10
11#include "experimental/graphite/src/CommandBuffer.h"
12#include "experimental/graphite/src/GpuWorkSubmission.h"
13
14#include <memory>
15
16#include "include/core/SkTypes.h"
17#include "include/ports/SkCFObject.h"
18
19#import <Metal/Metal.h>
20
21namespace skgpu::mtl {
22class BlitCommandEncoder;
23class Gpu;
24class RenderCommandEncoder;
25
26class CommandBuffer final : public skgpu::CommandBuffer {
27public:
28    static sk_sp<CommandBuffer> Make(const Gpu*);
29    ~CommandBuffer() override;
30
31    bool isFinished() {
32        return (*fCommandBuffer).status == MTLCommandBufferStatusCompleted ||
33               (*fCommandBuffer).status == MTLCommandBufferStatusError;
34
35    }
36    void waitUntilFinished() {
37        // TODO: it's not clear what do to if status is Enqueued. Commit and then wait?
38        if ((*fCommandBuffer).status == MTLCommandBufferStatusScheduled ||
39            (*fCommandBuffer).status == MTLCommandBufferStatusCommitted) {
40            [(*fCommandBuffer) waitUntilCompleted];
41        }
42        if (!this->isFinished()) {
43            SkDebugf("Unfinished command buffer status: %d\n",
44                     (int)(*fCommandBuffer).status);
45            SkASSERT(false);
46        }
47    }
48    bool commit();
49
50private:
51    CommandBuffer(sk_cfp<id<MTLCommandBuffer>> cmdBuffer, const Gpu* gpu);
52
53    void onBeginRenderPass(const RenderPassDesc&) override;
54    void endRenderPass() override;
55
56    void onBindGraphicsPipeline(const skgpu::GraphicsPipeline*) override;
57    void onBindUniformBuffer(const skgpu::Buffer*, size_t offset) override;
58    void onBindVertexBuffers(const skgpu::Buffer* vertexBuffer, size_t vertexOffset,
59                             const skgpu::Buffer* instanceBuffer, size_t instanceOffset) override;
60    void onBindIndexBuffer(const skgpu::Buffer* indexBuffer, size_t offset) override;
61
62    void onDraw(PrimitiveType type, unsigned int baseVertex, unsigned int vertexCount) override;
63    void onDrawIndexed(PrimitiveType type, unsigned int baseIndex, unsigned int indexCount,
64                       unsigned int baseVertex) override;
65    void onDrawInstanced(PrimitiveType type,
66                         unsigned int baseVertex, unsigned int vertexCount,
67                         unsigned int baseInstance, unsigned int instanceCount) override;
68    void onDrawIndexedInstanced(PrimitiveType type, unsigned int baseIndex,
69                                unsigned int indexCount, unsigned int baseVertex,
70                                unsigned int baseInstance, unsigned int instanceCount) override;
71
72    void onCopyTextureToBuffer(const skgpu::Texture*,
73                               SkIRect srcRect,
74                               const skgpu::Buffer*,
75                               size_t bufferOffset,
76                               size_t bufferRowBytes) override;
77
78    BlitCommandEncoder* getBlitCommandEncoder();
79    void endBlitCommandEncoder();
80
81    sk_cfp<id<MTLCommandBuffer>> fCommandBuffer;
82    sk_sp<RenderCommandEncoder> fActiveRenderCommandEncoder;
83    sk_sp<BlitCommandEncoder> fActiveBlitCommandEncoder;
84
85    size_t fCurrentVertexStride = 0;
86    size_t fCurrentInstanceStride = 0;
87    id<MTLBuffer> fCurrentIndexBuffer;
88    size_t fCurrentIndexBufferOffset = 0;
89
90    const Gpu* fGpu;
91};
92
93} // namespace skgpu::mtl
94
95#endif // skgpu_MtlCommandBuffer_DEFINED
96