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_graphite_MtlCommandBuffer_DEFINED 9 #define skgpu_graphite_MtlCommandBuffer_DEFINED 10 11 #include "src/gpu/graphite/CommandBuffer.h" 12 #include "src/gpu/graphite/DrawPass.h" 13 #include "src/gpu/graphite/Log.h" 14 15 #include <memory> 16 17 #include "include/core/SkTypes.h" 18 #include "include/ports/SkCFObject.h" 19 20 #ifdef SK_ENABLE_PIET_GPU 21 #include "src/gpu/piet/Render.h" 22 #endif 23 24 #import <Metal/Metal.h> 25 26 namespace skgpu::graphite { 27 class MtlBlitCommandEncoder; 28 class MtlComputeCommandEncoder; 29 class MtlRenderCommandEncoder; 30 class MtlResourceProvider; 31 class MtlSharedContext; 32 33 class MtlCommandBuffer final : public CommandBuffer { 34 public: 35 static std::unique_ptr<MtlCommandBuffer> Make(id<MTLCommandQueue>, 36 const MtlSharedContext*, 37 MtlResourceProvider*); 38 ~MtlCommandBuffer() override; 39 40 bool setNewCommandBufferResources() override; 41 isFinished()42 bool isFinished() { 43 return (*fCommandBuffer).status == MTLCommandBufferStatusCompleted || 44 (*fCommandBuffer).status == MTLCommandBufferStatusError; 45 46 } waitUntilFinished()47 void waitUntilFinished() { 48 // TODO: it's not clear what do to if status is Enqueued. Commit and then wait? 49 if ((*fCommandBuffer).status == MTLCommandBufferStatusScheduled || 50 (*fCommandBuffer).status == MTLCommandBufferStatusCommitted) { 51 [(*fCommandBuffer) waitUntilCompleted]; 52 } 53 if (!this->isFinished()) { 54 SKGPU_LOG_E("Unfinished command buffer status: %d", 55 (int)(*fCommandBuffer).status); 56 SkASSERT(false); 57 } 58 } 59 bool commit(); 60 61 #ifdef SK_ENABLE_PIET_GPU setPietRenderer(const skgpu::piet::MtlRenderer * renderer)62 void setPietRenderer(const skgpu::piet::MtlRenderer* renderer) { fPietRenderer = renderer; } 63 #endif 64 65 private: 66 MtlCommandBuffer(id<MTLCommandQueue>, 67 const MtlSharedContext* sharedContext, 68 MtlResourceProvider* resourceProvider); 69 70 bool createNewMTLCommandBuffer(); 71 72 void onResetCommandBuffer() override; 73 74 bool onAddRenderPass(const RenderPassDesc&, 75 const Texture* colorTexture, 76 const Texture* resolveTexture, 77 const Texture* depthStencilTexture, 78 SkRect viewport, 79 const std::vector<std::unique_ptr<DrawPass>>& drawPasses) override; 80 bool onAddComputePass(const ComputePassDesc&, 81 const ComputePipeline*, 82 const std::vector<ResourceBinding>& bindings) override; 83 84 // Methods for populating a MTLRenderCommandEncoder: 85 bool beginRenderPass(const RenderPassDesc&, 86 const Texture* colorTexture, 87 const Texture* resolveTexture, 88 const Texture* depthStencilTexture); 89 void endRenderPass(); 90 91 void addDrawPass(const DrawPass*); 92 93 void bindGraphicsPipeline(const GraphicsPipeline*); 94 void setBlendConstants(float* blendConstants); 95 96 void bindUniformBuffer(const BindBufferInfo& info, UniformSlot); 97 void bindDrawBuffers(const BindBufferInfo& vertices, 98 const BindBufferInfo& instances, 99 const BindBufferInfo& indices, 100 const BindBufferInfo& indirect); 101 void bindVertexBuffers(const Buffer* vertexBuffer, size_t vertexOffset, 102 const Buffer* instanceBuffer, size_t instanceOffset); 103 void bindIndexBuffer(const Buffer* indexBuffer, size_t offset); 104 void bindIndirectBuffer(const Buffer* indirectBuffer, size_t offset); 105 106 void bindTextureAndSampler(const Texture*, const Sampler*, unsigned int bindIndex); 107 108 void setScissor(unsigned int left, unsigned int top, 109 unsigned int width, unsigned int height); 110 void setViewport(float x, float y, float width, float height, 111 float minDepth, float maxDepth); 112 113 void draw(PrimitiveType type, unsigned int baseVertex, unsigned int vertexCount); 114 void drawIndexed(PrimitiveType type, unsigned int baseIndex, unsigned int indexCount, 115 unsigned int baseVertex); 116 void drawInstanced(PrimitiveType type, 117 unsigned int baseVertex, unsigned int vertexCount, 118 unsigned int baseInstance, unsigned int instanceCount); 119 void drawIndexedInstanced(PrimitiveType type, unsigned int baseIndex, 120 unsigned int indexCount, unsigned int baseVertex, 121 unsigned int baseInstance, unsigned int instanceCount); 122 void drawIndirect(PrimitiveType type); 123 void drawIndexedIndirect(PrimitiveType type); 124 125 // Methods for populating a MTLComputeCommandEncoder: 126 void beginComputePass(); 127 void bindComputePipeline(const ComputePipeline*); 128 void bindBuffer(const Buffer* buffer, unsigned int offset, unsigned int index); 129 void dispatchThreadgroups(const WorkgroupSize& globalSize, const WorkgroupSize& localSize); 130 void endComputePass(); 131 132 // Methods for populating a MTLBlitCommandEncoder: 133 bool onCopyBufferToBuffer(const Buffer* srcBuffer, 134 size_t srcOffset, 135 const Buffer* dstBuffer, 136 size_t dstOffset, 137 size_t size) override; 138 bool onCopyTextureToBuffer(const Texture*, 139 SkIRect srcRect, 140 const Buffer*, 141 size_t bufferOffset, 142 size_t bufferRowBytes) override; 143 bool onCopyBufferToTexture(const Buffer*, 144 const Texture*, 145 const BufferTextureCopyData* copyData, 146 int count) override; 147 bool onCopyTextureToTexture(const Texture* src, 148 SkIRect srcRect, 149 const Texture* dst, 150 SkIPoint dstPoint) override; 151 bool onSynchronizeBufferToCpu(const Buffer*, bool* outDidResultInWork) override; 152 bool onClearBuffer(const Buffer*, size_t offset, size_t size) override; 153 154 #ifdef SK_ENABLE_PIET_GPU 155 void onRenderPietScene(const skgpu::piet::Scene& scene, const Texture* target) override; 156 #endif 157 158 MtlBlitCommandEncoder* getBlitCommandEncoder(); 159 void endBlitCommandEncoder(); 160 161 sk_cfp<id<MTLCommandBuffer>> fCommandBuffer; 162 sk_sp<MtlRenderCommandEncoder> fActiveRenderCommandEncoder; 163 sk_sp<MtlComputeCommandEncoder> fActiveComputeCommandEncoder; 164 sk_sp<MtlBlitCommandEncoder> fActiveBlitCommandEncoder; 165 166 id<MTLBuffer> fCurrentIndexBuffer; 167 id<MTLBuffer> fCurrentIndirectBuffer; 168 size_t fCurrentIndexBufferOffset = 0; 169 size_t fCurrentIndirectBufferOffset = 0; 170 171 // The command buffer will outlive the MtlQueueManager which owns the MTLCommandQueue. 172 id<MTLCommandQueue> fQueue; 173 const MtlSharedContext* fSharedContext; 174 MtlResourceProvider* fResourceProvider; 175 176 // If true, the draw commands being added are entirely offscreen and can be skipped. 177 // This can happen if a recording is being replayed with a transform that moves the recorded 178 // commands outside of the render target bounds. 179 bool fDrawIsOffscreen = false; 180 181 #ifdef SK_ENABLE_PIET_GPU 182 const skgpu::piet::MtlRenderer* fPietRenderer = nullptr; // owned by MtlQueueManager 183 #endif 184 }; 185 186 } // namespace skgpu::graphite 187 188 #endif // skgpu_graphite_MtlCommandBuffer_DEFINED 189