1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlCommandBuffer.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "experimental/graphite/src/TextureProxy.h" 11cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlBlitCommandEncoder.h" 12cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlBuffer.h" 13cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlCaps.h" 14cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlGpu.h" 15cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlGraphicsPipeline.h" 16cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlRenderCommandEncoder.h" 17cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlTexture.h" 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cinamespace skgpu::mtl { 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_cisk_sp<CommandBuffer> CommandBuffer::Make(const Gpu* gpu) { 22cb93a386Sopenharmony_ci sk_cfp<id<MTLCommandBuffer>> cmdBuffer; 23cb93a386Sopenharmony_ci id<MTLCommandQueue> queue = gpu->queue(); 24cb93a386Sopenharmony_ci if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { 25cb93a386Sopenharmony_ci sk_cfp<MTLCommandBufferDescriptor*> desc([[MTLCommandBufferDescriptor alloc] init]); 26cb93a386Sopenharmony_ci (*desc).retainedReferences = NO; 27cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO 28cb93a386Sopenharmony_ci (*desc).errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus; 29cb93a386Sopenharmony_ci#endif 30cb93a386Sopenharmony_ci // We add a retain here because the command buffer is set to autorelease (not alloc or copy) 31cb93a386Sopenharmony_ci cmdBuffer.reset([[queue commandBufferWithDescriptor:desc.get()] retain]); 32cb93a386Sopenharmony_ci } else { 33cb93a386Sopenharmony_ci // We add a retain here because the command buffer is set to autorelease (not alloc or copy) 34cb93a386Sopenharmony_ci cmdBuffer.reset([[queue commandBufferWithUnretainedReferences] retain]); 35cb93a386Sopenharmony_ci } 36cb93a386Sopenharmony_ci if (cmdBuffer == nil) { 37cb93a386Sopenharmony_ci return nullptr; 38cb93a386Sopenharmony_ci } 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO 41cb93a386Sopenharmony_ci (*cmdBuffer).label = @"CommandBuffer::Make"; 42cb93a386Sopenharmony_ci#endif 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci return sk_sp<CommandBuffer>(new CommandBuffer(std::move(cmdBuffer), gpu)); 45cb93a386Sopenharmony_ci} 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ciCommandBuffer::CommandBuffer(sk_cfp<id<MTLCommandBuffer>> cmdBuffer, const Gpu* gpu) 48cb93a386Sopenharmony_ci : fCommandBuffer(std::move(cmdBuffer)), fGpu(gpu) {} 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ciCommandBuffer::~CommandBuffer() {} 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_cibool CommandBuffer::commit() { 53cb93a386Sopenharmony_ci SkASSERT(!fActiveRenderCommandEncoder); 54cb93a386Sopenharmony_ci this->endBlitCommandEncoder(); 55cb93a386Sopenharmony_ci [(*fCommandBuffer) commit]; 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_ci // TODO: better error reporting 58cb93a386Sopenharmony_ci if ((*fCommandBuffer).status == MTLCommandBufferStatusError) { 59cb93a386Sopenharmony_ci NSString* description = (*fCommandBuffer).error.localizedDescription; 60cb93a386Sopenharmony_ci const char* errorString = [description UTF8String]; 61cb93a386Sopenharmony_ci SkDebugf("Error submitting command buffer: %s\n", errorString); 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci return ((*fCommandBuffer).status != MTLCommandBufferStatusError); 65cb93a386Sopenharmony_ci} 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_civoid CommandBuffer::onBeginRenderPass(const RenderPassDesc& renderPassDesc) { 68cb93a386Sopenharmony_ci SkASSERT(!fActiveRenderCommandEncoder); 69cb93a386Sopenharmony_ci this->endBlitCommandEncoder(); 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci const static MTLLoadAction mtlLoadAction[] { 72cb93a386Sopenharmony_ci MTLLoadActionLoad, 73cb93a386Sopenharmony_ci MTLLoadActionClear, 74cb93a386Sopenharmony_ci MTLLoadActionDontCare 75cb93a386Sopenharmony_ci }; 76cb93a386Sopenharmony_ci static_assert((int)LoadOp::kLoad == 0); 77cb93a386Sopenharmony_ci static_assert((int)LoadOp::kClear == 1); 78cb93a386Sopenharmony_ci static_assert((int)LoadOp::kDiscard == 2); 79cb93a386Sopenharmony_ci static_assert(SK_ARRAY_COUNT(mtlLoadAction) == kLoadOpCount); 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci const static MTLStoreAction mtlStoreAction[] { 82cb93a386Sopenharmony_ci MTLStoreActionStore, 83cb93a386Sopenharmony_ci MTLStoreActionDontCare 84cb93a386Sopenharmony_ci }; 85cb93a386Sopenharmony_ci static_assert((int)StoreOp::kStore == 0); 86cb93a386Sopenharmony_ci static_assert((int)StoreOp::kDiscard == 1); 87cb93a386Sopenharmony_ci static_assert(SK_ARRAY_COUNT(mtlStoreAction) == kStoreOpCount); 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci sk_cfp<MTLRenderPassDescriptor*> descriptor([[MTLRenderPassDescriptor alloc] init]); 90cb93a386Sopenharmony_ci // Set up color attachment. 91cb93a386Sopenharmony_ci auto& colorInfo = renderPassDesc.fColorAttachment; 92cb93a386Sopenharmony_ci if (colorInfo.fTextureProxy) { 93cb93a386Sopenharmony_ci auto colorAttachment = (*descriptor).colorAttachments[0]; 94cb93a386Sopenharmony_ci const Texture* colorTexture = (const Texture*)colorInfo.fTextureProxy->texture(); 95cb93a386Sopenharmony_ci colorAttachment.texture = colorTexture->mtlTexture(); 96cb93a386Sopenharmony_ci const std::array<float, 4>& clearColor = renderPassDesc.fClearColor; 97cb93a386Sopenharmony_ci colorAttachment.clearColor = 98cb93a386Sopenharmony_ci MTLClearColorMake(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); 99cb93a386Sopenharmony_ci colorAttachment.loadAction = mtlLoadAction[static_cast<int>(colorInfo.fLoadOp)]; 100cb93a386Sopenharmony_ci colorAttachment.storeAction = mtlStoreAction[static_cast<int>(colorInfo.fStoreOp)]; 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci // TODO: 104cb93a386Sopenharmony_ci // * setup resolve 105cb93a386Sopenharmony_ci // * set up stencil and depth 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci fActiveRenderCommandEncoder = RenderCommandEncoder::Make(fCommandBuffer.get(), 108cb93a386Sopenharmony_ci descriptor.get()); 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci this->trackResource(fActiveRenderCommandEncoder); 111cb93a386Sopenharmony_ci} 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_civoid CommandBuffer::endRenderPass() { 114cb93a386Sopenharmony_ci SkASSERT(fActiveRenderCommandEncoder); 115cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->endEncoding(); 116cb93a386Sopenharmony_ci fActiveRenderCommandEncoder.reset(); 117cb93a386Sopenharmony_ci} 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ciBlitCommandEncoder* CommandBuffer::getBlitCommandEncoder() { 120cb93a386Sopenharmony_ci if (fActiveBlitCommandEncoder) { 121cb93a386Sopenharmony_ci return fActiveBlitCommandEncoder.get(); 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci fActiveBlitCommandEncoder = BlitCommandEncoder::Make(fCommandBuffer.get()); 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci if (!fActiveBlitCommandEncoder) { 127cb93a386Sopenharmony_ci return nullptr; 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci // We add the ref on the command buffer for the BlitCommandEncoder now so that we don't need 131cb93a386Sopenharmony_ci // to add a ref for every copy we do. 132cb93a386Sopenharmony_ci this->trackResource(fActiveBlitCommandEncoder); 133cb93a386Sopenharmony_ci return fActiveBlitCommandEncoder.get(); 134cb93a386Sopenharmony_ci} 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_civoid CommandBuffer::endBlitCommandEncoder() { 137cb93a386Sopenharmony_ci if (fActiveBlitCommandEncoder) { 138cb93a386Sopenharmony_ci fActiveBlitCommandEncoder->endEncoding(); 139cb93a386Sopenharmony_ci fActiveBlitCommandEncoder.reset(); 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci} 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_civoid CommandBuffer::onBindGraphicsPipeline(const skgpu::GraphicsPipeline* graphicsPipeline) { 144cb93a386Sopenharmony_ci SkASSERT(fActiveRenderCommandEncoder); 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci auto mtlPipeline = static_cast<const GraphicsPipeline*>(graphicsPipeline); 147cb93a386Sopenharmony_ci auto pipelineState = mtlPipeline->mtlPipelineState(); 148cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->setRenderPipelineState(pipelineState); 149cb93a386Sopenharmony_ci fCurrentVertexStride = mtlPipeline->vertexStride(); 150cb93a386Sopenharmony_ci fCurrentInstanceStride = mtlPipeline->instanceStride(); 151cb93a386Sopenharmony_ci} 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_civoid CommandBuffer::onBindUniformBuffer(const skgpu::Buffer* uniformBuffer, 154cb93a386Sopenharmony_ci size_t uniformOffset) { 155cb93a386Sopenharmony_ci SkASSERT(fActiveRenderCommandEncoder); 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci id<MTLBuffer> mtlBuffer = static_cast<const Buffer*>(uniformBuffer)->mtlBuffer(); 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci if (fGpu->mtlCaps().isMac()) { 160cb93a386Sopenharmony_ci SkASSERT((uniformOffset & 0xFF) == 0); 161cb93a386Sopenharmony_ci } else { 162cb93a386Sopenharmony_ci SkASSERT((uniformOffset & 0xF) == 0); 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->setVertexBuffer(mtlBuffer, uniformOffset, 165cb93a386Sopenharmony_ci GraphicsPipeline::kUniformBufferIndex); 166cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->setFragmentBuffer(mtlBuffer, uniformOffset, 167cb93a386Sopenharmony_ci GraphicsPipeline::kUniformBufferIndex); 168cb93a386Sopenharmony_ci} 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_civoid CommandBuffer::onBindVertexBuffers(const skgpu::Buffer* vertexBuffer, 171cb93a386Sopenharmony_ci size_t vertexOffset, 172cb93a386Sopenharmony_ci const skgpu::Buffer* instanceBuffer, 173cb93a386Sopenharmony_ci size_t instanceOffset) { 174cb93a386Sopenharmony_ci SkASSERT(fActiveRenderCommandEncoder); 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ci if (vertexBuffer) { 177cb93a386Sopenharmony_ci id<MTLBuffer> mtlBuffer = static_cast<const Buffer*>(vertexBuffer)->mtlBuffer(); 178cb93a386Sopenharmony_ci SkASSERT((vertexOffset & 0xF) == 0); 179cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->setVertexBuffer(mtlBuffer, vertexOffset, 180cb93a386Sopenharmony_ci GraphicsPipeline::kVertexBufferIndex); 181cb93a386Sopenharmony_ci } 182cb93a386Sopenharmony_ci if (instanceBuffer) { 183cb93a386Sopenharmony_ci id<MTLBuffer> mtlBuffer = static_cast<const Buffer*>(instanceBuffer)->mtlBuffer(); 184cb93a386Sopenharmony_ci SkASSERT((instanceOffset & 0xF) == 0); 185cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->setVertexBuffer(mtlBuffer, instanceOffset, 186cb93a386Sopenharmony_ci GraphicsPipeline::kInstanceBufferIndex); 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci} 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_civoid CommandBuffer::onBindIndexBuffer(const skgpu::Buffer* indexBuffer, size_t offset) { 191cb93a386Sopenharmony_ci if (indexBuffer) { 192cb93a386Sopenharmony_ci fCurrentIndexBuffer = static_cast<const Buffer*>(indexBuffer)->mtlBuffer(); 193cb93a386Sopenharmony_ci fCurrentIndexBufferOffset = offset; 194cb93a386Sopenharmony_ci } else { 195cb93a386Sopenharmony_ci fCurrentIndexBuffer = nil; 196cb93a386Sopenharmony_ci fCurrentIndexBufferOffset = 0; 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci} 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_cistatic MTLPrimitiveType graphite_to_mtl_primitive(PrimitiveType primitiveType) { 201cb93a386Sopenharmony_ci const static MTLPrimitiveType mtlPrimitiveType[] { 202cb93a386Sopenharmony_ci MTLPrimitiveTypeTriangle, 203cb93a386Sopenharmony_ci MTLPrimitiveTypeTriangleStrip, 204cb93a386Sopenharmony_ci MTLPrimitiveTypePoint, 205cb93a386Sopenharmony_ci }; 206cb93a386Sopenharmony_ci static_assert((int)PrimitiveType::kTriangles == 0); 207cb93a386Sopenharmony_ci static_assert((int)PrimitiveType::kTriangleStrip == 1); 208cb93a386Sopenharmony_ci static_assert((int)PrimitiveType::kPoints == 2); 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ci SkASSERT(primitiveType <= PrimitiveType::kPoints); 211cb93a386Sopenharmony_ci return mtlPrimitiveType[static_cast<int>(primitiveType)]; 212cb93a386Sopenharmony_ci} 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_civoid CommandBuffer::onDraw(PrimitiveType type, unsigned int baseVertex, unsigned int vertexCount) { 215cb93a386Sopenharmony_ci SkASSERT(fActiveRenderCommandEncoder); 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci auto mtlPrimitiveType = graphite_to_mtl_primitive(type); 218cb93a386Sopenharmony_ci 219cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->drawPrimitives(mtlPrimitiveType, baseVertex, vertexCount); 220cb93a386Sopenharmony_ci} 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_civoid CommandBuffer::onDrawIndexed(PrimitiveType type, unsigned int baseIndex, 223cb93a386Sopenharmony_ci unsigned int indexCount, unsigned int baseVertex) { 224cb93a386Sopenharmony_ci SkASSERT(fActiveRenderCommandEncoder); 225cb93a386Sopenharmony_ci 226cb93a386Sopenharmony_ci auto mtlPrimitiveType = graphite_to_mtl_primitive(type); 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->setVertexBufferOffset(baseVertex * fCurrentVertexStride, 229cb93a386Sopenharmony_ci GraphicsPipeline::kVertexBufferIndex); 230cb93a386Sopenharmony_ci size_t indexOffset = fCurrentIndexBufferOffset + sizeof(uint16_t )* baseIndex; 231cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->drawIndexedPrimitives(mtlPrimitiveType, indexCount, 232cb93a386Sopenharmony_ci MTLIndexTypeUInt16, fCurrentIndexBuffer, 233cb93a386Sopenharmony_ci indexOffset); 234cb93a386Sopenharmony_ci} 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_civoid CommandBuffer::onDrawInstanced(PrimitiveType type, unsigned int baseVertex, 237cb93a386Sopenharmony_ci unsigned int vertexCount, unsigned int baseInstance, 238cb93a386Sopenharmony_ci unsigned int instanceCount) { 239cb93a386Sopenharmony_ci SkASSERT(fActiveRenderCommandEncoder); 240cb93a386Sopenharmony_ci 241cb93a386Sopenharmony_ci auto mtlPrimitiveType = graphite_to_mtl_primitive(type); 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci // This ordering is correct 244cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->drawPrimitives(mtlPrimitiveType, baseVertex, vertexCount, 245cb93a386Sopenharmony_ci instanceCount, baseInstance); 246cb93a386Sopenharmony_ci} 247cb93a386Sopenharmony_ci 248cb93a386Sopenharmony_civoid CommandBuffer::onDrawIndexedInstanced(PrimitiveType type, unsigned int baseIndex, 249cb93a386Sopenharmony_ci unsigned int indexCount, unsigned int baseVertex, 250cb93a386Sopenharmony_ci unsigned int baseInstance, unsigned int instanceCount) { 251cb93a386Sopenharmony_ci SkASSERT(fActiveRenderCommandEncoder); 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ci auto mtlPrimitiveType = graphite_to_mtl_primitive(type); 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->setVertexBufferOffset(baseVertex * fCurrentVertexStride, 256cb93a386Sopenharmony_ci GraphicsPipeline::kVertexBufferIndex); 257cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->setVertexBufferOffset(baseInstance * fCurrentInstanceStride, 258cb93a386Sopenharmony_ci GraphicsPipeline::kInstanceBufferIndex); 259cb93a386Sopenharmony_ci size_t indexOffset = fCurrentIndexBufferOffset + sizeof(uint16_t) * baseIndex; 260cb93a386Sopenharmony_ci fActiveRenderCommandEncoder->drawIndexedPrimitives(mtlPrimitiveType, indexCount, 261cb93a386Sopenharmony_ci MTLIndexTypeUInt16, fCurrentIndexBuffer, 262cb93a386Sopenharmony_ci indexOffset, instanceCount, 263cb93a386Sopenharmony_ci baseVertex, baseInstance); 264cb93a386Sopenharmony_ci} 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_civoid CommandBuffer::onCopyTextureToBuffer(const skgpu::Texture* texture, 267cb93a386Sopenharmony_ci SkIRect srcRect, 268cb93a386Sopenharmony_ci const skgpu::Buffer* buffer, 269cb93a386Sopenharmony_ci size_t bufferOffset, 270cb93a386Sopenharmony_ci size_t bufferRowBytes) { 271cb93a386Sopenharmony_ci SkASSERT(!fActiveRenderCommandEncoder); 272cb93a386Sopenharmony_ci 273cb93a386Sopenharmony_ci id<MTLTexture> mtlTexture = static_cast<const Texture*>(texture)->mtlTexture(); 274cb93a386Sopenharmony_ci id<MTLBuffer> mtlBuffer = static_cast<const Buffer*>(buffer)->mtlBuffer(); 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ci BlitCommandEncoder* blitCmdEncoder = this->getBlitCommandEncoder(); 277cb93a386Sopenharmony_ci 278cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO 279cb93a386Sopenharmony_ci blitCmdEncoder->pushDebugGroup(@"readOrTransferPixels"); 280cb93a386Sopenharmony_ci#endif 281cb93a386Sopenharmony_ci blitCmdEncoder->copyFromTexture(mtlTexture, srcRect, mtlBuffer, bufferOffset, bufferRowBytes); 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci if (fGpu->mtlCaps().isMac()) { 284cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC 285cb93a386Sopenharmony_ci // Sync GPU data back to the CPU 286cb93a386Sopenharmony_ci blitCmdEncoder->synchronizeResource(mtlBuffer); 287cb93a386Sopenharmony_ci#endif 288cb93a386Sopenharmony_ci } 289cb93a386Sopenharmony_ci#ifdef SK_ENABLE_MTL_DEBUG_INFO 290cb93a386Sopenharmony_ci blitCmdEncoder->popDebugGroup(); 291cb93a386Sopenharmony_ci#endif 292cb93a386Sopenharmony_ci} 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_ci 295cb93a386Sopenharmony_ci} // namespace skgpu::mtl 296