1/* 2 * Copyright 2018 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/GrMtlOpsRenderPass.h" 9 10#include "src/gpu/GrBackendUtils.h" 11#include "src/gpu/GrColor.h" 12#include "src/gpu/GrRenderTarget.h" 13#include "src/gpu/mtl/GrMtlCommandBuffer.h" 14#include "src/gpu/mtl/GrMtlPipelineState.h" 15#include "src/gpu/mtl/GrMtlPipelineStateBuilder.h" 16#include "src/gpu/mtl/GrMtlRenderCommandEncoder.h" 17#include "src/gpu/mtl/GrMtlRenderTarget.h" 18#include "src/gpu/mtl/GrMtlTexture.h" 19 20#if !__has_feature(objc_arc) 21#error This file must be compiled with Arc. Use -fobjc-arc flag 22#endif 23 24GR_NORETAIN_BEGIN 25 26GrMtlOpsRenderPass::GrMtlOpsRenderPass(GrMtlGpu* gpu, GrRenderTarget* rt, 27 sk_sp<GrMtlFramebuffer> framebuffer, GrSurfaceOrigin origin, 28 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, 29 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo) 30 : INHERITED(rt, origin) 31 , fGpu(gpu) 32 , fFramebuffer(std::move(framebuffer)) { 33 this->setupRenderPass(colorInfo, stencilInfo); 34} 35 36GrMtlOpsRenderPass::~GrMtlOpsRenderPass() { 37} 38 39void GrMtlOpsRenderPass::submit() { 40 if (!fFramebuffer) { 41 return; 42 } 43 SkIRect iBounds; 44 fBounds.roundOut(&iBounds); 45 fGpu->submitIndirectCommandBuffer(fRenderTarget, fOrigin, &iBounds); 46 fActiveRenderCmdEncoder = nil; 47} 48 49static MTLPrimitiveType gr_to_mtl_primitive(GrPrimitiveType primitiveType) { 50 const static MTLPrimitiveType mtlPrimitiveType[] { 51 MTLPrimitiveTypeTriangle, 52 MTLPrimitiveTypeTriangleStrip, 53 MTLPrimitiveTypePoint, 54 MTLPrimitiveTypeLine, 55 MTLPrimitiveTypeLineStrip 56 }; 57 static_assert((int)GrPrimitiveType::kTriangles == 0); 58 static_assert((int)GrPrimitiveType::kTriangleStrip == 1); 59 static_assert((int)GrPrimitiveType::kPoints == 2); 60 static_assert((int)GrPrimitiveType::kLines == 3); 61 static_assert((int)GrPrimitiveType::kLineStrip == 4); 62 63 SkASSERT(primitiveType <= GrPrimitiveType::kLineStrip); 64 return mtlPrimitiveType[static_cast<int>(primitiveType)]; 65} 66 67bool GrMtlOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo, 68 const SkRect& drawBounds) { 69 const GrMtlCaps& caps = fGpu->mtlCaps(); 70 GrProgramDesc programDesc = caps.makeDesc(fRenderTarget, programInfo, 71 GrCaps::ProgramDescOverrideFlags::kNone); 72 if (!programDesc.isValid()) { 73 return false; 74 } 75 76 fActivePipelineState = fGpu->resourceProvider().findOrCreateCompatiblePipelineState( 77 programDesc, programInfo); 78 if (!fActivePipelineState) { 79 return false; 80 } 81 82 fActivePipelineState->setData(fFramebuffer.get(), programInfo); 83 fCurrentVertexStride = programInfo.geomProc().vertexStride(); 84 85 if (!fActiveRenderCmdEncoder) { 86 fActiveRenderCmdEncoder = 87 fGpu->commandBuffer()->getRenderCommandEncoder(fRenderPassDesc, 88 fActivePipelineState, this); 89 if (!fActiveRenderCmdEncoder) { 90 return false; 91 } 92 fGpu->commandBuffer()->addGrSurface( 93 sk_ref_sp<GrMtlAttachment>(fFramebuffer->colorAttachment())); 94 } 95 96 fActiveRenderCmdEncoder->setRenderPipelineState( 97 fActivePipelineState->pipeline()->mtlPipelineState()); 98#ifdef SK_ENABLE_MTL_DEBUG_INFO 99 if (!fDebugGroupActive) { 100 fActiveRenderCmdEncoder->pushDebugGroup(@"bindAndDraw"); 101 fDebugGroupActive = true; 102 } 103#endif 104 fActivePipelineState->setDrawState(fActiveRenderCmdEncoder, 105 programInfo.pipeline().writeSwizzle(), 106 programInfo.pipeline().getXferProcessor()); 107 if (this->gpu()->caps()->wireframeMode() || programInfo.pipeline().isWireframe()) { 108 fActiveRenderCmdEncoder->setTriangleFillMode(MTLTriangleFillModeLines); 109 } else { 110 fActiveRenderCmdEncoder->setTriangleFillMode(MTLTriangleFillModeFill); 111 } 112 113 if (!programInfo.pipeline().isScissorTestEnabled()) { 114 // "Disable" scissor by setting it to the full pipeline bounds. 115 SkISize dimensions = fFramebuffer->colorAttachment()->dimensions(); 116 GrMtlPipelineState::SetDynamicScissorRectState(fActiveRenderCmdEncoder, 117 dimensions, fOrigin, 118 SkIRect::MakeWH(dimensions.width(), 119 dimensions.height())); 120 } 121 122 fActivePrimitiveType = gr_to_mtl_primitive(programInfo.primitiveType()); 123 fBounds.join(drawBounds); 124 return true; 125} 126 127void GrMtlOpsRenderPass::onSetScissorRect(const SkIRect& scissor) { 128 SkASSERT(fActivePipelineState); 129 SkASSERT(fActiveRenderCmdEncoder); 130 GrMtlPipelineState::SetDynamicScissorRectState(fActiveRenderCmdEncoder, 131 fFramebuffer->colorAttachment()->dimensions(), 132 fOrigin, scissor); 133} 134 135bool GrMtlOpsRenderPass::onBindTextures(const GrGeometryProcessor& geomProc, 136 const GrSurfaceProxy* const geomProcTextures[], 137 const GrPipeline& pipeline) { 138 SkASSERT(fActivePipelineState); 139 SkASSERT(fActiveRenderCmdEncoder); 140#ifdef SK_ENABLE_MTL_DEBUG_INFO 141 if (!fDebugGroupActive) { 142 fActiveRenderCmdEncoder->pushDebugGroup(@"bindAndDraw"); 143 fDebugGroupActive = true; 144 } 145#endif 146 fActivePipelineState->setTextures(geomProc, pipeline, geomProcTextures); 147 fActivePipelineState->bindTextures(fActiveRenderCmdEncoder); 148 return true; 149} 150 151void GrMtlOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) { 152 // Partial clears are not supported 153 SkASSERT(!scissor.enabled()); 154 155 // Ideally we should never end up here since all clears should either be done as draws or 156 // load ops in metal. However, if a client inserts a wait op we need to handle it. 157 auto colorAttachment = fRenderPassDesc.colorAttachments[0]; 158 colorAttachment.clearColor = MTLClearColorMake(color[0], color[1], color[2], color[3]); 159 colorAttachment.loadAction = MTLLoadActionClear; 160 fActiveRenderCmdEncoder = 161 fGpu->commandBuffer()->getRenderCommandEncoder(fRenderPassDesc, nullptr, this); 162} 163 164void GrMtlOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) { 165 // Partial clears are not supported 166 SkASSERT(!scissor.enabled()); 167 168 GrAttachment* sb = fFramebuffer->stencilAttachment(); 169 // this should only be called internally when we know we have a 170 // stencil buffer. 171 SkASSERT(sb); 172 int stencilBitCount = GrBackendFormatStencilBits(sb->backendFormat()); 173 174 // The contract with the callers does not guarantee that we preserve all bits in the stencil 175 // during this clear. Thus we will clear the entire stencil to the desired value. 176 auto stencilAttachment = fRenderPassDesc.stencilAttachment; 177 if (insideStencilMask) { 178 stencilAttachment.clearStencil = (1 << (stencilBitCount - 1)); 179 } else { 180 stencilAttachment.clearStencil = 0; 181 } 182 183 stencilAttachment.loadAction = MTLLoadActionClear; 184 fActiveRenderCmdEncoder = this->setupResolve(); 185 186 if (!fActiveRenderCmdEncoder) { 187 fActiveRenderCmdEncoder = 188 fGpu->commandBuffer()->getRenderCommandEncoder(fRenderPassDesc, nullptr, this); 189 } 190} 191 192void GrMtlOpsRenderPass::inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) { 193 // TODO: could this be more efficient? 194 state->doUpload(upload); 195 // doUpload() creates a blitCommandEncoder, so if we had a previous render we need to 196 // adjust the renderPassDescriptor to load from it. 197 if (fActiveRenderCmdEncoder) { 198 auto colorAttachment = fRenderPassDesc.colorAttachments[0]; 199 colorAttachment.loadAction = MTLLoadActionLoad; 200 auto mtlStencil = fRenderPassDesc.stencilAttachment; 201 mtlStencil.loadAction = MTLLoadActionLoad; 202 } 203 // If the previous renderCommandEncoder did a resolve without an MSAA store 204 // (e.g., if the color attachment is memoryless) we need to copy the contents of 205 // the resolve attachment to the MSAA attachment at this point. 206 fActiveRenderCmdEncoder = this->setupResolve(); 207 208 if (!fActiveRenderCmdEncoder) { 209 // If setting up for the resolve didn't create an encoder, it's probably reasonable to 210 // create a new encoder at this point, though maybe not necessary. 211 fActiveRenderCmdEncoder = 212 fGpu->commandBuffer()->getRenderCommandEncoder(fRenderPassDesc, nullptr, this); 213 } 214} 215 216void GrMtlOpsRenderPass::initRenderState(GrMtlRenderCommandEncoder* encoder) { 217 if (!encoder) { 218 return; 219 } 220#ifdef SK_ENABLE_MTL_DEBUG_INFO 221 encoder->pushDebugGroup(@"initRenderState"); 222#endif 223 encoder->setFrontFacingWinding(MTLWindingCounterClockwise); 224 SkISize colorAttachmentDimensions = fFramebuffer->colorAttachment()->dimensions(); 225 // Strictly speaking we shouldn't have to set this, as the default viewport is the size of 226 // the drawable used to generate the renderCommandEncoder -- but just in case. 227 MTLViewport viewport = { 0.0, 0.0, 228 (double) colorAttachmentDimensions.width(), 229 (double) colorAttachmentDimensions.height(), 230 0.0, 1.0 }; 231 encoder->setViewport(viewport); 232#ifdef SK_ENABLE_MTL_DEBUG_INFO 233 encoder->popDebugGroup(); 234#endif 235} 236 237void GrMtlOpsRenderPass::setupRenderPass( 238 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, 239 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo) { 240 const static MTLLoadAction mtlLoadAction[] { 241 MTLLoadActionLoad, 242 MTLLoadActionClear, 243 MTLLoadActionDontCare 244 }; 245 static_assert((int)GrLoadOp::kLoad == 0); 246 static_assert((int)GrLoadOp::kClear == 1); 247 static_assert((int)GrLoadOp::kDiscard == 2); 248 SkASSERT(colorInfo.fLoadOp <= GrLoadOp::kDiscard); 249 SkASSERT(stencilInfo.fLoadOp <= GrLoadOp::kDiscard); 250 251 const static MTLStoreAction mtlStoreAction[] { 252 MTLStoreActionStore, 253 MTLStoreActionDontCare 254 }; 255 static_assert((int)GrStoreOp::kStore == 0); 256 static_assert((int)GrStoreOp::kDiscard == 1); 257 SkASSERT(colorInfo.fStoreOp <= GrStoreOp::kDiscard); 258 SkASSERT(stencilInfo.fStoreOp <= GrStoreOp::kDiscard); 259 260 fRenderPassDesc = [MTLRenderPassDescriptor new]; 261 auto colorAttachment = fRenderPassDesc.colorAttachments[0]; 262 auto color = fFramebuffer->colorAttachment(); 263 colorAttachment.texture = color->mtlTexture(); 264 const std::array<float, 4>& clearColor = colorInfo.fClearColor; 265 colorAttachment.clearColor = 266 MTLClearColorMake(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); 267 colorAttachment.loadAction = mtlLoadAction[static_cast<int>(colorInfo.fLoadOp)]; 268 colorAttachment.storeAction = mtlStoreAction[static_cast<int>(colorInfo.fStoreOp)]; 269 270 auto stencil = fFramebuffer->stencilAttachment(); 271 auto mtlStencil = fRenderPassDesc.stencilAttachment; 272 if (stencil) { 273 mtlStencil.texture = stencil->mtlTexture(); 274 } 275 mtlStencil.clearStencil = 0; 276 mtlStencil.loadAction = mtlLoadAction[static_cast<int>(stencilInfo.fLoadOp)]; 277 mtlStencil.storeAction = mtlStoreAction[static_cast<int>(stencilInfo.fStoreOp)]; 278 279 fActiveRenderCmdEncoder = this->setupResolve(); 280 281 if (!fActiveRenderCmdEncoder) { 282 // Manage initial clears 283 if (colorInfo.fLoadOp == GrLoadOp::kClear || stencilInfo.fLoadOp == GrLoadOp::kClear) { 284 fBounds = SkRect::MakeWH(color->dimensions().width(), 285 color->dimensions().height()); 286 fActiveRenderCmdEncoder = 287 fGpu->commandBuffer()->getRenderCommandEncoder(fRenderPassDesc, nullptr, this); 288 } else { 289 fBounds.setEmpty(); 290 // For now, we lazily create the renderCommandEncoder because we may have no draws, 291 // and an empty renderCommandEncoder can still produce output. This can cause issues 292 // when we've cleared a texture upon creation -- we'll subsequently discard the contents. 293 // This can be removed when that ordering is fixed. 294 } 295 } 296} 297 298GrMtlRenderCommandEncoder* GrMtlOpsRenderPass::setupResolve() { 299 auto resolve = fFramebuffer->resolveAttachment(); 300 if (resolve) { 301 auto colorAttachment = fRenderPassDesc.colorAttachments[0]; 302 colorAttachment.resolveTexture = resolve->mtlTexture(); 303 // TODO: For framebufferOnly attachments we should do StoreAndMultisampleResolve if 304 // the storeAction is Store. But for the moment they don't take this path. 305 colorAttachment.storeAction = MTLStoreActionMultisampleResolve; 306 if (colorAttachment.loadAction == MTLLoadActionLoad) { 307 auto color = fFramebuffer->colorAttachment(); 308 auto dimensions = color->dimensions(); 309 // for now use the full bounds 310 auto nativeBounds = GrNativeRect::MakeIRectRelativeTo( 311 fOrigin, dimensions.height(), SkIRect::MakeSize(dimensions)); 312 return fGpu->loadMSAAFromResolve(color, resolve, nativeBounds, 313 fRenderPassDesc.stencilAttachment); 314 } 315 } 316 317 return nullptr; 318} 319 320void GrMtlOpsRenderPass::onBindBuffers(sk_sp<const GrBuffer> indexBuffer, 321 sk_sp<const GrBuffer> instanceBuffer, 322 sk_sp<const GrBuffer> vertexBuffer, 323 GrPrimitiveRestart primRestart) { 324#ifdef SK_ENABLE_MTL_DEBUG_INFO 325 if (!fDebugGroupActive) { 326 fActiveRenderCmdEncoder->pushDebugGroup(@"bindAndDraw"); 327 fDebugGroupActive = true; 328 } 329#endif 330 SkASSERT(GrPrimitiveRestart::kNo == primRestart); 331 int inputBufferIndex = 0; 332 if (vertexBuffer) { 333 SkASSERT(!vertexBuffer->isCpuBuffer()); 334 SkASSERT(!static_cast<const GrGpuBuffer*>(vertexBuffer.get())->isMapped()); 335 fActiveVertexBuffer = std::move(vertexBuffer); 336 fGpu->commandBuffer()->addGrBuffer(fActiveVertexBuffer); 337 ++inputBufferIndex; 338 } 339 if (instanceBuffer) { 340 SkASSERT(!instanceBuffer->isCpuBuffer()); 341 SkASSERT(!static_cast<const GrGpuBuffer*>(instanceBuffer.get())->isMapped()); 342 this->setVertexBuffer(fActiveRenderCmdEncoder, instanceBuffer.get(), 0, inputBufferIndex++); 343 fActiveInstanceBuffer = std::move(instanceBuffer); 344 fGpu->commandBuffer()->addGrBuffer(fActiveInstanceBuffer); 345 } 346 if (indexBuffer) { 347 SkASSERT(!indexBuffer->isCpuBuffer()); 348 SkASSERT(!static_cast<const GrGpuBuffer*>(indexBuffer.get())->isMapped()); 349 fActiveIndexBuffer = std::move(indexBuffer); 350 fGpu->commandBuffer()->addGrBuffer(fActiveIndexBuffer); 351 } 352} 353 354void GrMtlOpsRenderPass::onDraw(int vertexCount, int baseVertex) { 355 SkASSERT(fActivePipelineState); 356 SkASSERT(nil != fActiveRenderCmdEncoder); 357#ifdef SK_ENABLE_MTL_DEBUG_INFO 358 if (!fDebugGroupActive) { 359 fActiveRenderCmdEncoder->pushDebugGroup(@"bindAndDraw"); 360 fDebugGroupActive = true; 361 } 362#endif 363 this->setVertexBuffer(fActiveRenderCmdEncoder, fActiveVertexBuffer.get(), 0, 0); 364 365 fActiveRenderCmdEncoder->drawPrimitives(fActivePrimitiveType, baseVertex, vertexCount); 366 fGpu->stats()->incNumDraws(); 367#ifdef SK_ENABLE_MTL_DEBUG_INFO 368 SkASSERT(fDebugGroupActive); 369 fActiveRenderCmdEncoder->popDebugGroup(); 370 fDebugGroupActive = false; 371#endif 372} 373 374void GrMtlOpsRenderPass::onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue, 375 uint16_t maxIndexValue, int baseVertex) { 376 SkASSERT(fActivePipelineState); 377 SkASSERT(nil != fActiveRenderCmdEncoder); 378 SkASSERT(fActiveIndexBuffer); 379#ifdef SK_ENABLE_MTL_DEBUG_INFO 380 if (!fDebugGroupActive) { 381 fActiveRenderCmdEncoder->pushDebugGroup(@"bindAndDraw"); 382 fDebugGroupActive = true; 383 } 384#endif 385 this->setVertexBuffer(fActiveRenderCmdEncoder, fActiveVertexBuffer.get(), 386 fCurrentVertexStride * baseVertex, 0); 387 388 auto mtlIndexBuffer = static_cast<const GrMtlBuffer*>(fActiveIndexBuffer.get()); 389 size_t indexOffset = sizeof(uint16_t) * baseIndex; 390 id<MTLBuffer> indexBuffer = mtlIndexBuffer->mtlBuffer(); 391 fActiveRenderCmdEncoder->drawIndexedPrimitives(fActivePrimitiveType, indexCount, 392 MTLIndexTypeUInt16, indexBuffer, indexOffset); 393 fGpu->stats()->incNumDraws(); 394#ifdef SK_ENABLE_MTL_DEBUG_INFO 395 SkASSERT(fDebugGroupActive); 396 fActiveRenderCmdEncoder->popDebugGroup(); 397 fDebugGroupActive = false; 398#endif 399} 400 401void GrMtlOpsRenderPass::onDrawInstanced(int instanceCount, int baseInstance, int vertexCount, 402 int baseVertex) { 403 SkASSERT(fActivePipelineState); 404 SkASSERT(nil != fActiveRenderCmdEncoder); 405#ifdef SK_ENABLE_MTL_DEBUG_INFO 406 if (!fDebugGroupActive) { 407 fActiveRenderCmdEncoder->pushDebugGroup(@"bindAndDraw"); 408 fDebugGroupActive = true; 409 } 410#endif 411 this->setVertexBuffer(fActiveRenderCmdEncoder, fActiveVertexBuffer.get(), 0, 0); 412 413 if (@available(macOS 10.11, iOS 9.0, *)) { 414 fActiveRenderCmdEncoder->drawPrimitives(fActivePrimitiveType, baseVertex, vertexCount, 415 instanceCount, baseInstance); 416 } else { 417 SkASSERT(false); 418 } 419 fGpu->stats()->incNumDraws(); 420#ifdef SK_ENABLE_MTL_DEBUG_INFO 421 SkASSERT(fDebugGroupActive); 422 fActiveRenderCmdEncoder->popDebugGroup(); 423 fDebugGroupActive = false; 424#endif 425} 426 427void GrMtlOpsRenderPass::onDrawIndexedInstanced( 428 int indexCount, int baseIndex, int instanceCount, int baseInstance, int baseVertex) { 429 SkASSERT(fActivePipelineState); 430 SkASSERT(nil != fActiveRenderCmdEncoder); 431 SkASSERT(fActiveIndexBuffer); 432#ifdef SK_ENABLE_MTL_DEBUG_INFO 433 if (!fDebugGroupActive) { 434 fActiveRenderCmdEncoder->pushDebugGroup(@"bindAndDraw"); 435 fDebugGroupActive = true; 436 } 437#endif 438 this->setVertexBuffer(fActiveRenderCmdEncoder, fActiveVertexBuffer.get(), 0, 0); 439 440 auto mtlIndexBuffer = static_cast<const GrMtlBuffer*>(fActiveIndexBuffer.get()); 441 size_t indexOffset = sizeof(uint16_t) * baseIndex; 442 if (@available(macOS 10.11, iOS 9.0, *)) { 443 fActiveRenderCmdEncoder->drawIndexedPrimitives(fActivePrimitiveType, indexCount, 444 MTLIndexTypeUInt16, 445 mtlIndexBuffer->mtlBuffer(), indexOffset, 446 instanceCount, baseVertex, baseInstance); 447 } else { 448 SkASSERT(false); 449 } 450 fGpu->stats()->incNumDraws(); 451#ifdef SK_ENABLE_MTL_DEBUG_INFO 452 SkASSERT(fDebugGroupActive); 453 fActiveRenderCmdEncoder->popDebugGroup(); 454 fDebugGroupActive = false; 455#endif 456} 457 458void GrMtlOpsRenderPass::onDrawIndirect(const GrBuffer* drawIndirectBuffer, 459 size_t bufferOffset, 460 int drawCount) { 461 SkASSERT(fGpu->caps()->nativeDrawIndirectSupport()); 462 SkASSERT(fActivePipelineState); 463 SkASSERT(nil != fActiveRenderCmdEncoder); 464#ifdef SK_ENABLE_MTL_DEBUG_INFO 465 if (!fDebugGroupActive) { 466 fActiveRenderCmdEncoder->pushDebugGroup(@"bindAndDraw"); 467 fDebugGroupActive = true; 468 } 469#endif 470 this->setVertexBuffer(fActiveRenderCmdEncoder, fActiveVertexBuffer.get(), 0, 0); 471 472 auto mtlIndirectBuffer = static_cast<const GrMtlBuffer*>(drawIndirectBuffer); 473 const size_t stride = sizeof(GrDrawIndirectCommand); 474 while (drawCount >= 1) { 475 if (@available(macOS 10.11, iOS 9.0, *)) { 476 fActiveRenderCmdEncoder->drawPrimitives(fActivePrimitiveType, 477 mtlIndirectBuffer->mtlBuffer(), bufferOffset); 478 } else { 479 SkASSERT(false); 480 } 481 drawCount--; 482 bufferOffset += stride; 483 fGpu->stats()->incNumDraws(); 484 } 485#ifdef SK_ENABLE_MTL_DEBUG_INFO 486 SkASSERT(fDebugGroupActive); 487 fActiveRenderCmdEncoder->popDebugGroup(); 488 fDebugGroupActive = false; 489#endif 490} 491 492void GrMtlOpsRenderPass::onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer, 493 size_t bufferOffset, 494 int drawCount) { 495 SkASSERT(fGpu->caps()->nativeDrawIndirectSupport()); 496 SkASSERT(fActivePipelineState); 497 SkASSERT(nil != fActiveRenderCmdEncoder); 498 SkASSERT(fActiveIndexBuffer); 499#ifdef SK_ENABLE_MTL_DEBUG_INFO 500 if (!fDebugGroupActive) { 501 fActiveRenderCmdEncoder->pushDebugGroup(@"bindAndDraw"); 502 fDebugGroupActive = true; 503 } 504#endif 505 this->setVertexBuffer(fActiveRenderCmdEncoder, fActiveVertexBuffer.get(), 0, 0); 506 507 auto mtlIndexBuffer = static_cast<const GrMtlBuffer*>(fActiveIndexBuffer.get()); 508 auto mtlIndirectBuffer = static_cast<const GrMtlBuffer*>(drawIndirectBuffer); 509 size_t indexOffset = 0; 510 511 const size_t stride = sizeof(GrDrawIndexedIndirectCommand); 512 while (drawCount >= 1) { 513 if (@available(macOS 10.11, iOS 9.0, *)) { 514 fActiveRenderCmdEncoder->drawIndexedPrimitives(fActivePrimitiveType, 515 MTLIndexTypeUInt16, 516 mtlIndexBuffer->mtlBuffer(), 517 indexOffset, 518 mtlIndirectBuffer->mtlBuffer(), 519 bufferOffset); 520 } else { 521 SkASSERT(false); 522 } 523 drawCount--; 524 bufferOffset += stride; 525 fGpu->stats()->incNumDraws(); 526 } 527#ifdef SK_ENABLE_MTL_DEBUG_INFO 528 SkASSERT(fDebugGroupActive); 529 fActiveRenderCmdEncoder->popDebugGroup(); 530 fDebugGroupActive = false; 531#endif 532} 533 534void GrMtlOpsRenderPass::setVertexBuffer(GrMtlRenderCommandEncoder* encoder, 535 const GrBuffer* buffer, 536 size_t vertexOffset, 537 size_t inputBufferIndex) { 538 if (!buffer) { 539 return; 540 } 541 542 constexpr static int kFirstBufferBindingIdx = GrMtlUniformHandler::kLastUniformBinding + 1; 543 int index = inputBufferIndex + kFirstBufferBindingIdx; 544 SkASSERT(index < 4); 545 auto mtlBuffer = static_cast<const GrMtlBuffer*>(buffer); 546 id<MTLBuffer> mtlVertexBuffer = mtlBuffer->mtlBuffer(); 547 SkASSERT(mtlVertexBuffer); 548 size_t offset = vertexOffset; 549 encoder->setVertexBuffer(mtlVertexBuffer, offset, index); 550} 551 552GR_NORETAIN_END 553