1// 2// Copyright 2019 The ANGLE Project Authors. All rights reserved. 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5// 6// mtl_command_buffer.mm: 7// Implementations of Metal framework's MTLCommandBuffer, MTLCommandQueue, 8// MTLCommandEncoder's wrappers. 9// 10 11#include "libANGLE/renderer/metal/mtl_command_buffer.h" 12 13#include <cassert> 14#if ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER 15# include <random> 16#endif 17 18#include "common/debug.h" 19#include "libANGLE/renderer/metal/mtl_occlusion_query_pool.h" 20#include "libANGLE/renderer/metal/mtl_resources.h" 21 22// Use to compare the new values with the values already set in the command encoder: 23static inline bool operator==(const MTLViewport &lhs, const MTLViewport &rhs) 24{ 25 return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; 26} 27 28static inline bool operator==(const MTLScissorRect &lhs, const MTLScissorRect &rhs) 29{ 30 return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; 31} 32 33namespace rx 34{ 35namespace mtl 36{ 37 38namespace 39{ 40 41#define ANGLE_MTL_CMD_X(PROC) \ 42 PROC(Invalid) \ 43 PROC(SetRenderPipelineState) \ 44 PROC(SetTriangleFillMode) \ 45 PROC(SetFrontFacingWinding) \ 46 PROC(SetCullMode) \ 47 PROC(SetDepthStencilState) \ 48 PROC(SetDepthBias) \ 49 PROC(SetStencilRefVals) \ 50 PROC(SetViewport) \ 51 PROC(SetScissorRect) \ 52 PROC(SetBlendColor) \ 53 PROC(SetVertexBuffer) \ 54 PROC(SetVertexBufferOffset) \ 55 PROC(SetVertexBytes) \ 56 PROC(SetVertexSamplerState) \ 57 PROC(SetVertexTexture) \ 58 PROC(SetFragmentBuffer) \ 59 PROC(SetFragmentBufferOffset) \ 60 PROC(SetFragmentBytes) \ 61 PROC(SetFragmentSamplerState) \ 62 PROC(SetFragmentTexture) \ 63 PROC(Draw) \ 64 PROC(DrawInstanced) \ 65 PROC(DrawInstancedBaseInstance) \ 66 PROC(DrawIndexed) \ 67 PROC(DrawIndexedInstanced) \ 68 PROC(DrawIndexedInstancedBaseVertexBaseInstance) \ 69 PROC(SetVisibilityResultMode) \ 70 PROC(UseResource) \ 71 PROC(MemoryBarrierWithResource) \ 72 PROC(InsertDebugsign) \ 73 PROC(PushDebugGroup) \ 74 PROC(PopDebugGroup) 75 76#define ANGLE_MTL_TYPE_DECL(CMD) CMD, 77 78// Command types 79enum class CmdType : uint8_t 80{ 81 ANGLE_MTL_CMD_X(ANGLE_MTL_TYPE_DECL) 82}; 83 84// Commands decoder 85void InvalidCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 86{ 87 UNREACHABLE(); 88} 89 90void SetRenderPipelineStateCmd(id<MTLRenderCommandEncoder> encoder, 91 IntermediateCommandStream *stream) 92{ 93 id<MTLRenderPipelineState> state = stream->fetch<id<MTLRenderPipelineState>>(); 94 [encoder setRenderPipelineState:state]; 95 [state ANGLE_MTL_RELEASE]; 96} 97 98void SetTriangleFillModeCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 99{ 100 MTLTriangleFillMode mode = stream->fetch<MTLTriangleFillMode>(); 101 [encoder setTriangleFillMode:mode]; 102} 103 104void SetFrontFacingWindingCmd(id<MTLRenderCommandEncoder> encoder, 105 IntermediateCommandStream *stream) 106{ 107 MTLWinding winding = stream->fetch<MTLWinding>(); 108 [encoder setFrontFacingWinding:winding]; 109} 110 111void SetCullModeCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 112{ 113 MTLCullMode mode = stream->fetch<MTLCullMode>(); 114 [encoder setCullMode:mode]; 115} 116 117void SetDepthStencilStateCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 118{ 119 id<MTLDepthStencilState> state = stream->fetch<id<MTLDepthStencilState>>(); 120 [encoder setDepthStencilState:state]; 121 [state ANGLE_MTL_RELEASE]; 122} 123 124void SetDepthBiasCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 125{ 126 float depthBias = stream->fetch<float>(); 127 float slopeScale = stream->fetch<float>(); 128 float clamp = stream->fetch<float>(); 129 [encoder setDepthBias:depthBias slopeScale:slopeScale clamp:clamp]; 130} 131 132void SetStencilRefValsCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 133{ 134 // Metal has some bugs when reference values are larger than 0xff 135 uint32_t frontRef = stream->fetch<uint32_t>(); 136 uint32_t backRef = stream->fetch<uint32_t>(); 137 [encoder setStencilFrontReferenceValue:frontRef backReferenceValue:backRef]; 138} 139 140void SetViewportCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 141{ 142 MTLViewport viewport = stream->fetch<MTLViewport>(); 143 [encoder setViewport:viewport]; 144} 145 146void SetScissorRectCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 147{ 148 MTLScissorRect rect = stream->fetch<MTLScissorRect>(); 149 [encoder setScissorRect:rect]; 150} 151 152void SetBlendColorCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 153{ 154 float r = stream->fetch<float>(); 155 float g = stream->fetch<float>(); 156 float b = stream->fetch<float>(); 157 float a = stream->fetch<float>(); 158 [encoder setBlendColorRed:r green:g blue:b alpha:a]; 159} 160 161void SetVertexBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 162{ 163 id<MTLBuffer> buffer = stream->fetch<id<MTLBuffer>>(); 164 uint32_t offset = stream->fetch<uint32_t>(); 165 uint32_t index = stream->fetch<uint32_t>(); 166 [encoder setVertexBuffer:buffer offset:offset atIndex:index]; 167 [buffer ANGLE_MTL_RELEASE]; 168} 169 170void SetVertexBufferOffsetCmd(id<MTLRenderCommandEncoder> encoder, 171 IntermediateCommandStream *stream) 172{ 173 uint32_t offset = stream->fetch<uint32_t>(); 174 uint32_t index = stream->fetch<uint32_t>(); 175 [encoder setVertexBufferOffset:offset atIndex:index]; 176} 177 178void SetVertexBytesCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 179{ 180 size_t size = stream->fetch<size_t>(); 181 const uint8_t *bytes = stream->fetch(size); 182 uint32_t index = stream->fetch<uint32_t>(); 183 [encoder setVertexBytes:bytes length:size atIndex:index]; 184} 185 186void SetVertexSamplerStateCmd(id<MTLRenderCommandEncoder> encoder, 187 IntermediateCommandStream *stream) 188{ 189 id<MTLSamplerState> state = stream->fetch<id<MTLSamplerState>>(); 190 float lodMinClamp = stream->fetch<float>(); 191 float lodMaxClamp = stream->fetch<float>(); 192 uint32_t index = stream->fetch<uint32_t>(); 193 [encoder setVertexSamplerState:state 194 lodMinClamp:lodMinClamp 195 lodMaxClamp:lodMaxClamp 196 atIndex:index]; 197 198 [state ANGLE_MTL_RELEASE]; 199} 200 201void SetVertexTextureCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 202{ 203 id<MTLTexture> texture = stream->fetch<id<MTLTexture>>(); 204 uint32_t index = stream->fetch<uint32_t>(); 205 [encoder setVertexTexture:texture atIndex:index]; 206 [texture ANGLE_MTL_RELEASE]; 207} 208 209void SetFragmentBufferCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 210{ 211 id<MTLBuffer> buffer = stream->fetch<id<MTLBuffer>>(); 212 uint32_t offset = stream->fetch<uint32_t>(); 213 uint32_t index = stream->fetch<uint32_t>(); 214 [encoder setFragmentBuffer:buffer offset:offset atIndex:index]; 215 [buffer ANGLE_MTL_RELEASE]; 216} 217 218void SetFragmentBufferOffsetCmd(id<MTLRenderCommandEncoder> encoder, 219 IntermediateCommandStream *stream) 220{ 221 uint32_t offset = stream->fetch<uint32_t>(); 222 uint32_t index = stream->fetch<uint32_t>(); 223 [encoder setFragmentBufferOffset:offset atIndex:index]; 224} 225 226void SetFragmentBytesCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 227{ 228 size_t size = stream->fetch<size_t>(); 229 const uint8_t *bytes = stream->fetch(size); 230 uint32_t index = stream->fetch<uint32_t>(); 231 [encoder setFragmentBytes:bytes length:size atIndex:index]; 232} 233 234void SetFragmentSamplerStateCmd(id<MTLRenderCommandEncoder> encoder, 235 IntermediateCommandStream *stream) 236{ 237 id<MTLSamplerState> state = stream->fetch<id<MTLSamplerState>>(); 238 float lodMinClamp = stream->fetch<float>(); 239 float lodMaxClamp = stream->fetch<float>(); 240 uint32_t index = stream->fetch<uint32_t>(); 241 [encoder setFragmentSamplerState:state 242 lodMinClamp:lodMinClamp 243 lodMaxClamp:lodMaxClamp 244 atIndex:index]; 245 [state ANGLE_MTL_RELEASE]; 246} 247 248void SetFragmentTextureCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 249{ 250 id<MTLTexture> texture = stream->fetch<id<MTLTexture>>(); 251 uint32_t index = stream->fetch<uint32_t>(); 252 [encoder setFragmentTexture:texture atIndex:index]; 253 [texture ANGLE_MTL_RELEASE]; 254} 255 256void DrawCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 257{ 258 MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>(); 259 uint32_t vertexStart = stream->fetch<uint32_t>(); 260 uint32_t vertexCount = stream->fetch<uint32_t>(); 261 [encoder drawPrimitives:primitiveType vertexStart:vertexStart vertexCount:vertexCount]; 262} 263 264void DrawInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 265{ 266 MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>(); 267 uint32_t vertexStart = stream->fetch<uint32_t>(); 268 uint32_t vertexCount = stream->fetch<uint32_t>(); 269 uint32_t instances = stream->fetch<uint32_t>(); 270 [encoder drawPrimitives:primitiveType 271 vertexStart:vertexStart 272 vertexCount:vertexCount 273 instanceCount:instances]; 274} 275 276void DrawInstancedBaseInstanceCmd(id<MTLRenderCommandEncoder> encoder, 277 IntermediateCommandStream *stream) 278{ 279 MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>(); 280 uint32_t vertexStart = stream->fetch<uint32_t>(); 281 uint32_t vertexCount = stream->fetch<uint32_t>(); 282 uint32_t instances = stream->fetch<uint32_t>(); 283 uint32_t baseInstance = stream->fetch<uint32_t>(); 284 [encoder drawPrimitives:primitiveType 285 vertexStart:vertexStart 286 vertexCount:vertexCount 287 instanceCount:instances 288 baseInstance:baseInstance]; 289} 290 291void DrawIndexedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 292{ 293 MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>(); 294 uint32_t indexCount = stream->fetch<uint32_t>(); 295 MTLIndexType indexType = stream->fetch<MTLIndexType>(); 296 id<MTLBuffer> indexBuffer = stream->fetch<id<MTLBuffer>>(); 297 size_t bufferOffset = stream->fetch<size_t>(); 298 [encoder drawIndexedPrimitives:primitiveType 299 indexCount:indexCount 300 indexType:indexType 301 indexBuffer:indexBuffer 302 indexBufferOffset:bufferOffset]; 303 [indexBuffer ANGLE_MTL_RELEASE]; 304} 305 306void DrawIndexedInstancedCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 307{ 308 MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>(); 309 uint32_t indexCount = stream->fetch<uint32_t>(); 310 MTLIndexType indexType = stream->fetch<MTLIndexType>(); 311 id<MTLBuffer> indexBuffer = stream->fetch<id<MTLBuffer>>(); 312 size_t bufferOffset = stream->fetch<size_t>(); 313 uint32_t instances = stream->fetch<uint32_t>(); 314 [encoder drawIndexedPrimitives:primitiveType 315 indexCount:indexCount 316 indexType:indexType 317 indexBuffer:indexBuffer 318 indexBufferOffset:bufferOffset 319 instanceCount:instances]; 320 [indexBuffer ANGLE_MTL_RELEASE]; 321} 322 323void DrawIndexedInstancedBaseVertexBaseInstanceCmd(id<MTLRenderCommandEncoder> encoder, 324 IntermediateCommandStream *stream) 325{ 326 MTLPrimitiveType primitiveType = stream->fetch<MTLPrimitiveType>(); 327 uint32_t indexCount = stream->fetch<uint32_t>(); 328 MTLIndexType indexType = stream->fetch<MTLIndexType>(); 329 id<MTLBuffer> indexBuffer = stream->fetch<id<MTLBuffer>>(); 330 size_t bufferOffset = stream->fetch<size_t>(); 331 uint32_t instances = stream->fetch<uint32_t>(); 332 uint32_t baseVertex = stream->fetch<uint32_t>(); 333 uint32_t baseInstance = stream->fetch<uint32_t>(); 334 [encoder drawIndexedPrimitives:primitiveType 335 indexCount:indexCount 336 indexType:indexType 337 indexBuffer:indexBuffer 338 indexBufferOffset:bufferOffset 339 instanceCount:instances 340 baseVertex:baseVertex 341 baseInstance:baseInstance]; 342 [indexBuffer ANGLE_MTL_RELEASE]; 343} 344 345void SetVisibilityResultModeCmd(id<MTLRenderCommandEncoder> encoder, 346 IntermediateCommandStream *stream) 347{ 348 MTLVisibilityResultMode mode = stream->fetch<MTLVisibilityResultMode>(); 349 size_t offset = stream->fetch<size_t>(); 350 [encoder setVisibilityResultMode:mode offset:offset]; 351} 352 353void UseResourceCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 354{ 355 id<MTLResource> resource = stream->fetch<id<MTLResource>>(); 356 MTLResourceUsage usage = stream->fetch<MTLResourceUsage>(); 357 mtl::RenderStages stages = stream->fetch<mtl::RenderStages>(); 358 ANGLE_UNUSED_VARIABLE(stages); 359#if defined(__IPHONE_13_0) || defined(__MAC_10_15) 360 if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0)) 361 { 362 [encoder useResource:resource usage:usage stages:stages]; 363 } 364 else 365#endif 366 { 367 [encoder useResource:resource usage:usage]; 368 } 369 [resource ANGLE_MTL_RELEASE]; 370} 371 372void MemoryBarrierWithResourceCmd(id<MTLRenderCommandEncoder> encoder, 373 IntermediateCommandStream *stream) 374{ 375 id<MTLResource> resource = stream->fetch<id<MTLResource>>(); 376 mtl::RenderStages after = stream->fetch<mtl::RenderStages>(); 377 mtl::RenderStages before = stream->fetch<mtl::RenderStages>(); 378 ANGLE_UNUSED_VARIABLE(after); 379 ANGLE_UNUSED_VARIABLE(before); 380#if defined(__MAC_10_14) && (TARGET_OS_OSX || TARGET_OS_MACCATALYST) 381 if (ANGLE_APPLE_AVAILABLE_XC(10.14, 13.0)) 382 { 383 [encoder memoryBarrierWithResources:&resource 384 count:1 385 afterStages:after 386 beforeStages:before]; 387 } 388#endif 389 [resource ANGLE_MTL_RELEASE]; 390} 391 392void InsertDebugsignCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 393{ 394 NSString *label = stream->fetch<NSString *>(); 395 [encoder insertDebugSignpost:label]; 396 [label ANGLE_MTL_RELEASE]; 397} 398 399void PushDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 400{ 401 NSString *label = stream->fetch<NSString *>(); 402 [encoder pushDebugGroup:label]; 403 [label ANGLE_MTL_RELEASE]; 404} 405 406void PopDebugGroupCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream) 407{ 408 [encoder popDebugGroup]; 409} 410 411// Command encoder mapping 412#define ANGLE_MTL_CMD_MAP(CMD) CMD##Cmd, 413 414using CommandEncoderFunc = void (*)(id<MTLRenderCommandEncoder>, IntermediateCommandStream *); 415constexpr CommandEncoderFunc gCommandEncoders[] = {ANGLE_MTL_CMD_X(ANGLE_MTL_CMD_MAP)}; 416 417NSString *cppLabelToObjC(const std::string &marker) 418{ 419 NSString *label = [NSString stringWithUTF8String:marker.c_str()]; 420 if (!label) 421 { 422 // This can happen if the string is not a valid ascii string. 423 label = @"Invalid ASCII string"; 424 } 425 return label; 426} 427} 428 429// CommandQueue implementation 430void CommandQueue::reset() 431{ 432 finishAllCommands(); 433 ParentClass::reset(); 434} 435 436void CommandQueue::set(id<MTLCommandQueue> metalQueue) 437{ 438 finishAllCommands(); 439 440 ParentClass::set(metalQueue); 441} 442 443void CommandQueue::finishAllCommands() 444{ 445 std::deque<CmdBufferQueueEntry> commandBuffers; 446 { 447 std::lock_guard<std::mutex> lg(mLock); 448 mMetalCmdBuffers.swap(commandBuffers); 449 } 450 for (CmdBufferQueueEntry &entry : commandBuffers) 451 { 452 [entry.buffer waitUntilCompleted]; 453 } 454} 455 456void CommandQueue::ensureResourceReadyForCPU(const ResourceRef &resource) 457{ 458 if (!resource) 459 { 460 return; 461 } 462 463 ensureResourceReadyForCPU(resource.get()); 464} 465 466void CommandQueue::ensureResourceReadyForCPU(Resource *resource) 467{ 468 mLock.lock(); 469 while (isResourceBeingUsedByGPU(resource) && !mMetalCmdBuffers.empty()) 470 { 471 CmdBufferQueueEntry metalBufferEntry = mMetalCmdBuffers.front(); 472 mMetalCmdBuffers.pop_front(); 473 mLock.unlock(); 474 475 ANGLE_MTL_LOG("Waiting for MTLCommandBuffer %llu:%p", metalBufferEntry.serial, 476 metalBufferEntry.buffer.get()); 477 [metalBufferEntry.buffer waitUntilCompleted]; 478 479 mLock.lock(); 480 } 481 mLock.unlock(); 482 483 // This can happen if the resource is read then write in the same command buffer. 484 // So it is the responsitibily of outer code to ensure the command buffer is commit before 485 // the resource can be read or written again 486 ASSERT(!isResourceBeingUsedByGPU(resource)); 487} 488 489bool CommandQueue::isResourceBeingUsedByGPU(const Resource *resource) const 490{ 491 if (!resource) 492 { 493 return false; 494 } 495 496 return mCompletedBufferSerial.load(std::memory_order_relaxed) < 497 resource->getCommandBufferQueueSerial(); 498} 499 500bool CommandQueue::resourceHasPendingWorks(const Resource *resource) const 501{ 502 if (!resource) 503 { 504 return false; 505 } 506 507 return mCommittedBufferSerial.load(std::memory_order_relaxed) < 508 resource->getCommandBufferQueueSerial(); 509} 510 511AutoObjCPtr<id<MTLCommandBuffer>> CommandQueue::makeMetalCommandBuffer(uint64_t *queueSerialOut) 512{ 513 ANGLE_MTL_OBJC_SCOPE 514 { 515 AutoObjCPtr<id<MTLCommandBuffer>> metalCmdBuffer = [get() commandBuffer]; 516 517 std::lock_guard<std::mutex> lg(mLock); 518 519 uint64_t serial = mQueueSerialCounter++; 520 521 mMetalCmdBuffers.push_back({metalCmdBuffer, serial}); 522 523 ANGLE_MTL_LOG("Created MTLCommandBuffer %llu:%p", serial, metalCmdBuffer.get()); 524 525 [metalCmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> buf) { 526 onCommandBufferCompleted(buf, serial); 527 }]; 528 529 ASSERT(metalCmdBuffer); 530 531 *queueSerialOut = serial; 532 533 return metalCmdBuffer; 534 } 535} 536 537void CommandQueue::onCommandBufferCommitted(id<MTLCommandBuffer> buf, uint64_t serial) 538{ 539 std::lock_guard<std::mutex> lg(mLock); 540 541 ANGLE_MTL_LOG("Committed MTLCommandBuffer %llu:%p", serial, buf); 542 ++mLastCommittedSerial; 543 ASSERT(serial == mLastCommittedSerial && "Verify that CommandBuffers are submitted in order"); 544 545 mCommittedBufferSerial.store( 546 std::max(mCommittedBufferSerial.load(std::memory_order_relaxed), serial), 547 std::memory_order_relaxed); 548} 549 550void CommandQueue::onCommandBufferCompleted(id<MTLCommandBuffer> buf, uint64_t serial) 551{ 552 std::lock_guard<std::mutex> lg(mLock); 553 554 ANGLE_MTL_LOG("Completed MTLCommandBuffer %llu:%p", serial, buf); 555 556 if (mCompletedBufferSerial >= serial) 557 { 558 // Already handled. 559 return; 560 } 561 562 while (!mMetalCmdBuffers.empty() && mMetalCmdBuffers.front().serial <= serial) 563 { 564 CmdBufferQueueEntry metalBufferEntry = mMetalCmdBuffers.front(); 565 ANGLE_UNUSED_VARIABLE(metalBufferEntry); 566 ANGLE_MTL_LOG("Popped MTLCommandBuffer %llu:%p", metalBufferEntry.serial, 567 metalBufferEntry.buffer.get()); 568 569 mMetalCmdBuffers.pop_front(); 570 } 571 572 mCompletedBufferSerial.store( 573 std::max(mCompletedBufferSerial.load(std::memory_order_relaxed), serial), 574 std::memory_order_relaxed); 575} 576 577// CommandBuffer implementation 578CommandBuffer::CommandBuffer(CommandQueue *cmdQueue) : mCmdQueue(*cmdQueue) {} 579 580CommandBuffer::~CommandBuffer() 581{ 582 commit(WaitUntilFinished); 583 cleanup(); 584} 585 586bool CommandBuffer::ready() const 587{ 588 std::lock_guard<std::mutex> lg(mLock); 589 590 return readyImpl(); 591} 592 593void CommandBuffer::commit(CommandBufferFinishOperation operation) 594{ 595 std::lock_guard<std::mutex> lg(mLock); 596 if (commitImpl()) 597 { 598 if (operation == WaitUntilScheduled) 599 { 600 [get() waitUntilScheduled]; 601 } 602 else if (operation == WaitUntilFinished) 603 { 604 [get() waitUntilCompleted]; 605 } 606 } 607} 608 609void CommandBuffer::present(id<CAMetalDrawable> presentationDrawable) 610{ 611 [get() presentDrawable:presentationDrawable]; 612} 613 614void CommandBuffer::setResourceUsedByCommandBuffer(const ResourceRef &resource) 615{ 616 if (resource) 617 { 618 auto result = mResourceList.insert(resource->getID()); 619 // If we were able to add a unique Metal resource ID to the list, count it. 620 // 621 // Note that we store Metal IDs here, properly retained in non-ARC environments, rather than 622 // the ResourceRefs. There are some assumptions in TextureMtl in particular about weak refs 623 // to temporary textures being cleared out eagerly. Holding on to additional references here 624 // implies that that texture is still being used, and would require additional code to clear 625 // out temporary render targets upon texture redefinition. 626 if (result.second) 627 { 628 [resource->getID() ANGLE_MTL_RETAIN]; 629 mWorkingResourceSize += resource->estimatedByteSize(); 630 } 631 } 632} 633 634void CommandBuffer::clearResourceListAndSize() 635{ 636 for (const id &metalID : mResourceList) 637 { 638 [metalID ANGLE_MTL_RELEASE]; 639 } 640 mResourceList.clear(); 641 mWorkingResourceSize = 0; 642} 643 644void CommandBuffer::setWriteDependency(const ResourceRef &resource) 645{ 646 if (!resource) 647 { 648 return; 649 } 650 651 std::lock_guard<std::mutex> lg(mLock); 652 653 if (!readyImpl()) 654 { 655 return; 656 } 657 658 resource->setUsedByCommandBufferWithQueueSerial(mQueueSerial, true); 659 setResourceUsedByCommandBuffer(resource); 660} 661 662void CommandBuffer::setReadDependency(const ResourceRef &resource) 663{ 664 setReadDependency(resource.get()); 665 setResourceUsedByCommandBuffer(resource); 666} 667 668void CommandBuffer::setReadDependency(Resource *resource) 669{ 670 if (!resource) 671 { 672 return; 673 } 674 675 std::lock_guard<std::mutex> lg(mLock); 676 677 if (!readyImpl()) 678 { 679 return; 680 } 681 682 resource->setUsedByCommandBufferWithQueueSerial(mQueueSerial, false); 683} 684 685bool CommandBuffer::needsFlushForDrawCallLimits() const 686{ 687 return mWorkingResourceSize > kMaximumResidentMemorySizeInBytes; 688} 689 690void CommandBuffer::restart() 691{ 692 uint64_t serial = 0; 693 AutoObjCPtr<id<MTLCommandBuffer>> metalCmdBuffer = mCmdQueue.makeMetalCommandBuffer(&serial); 694 695 std::lock_guard<std::mutex> lg(mLock); 696 697 set(metalCmdBuffer); 698 mQueueSerial = serial; 699 mCommitted = false; 700 701 for (std::string &marker : mDebugGroups) 702 { 703 pushDebugGroupImpl(marker); 704 } 705 clearResourceListAndSize(); 706 ASSERT(metalCmdBuffer); 707} 708 709void CommandBuffer::insertDebugSign(const std::string &marker) 710{ 711 mtl::CommandEncoder *currentEncoder = mActiveCommandEncoder; 712 if (currentEncoder) 713 { 714 ANGLE_MTL_OBJC_SCOPE 715 { 716 NSString *label = cppLabelToObjC(marker); 717 currentEncoder->insertDebugSign(label); 718 } 719 } 720 else 721 { 722 mPendingDebugSigns.push_back(marker); 723 } 724} 725 726void CommandBuffer::pushDebugGroup(const std::string &marker) 727{ 728 mDebugGroups.push_back(marker); 729 730 std::lock_guard<std::mutex> lg(mLock); 731 732 if (readyImpl()) 733 { 734 pushDebugGroupImpl(marker); 735 } 736} 737 738void CommandBuffer::popDebugGroup() 739{ 740 if (!mDebugGroups.empty()) 741 { 742 mDebugGroups.pop_back(); 743 } 744 745 std::lock_guard<std::mutex> lg(mLock); 746 747 if (readyImpl()) 748 { 749 return; 750 } 751} 752 753void CommandBuffer::queueEventSignal(const mtl::SharedEventRef &event, uint64_t value) 754{ 755 std::lock_guard<std::mutex> lg(mLock); 756 757 ASSERT(readyImpl()); 758 759 if (mActiveCommandEncoder && mActiveCommandEncoder->getType() == CommandEncoder::RENDER) 760 { 761 // We cannot set event when there is an active render pass, defer the setting until the 762 // pass end. 763 mPendingSignalEvents.push_back({event, value}); 764 } 765 else 766 { 767 setEventImpl(event, value); 768 } 769} 770 771void CommandBuffer::serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value) 772{ 773 std::lock_guard<std::mutex> lg(mLock); 774 ASSERT(readyImpl()); 775 776 waitEventImpl(event, value); 777} 778 779/** private use only */ 780void CommandBuffer::set(id<MTLCommandBuffer> metalBuffer) 781{ 782 ParentClass::set(metalBuffer); 783} 784 785void CommandBuffer::setActiveCommandEncoder(CommandEncoder *encoder) 786{ 787 mActiveCommandEncoder = encoder; 788 for (std::string &marker : mPendingDebugSigns) 789 { 790 ANGLE_MTL_OBJC_SCOPE 791 { 792 NSString *label = cppLabelToObjC(marker); 793 encoder->insertDebugSign(label); 794 } 795 } 796 mPendingDebugSigns.clear(); 797} 798 799void CommandBuffer::invalidateActiveCommandEncoder(CommandEncoder *encoder) 800{ 801 if (mActiveCommandEncoder == encoder) 802 { 803 mActiveCommandEncoder = nullptr; 804 805 // No active command encoder, we can safely encode event signalling now. 806 setPendingEvents(); 807 } 808} 809 810void CommandBuffer::cleanup() 811{ 812 mActiveCommandEncoder = nullptr; 813 814 ParentClass::set(nil); 815} 816 817bool CommandBuffer::readyImpl() const 818{ 819 if (!ParentClass::valid()) 820 { 821 return false; 822 } 823 824 return !mCommitted; 825} 826 827bool CommandBuffer::commitImpl() 828{ 829 if (!readyImpl()) 830 { 831 return false; 832 } 833 834 // End the current encoder 835 forceEndingCurrentEncoder(); 836 837 // Encoding any pending event's signalling. 838 setPendingEvents(); 839 840 // Notify command queue 841 mCmdQueue.onCommandBufferCommitted(get(), mQueueSerial); 842 843 // Do the actual commit 844 [get() enqueue]; 845 [get() commit]; 846 // Reset the working resource set. 847 clearResourceListAndSize(); 848 mCommitted = true; 849 return true; 850} 851 852void CommandBuffer::forceEndingCurrentEncoder() 853{ 854 if (mActiveCommandEncoder) 855 { 856 mActiveCommandEncoder->endEncoding(); 857 mActiveCommandEncoder = nullptr; 858 } 859} 860 861void CommandBuffer::setPendingEvents() 862{ 863#if ANGLE_MTL_EVENT_AVAILABLE 864 for (const std::pair<mtl::SharedEventRef, uint64_t> &eventEntry : mPendingSignalEvents) 865 { 866 setEventImpl(eventEntry.first, eventEntry.second); 867 } 868 mPendingSignalEvents.clear(); 869#endif 870} 871 872void CommandBuffer::setEventImpl(const mtl::SharedEventRef &event, uint64_t value) 873{ 874#if ANGLE_MTL_EVENT_AVAILABLE 875 ASSERT(!mActiveCommandEncoder || mActiveCommandEncoder->getType() != CommandEncoder::RENDER); 876 // For non-render command encoder, we can safely end it, so that we can encode a signal 877 // event. 878 forceEndingCurrentEncoder(); 879 880 [get() encodeSignalEvent:event value:value]; 881#else 882 UNIMPLEMENTED(); 883 UNREACHABLE(); 884#endif // #if ANGLE_MTL_EVENT_AVAILABLE 885} 886 887void CommandBuffer::waitEventImpl(const mtl::SharedEventRef &event, uint64_t value) 888{ 889#if ANGLE_MTL_EVENT_AVAILABLE 890 ASSERT(!mActiveCommandEncoder || mActiveCommandEncoder->getType() != CommandEncoder::RENDER); 891 892 forceEndingCurrentEncoder(); 893 894 // Encoding any pending event's signalling. 895 setPendingEvents(); 896 897 [get() encodeWaitForEvent:event value:value]; 898#else 899 UNIMPLEMENTED(); 900 UNREACHABLE(); 901#endif // #if ANGLE_MTL_EVENT_AVAILABLE 902} 903 904void CommandBuffer::pushDebugGroupImpl(const std::string &marker) 905{ 906 ANGLE_MTL_OBJC_SCOPE 907 { 908 NSString *label = cppLabelToObjC(marker); 909 [get() pushDebugGroup:label]; 910 911 if (mActiveCommandEncoder) 912 { 913 mActiveCommandEncoder->pushDebugGroup(label); 914 } 915 } 916} 917 918void CommandBuffer::popDebugGroupImpl() 919{ 920 if (mActiveCommandEncoder) 921 { 922 mActiveCommandEncoder->popDebugGroup(); 923 } 924 [get() popDebugGroup]; 925} 926 927// CommandEncoder implementation 928CommandEncoder::CommandEncoder(CommandBuffer *cmdBuffer, Type type) 929 : mType(type), mCmdBuffer(*cmdBuffer) 930{} 931 932CommandEncoder::~CommandEncoder() 933{ 934 reset(); 935} 936 937void CommandEncoder::endEncoding() 938{ 939 [get() endEncoding]; 940 reset(); 941} 942 943void CommandEncoder::reset() 944{ 945 ParentClass::reset(); 946 947 mCmdBuffer.invalidateActiveCommandEncoder(this); 948} 949 950void CommandEncoder::set(id<MTLCommandEncoder> metalCmdEncoder) 951{ 952 ParentClass::set(metalCmdEncoder); 953 954 // Set this as active encoder 955 cmdBuffer().setActiveCommandEncoder(this); 956} 957 958CommandEncoder &CommandEncoder::markResourceBeingWrittenByGPU(const BufferRef &buffer) 959{ 960 cmdBuffer().setWriteDependency(buffer); 961 return *this; 962} 963 964CommandEncoder &CommandEncoder::markResourceBeingWrittenByGPU(const TextureRef &texture) 965{ 966 cmdBuffer().setWriteDependency(texture); 967 return *this; 968} 969 970void CommandEncoder::pushDebugGroup(NSString *label) 971{ 972 // Default implementation 973 [get() pushDebugGroup:label]; 974} 975 976void CommandEncoder::popDebugGroup() 977{ 978 // Default implementation 979 [get() popDebugGroup]; 980} 981 982void CommandEncoder::insertDebugSign(NSString *label) 983{ 984 insertDebugSignImpl(label); 985} 986 987void CommandEncoder::insertDebugSignImpl(NSString *label) 988{ 989 // Default implementation 990 [get() insertDebugSignpost:label]; 991} 992 993// RenderCommandEncoderShaderStates implementation 994RenderCommandEncoderShaderStates::RenderCommandEncoderShaderStates() 995{ 996 reset(); 997} 998 999void RenderCommandEncoderShaderStates::reset() 1000{ 1001 for (id<MTLBuffer> &buffer : buffers) 1002 { 1003 buffer = nil; 1004 } 1005 1006 for (uint32_t &offset : bufferOffsets) 1007 { 1008 offset = 0; 1009 } 1010 1011 for (id<MTLSamplerState> &sampler : samplers) 1012 { 1013 sampler = nil; 1014 } 1015 1016 for (Optional<std::pair<float, float>> &lodClampRange : samplerLodClamps) 1017 { 1018 lodClampRange.reset(); 1019 } 1020 1021 for (id<MTLTexture> &texture : textures) 1022 { 1023 texture = nil; 1024 } 1025} 1026 1027// RenderCommandEncoderStates implementation 1028RenderCommandEncoderStates::RenderCommandEncoderStates() 1029{ 1030 reset(); 1031} 1032 1033void RenderCommandEncoderStates::reset() 1034{ 1035 renderPipeline = nil; 1036 1037 triangleFillMode = MTLTriangleFillModeFill; 1038 winding = MTLWindingClockwise; 1039 cullMode = MTLCullModeNone; 1040 1041 depthStencilState = nil; 1042 depthBias = depthSlopeScale = depthClamp = 0; 1043 1044 stencilFrontRef = stencilBackRef = 0; 1045 1046 viewport.reset(); 1047 scissorRect.reset(); 1048 1049 blendColor = {0, 0, 0, 0}; 1050 1051 for (RenderCommandEncoderShaderStates &shaderStates : perShaderStates) 1052 { 1053 shaderStates.reset(); 1054 } 1055 1056 visibilityResultMode = MTLVisibilityResultModeDisabled; 1057 visibilityResultBufferOffset = 0; 1058} 1059 1060// RenderCommandEncoder implemtation 1061RenderCommandEncoder::RenderCommandEncoder(CommandBuffer *cmdBuffer, 1062 const OcclusionQueryPool &queryPool) 1063 : CommandEncoder(cmdBuffer, RENDER), mOcclusionQueryPool(queryPool) 1064{ 1065 ANGLE_MTL_OBJC_SCOPE 1066 { 1067 mCachedRenderPassDescObjC = [MTLRenderPassDescriptor renderPassDescriptor]; 1068 } 1069 1070 static_assert(sizeof(uint8_t) == sizeof(CmdType), "CmdType was expected to be 8 bit"); 1071 for (gl::ShaderType shaderType : gl::AllShaderTypes()) 1072 { 1073 mSetBufferCmds[shaderType] = static_cast<uint8_t>(CmdType::Invalid); 1074 mSetBytesCmds[shaderType] = static_cast<uint8_t>(CmdType::Invalid); 1075 mSetTextureCmds[shaderType] = static_cast<uint8_t>(CmdType::Invalid); 1076 mSetSamplerCmds[shaderType] = static_cast<uint8_t>(CmdType::Invalid); 1077 } 1078 1079 mSetBufferCmds[gl::ShaderType::Vertex] = static_cast<uint8_t>(CmdType::SetVertexBuffer); 1080 mSetBufferCmds[gl::ShaderType::Fragment] = static_cast<uint8_t>(CmdType::SetFragmentBuffer); 1081 1082 mSetBufferOffsetCmds[gl::ShaderType::Vertex] = 1083 static_cast<uint8_t>(CmdType::SetVertexBufferOffset); 1084 mSetBufferOffsetCmds[gl::ShaderType::Fragment] = 1085 static_cast<uint8_t>(CmdType::SetFragmentBufferOffset); 1086 1087 mSetBytesCmds[gl::ShaderType::Vertex] = static_cast<uint8_t>(CmdType::SetVertexBytes); 1088 mSetBytesCmds[gl::ShaderType::Fragment] = static_cast<uint8_t>(CmdType::SetFragmentBytes); 1089 1090 mSetTextureCmds[gl::ShaderType::Vertex] = static_cast<uint8_t>(CmdType::SetVertexTexture); 1091 mSetTextureCmds[gl::ShaderType::Fragment] = static_cast<uint8_t>(CmdType::SetFragmentTexture); 1092 1093 mSetSamplerCmds[gl::ShaderType::Vertex] = static_cast<uint8_t>(CmdType::SetVertexSamplerState); 1094 mSetSamplerCmds[gl::ShaderType::Fragment] = 1095 static_cast<uint8_t>(CmdType::SetFragmentSamplerState); 1096} 1097RenderCommandEncoder::~RenderCommandEncoder() {} 1098 1099void RenderCommandEncoder::reset() 1100{ 1101 CommandEncoder::reset(); 1102 mRecording = false; 1103 mPipelineStateSet = false; 1104 mCommands.clear(); 1105} 1106 1107void RenderCommandEncoder::finalizeLoadStoreAction( 1108 MTLRenderPassAttachmentDescriptor *objCRenderPassAttachment) 1109{ 1110 if (!objCRenderPassAttachment.texture) 1111 { 1112 objCRenderPassAttachment.loadAction = MTLLoadActionDontCare; 1113 objCRenderPassAttachment.storeAction = MTLStoreActionDontCare; 1114 objCRenderPassAttachment.resolveTexture = nil; 1115 return; 1116 } 1117 1118 if (objCRenderPassAttachment.resolveTexture) 1119 { 1120 if (objCRenderPassAttachment.storeAction == MTLStoreActionStore) 1121 { 1122 // NOTE(hqle): Currently if the store action with implicit MS texture is MTLStoreAction, 1123 // it is automatically convert to store and resolve action. It might introduce 1124 // unnecessary overhead. 1125 // Consider an improvement such as only store the MS texture, and resolve only at 1126 // the end of real render pass (not render pass the was interrupted by compute pass) 1127 // or before glBlitFramebuffer operation starts. 1128 objCRenderPassAttachment.storeAction = MTLStoreActionStoreAndMultisampleResolve; 1129 } 1130 else if (objCRenderPassAttachment.storeAction == MTLStoreActionDontCare) 1131 { 1132 // Ignore resolve texture if the store action is not a resolve action. 1133 objCRenderPassAttachment.resolveTexture = nil; 1134 } 1135 } 1136 1137 if (objCRenderPassAttachment.storeAction == MTLStoreActionUnknown) 1138 { 1139 // If storeAction hasn't been set for this attachment, we set to dontcare. 1140 objCRenderPassAttachment.storeAction = MTLStoreActionDontCare; 1141 } 1142} 1143 1144void RenderCommandEncoder::endEncoding() 1145{ 1146 endEncodingImpl(true); 1147} 1148 1149void RenderCommandEncoder::endEncodingImpl(bool considerDiscardSimulation) 1150{ 1151 if (!valid()) 1152 return; 1153 1154 // Last minute correcting the store options. 1155 MTLRenderPassDescriptor *objCRenderPassDesc = mCachedRenderPassDescObjC.get(); 1156 for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i) 1157 { 1158 // Update store action set between restart() and endEncoding() 1159 objCRenderPassDesc.colorAttachments[i].storeAction = 1160 mRenderPassDesc.colorAttachments[i].storeAction; 1161 finalizeLoadStoreAction(objCRenderPassDesc.colorAttachments[i]); 1162 } 1163 1164 // Update store action set between restart() and endEncoding() 1165 objCRenderPassDesc.depthAttachment.storeAction = mRenderPassDesc.depthAttachment.storeAction; 1166 finalizeLoadStoreAction(objCRenderPassDesc.depthAttachment); 1167 1168 // Update store action set between restart() and endEncoding() 1169 objCRenderPassDesc.stencilAttachment.storeAction = 1170 mRenderPassDesc.stencilAttachment.storeAction; 1171 finalizeLoadStoreAction(objCRenderPassDesc.stencilAttachment); 1172 1173 // Set visibility result buffer 1174 if (mOcclusionQueryPool.getNumRenderPassAllocatedQueries()) 1175 { 1176 objCRenderPassDesc.visibilityResultBuffer = 1177 mOcclusionQueryPool.getRenderPassVisibilityPoolBuffer()->get(); 1178 } 1179 else 1180 { 1181 objCRenderPassDesc.visibilityResultBuffer = nil; 1182 } 1183 1184 // Encode the actual encoder 1185 encodeMetalEncoder(); 1186 1187 CommandEncoder::endEncoding(); 1188 1189#if ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER 1190 if (considerDiscardSimulation) 1191 { 1192 simulateDiscardFramebuffer(); 1193 } 1194#endif 1195 1196 // reset state 1197 mRenderPassDesc = RenderPassDesc(); 1198 mStateCache.reset(); 1199} 1200 1201inline void RenderCommandEncoder::initAttachmentWriteDependencyAndScissorRect( 1202 const RenderPassAttachmentDesc &attachment) 1203{ 1204 TextureRef texture = attachment.texture; 1205 if (texture) 1206 { 1207 cmdBuffer().setWriteDependency(texture); 1208 1209 const MipmapNativeLevel &mipLevel = attachment.level; 1210 1211 mRenderPassMaxScissorRect.width = 1212 std::min<NSUInteger>(mRenderPassMaxScissorRect.width, texture->width(mipLevel)); 1213 mRenderPassMaxScissorRect.height = 1214 std::min<NSUInteger>(mRenderPassMaxScissorRect.height, texture->height(mipLevel)); 1215 } 1216} 1217 1218inline void RenderCommandEncoder::initWriteDependency(const TextureRef &texture) 1219{ 1220 if (texture) 1221 { 1222 cmdBuffer().setWriteDependency(texture); 1223 } 1224} 1225 1226void RenderCommandEncoder::simulateDiscardFramebuffer() 1227{ 1228 // Simulate true framebuffer discard operation by clearing the framebuffer 1229#if ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER 1230 std::random_device rd; // Will be used to obtain a seed for the random number engine 1231 std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() 1232 std::uniform_real_distribution<float> dis(0.0, 1.0f); 1233 bool hasDiscard = false; 1234 for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i) 1235 { 1236 if (mRenderPassDesc.colorAttachments[i].storeAction == MTLStoreActionDontCare) 1237 { 1238 hasDiscard = true; 1239 mRenderPassDesc.colorAttachments[i].loadAction = MTLLoadActionClear; 1240 mRenderPassDesc.colorAttachments[i].clearColor = 1241 MTLClearColorMake(dis(gen), dis(gen), dis(gen), dis(gen)); 1242 } 1243 else 1244 { 1245 mRenderPassDesc.colorAttachments[i].loadAction = MTLLoadActionLoad; 1246 } 1247 } 1248 1249 if (mRenderPassDesc.depthAttachment.storeAction == MTLStoreActionDontCare) 1250 { 1251 hasDiscard = true; 1252 mRenderPassDesc.depthAttachment.loadAction = MTLLoadActionClear; 1253 mRenderPassDesc.depthAttachment.clearDepth = dis(gen); 1254 } 1255 else 1256 { 1257 mRenderPassDesc.depthAttachment.loadAction = MTLLoadActionLoad; 1258 } 1259 1260 if (mRenderPassDesc.stencilAttachment.storeAction == MTLStoreActionDontCare) 1261 { 1262 hasDiscard = true; 1263 mRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionClear; 1264 mRenderPassDesc.stencilAttachment.clearStencil = rand(); 1265 } 1266 else 1267 { 1268 mRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionLoad; 1269 } 1270 1271 if (hasDiscard) 1272 { 1273 MTLRenderPassDescriptor tmpDesc = mRenderPassDesc; 1274 restart(tmpDesc); 1275 endEncodingImpl(false); 1276 } 1277#endif // ANGLE_MTL_SIMULATE_DISCARD_FRAMEBUFFER 1278} 1279 1280void RenderCommandEncoder::encodeMetalEncoder() 1281{ 1282 ANGLE_MTL_OBJC_SCOPE 1283 { 1284 ANGLE_MTL_LOG("Creating new render command encoder with desc: %@", 1285 [mCachedRenderPassDescObjC description]); 1286 1287 id<MTLRenderCommandEncoder> metalCmdEncoder = 1288 [cmdBuffer().get() renderCommandEncoderWithDescriptor:mCachedRenderPassDescObjC]; 1289 1290 set(metalCmdEncoder); 1291 1292 // Verify that it was created successfully 1293 ASSERT(get()); 1294 1295 // Work-around driver bug on iOS devices: stencil must be explicitly set to zero 1296 // even if the doc says the default value is already zero. 1297 [metalCmdEncoder setStencilReferenceValue:0]; 1298 1299 if (mLabel) 1300 { 1301 metalCmdEncoder.label = mLabel; 1302 } 1303 1304 while (mCommands.good()) 1305 { 1306 CmdType cmdType = mCommands.fetch<CmdType>(); 1307 CommandEncoderFunc encoder = gCommandEncoders[static_cast<int>(cmdType)]; 1308 encoder(metalCmdEncoder, &mCommands); 1309 } 1310 1311 mCommands.clear(); 1312 } 1313} 1314 1315RenderCommandEncoder &RenderCommandEncoder::restart(const RenderPassDesc &desc) 1316{ 1317 if (valid()) 1318 { 1319 if (mRenderPassDesc == desc) 1320 { 1321 // no change, skip 1322 return *this; 1323 } 1324 1325 // finish current encoder 1326 endEncoding(); 1327 } 1328 1329 if (!cmdBuffer().ready()) 1330 { 1331 reset(); 1332 return *this; 1333 } 1334 1335 mRenderPassDesc = desc; 1336 mRecording = true; 1337 mHasDrawCalls = false; 1338 mRenderPassMaxScissorRect = {.x = 0, 1339 .y = 0, 1340 .width = std::numeric_limits<NSUInteger>::max(), 1341 .height = std::numeric_limits<NSUInteger>::max()}; 1342 // mask writing dependency & set appropriate store options 1343 for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i) 1344 { 1345 initAttachmentWriteDependencyAndScissorRect(mRenderPassDesc.colorAttachments[i]); 1346 } 1347 1348 initAttachmentWriteDependencyAndScissorRect(mRenderPassDesc.depthAttachment); 1349 1350 initAttachmentWriteDependencyAndScissorRect(mRenderPassDesc.stencilAttachment); 1351 1352 // Convert to Objective-C descriptor 1353 mRenderPassDesc.convertToMetalDesc(mCachedRenderPassDescObjC); 1354 1355 // The actual Objective-C encoder will be created later in endEncoding(), we do so in order 1356 // to be able to sort the commands or do the preprocessing before the actual encoding. 1357 1358 // Since we defer the native encoder creation, we need to explicitly tell command buffer that 1359 // this object is the active encoder: 1360 cmdBuffer().setActiveCommandEncoder(this); 1361 1362 return *this; 1363} 1364 1365RenderCommandEncoder &RenderCommandEncoder::setRenderPipelineState(id<MTLRenderPipelineState> state) 1366{ 1367 mPipelineStateSet = true; 1368 if (mStateCache.renderPipeline == state) 1369 { 1370 return *this; 1371 } 1372 mStateCache.renderPipeline = state; 1373 1374 mCommands.push(CmdType::SetRenderPipelineState).push([state ANGLE_MTL_RETAIN]); 1375 1376 return *this; 1377} 1378RenderCommandEncoder &RenderCommandEncoder::setTriangleFillMode(MTLTriangleFillMode mode) 1379{ 1380 if (mStateCache.triangleFillMode == mode) 1381 { 1382 return *this; 1383 } 1384 mStateCache.triangleFillMode = mode; 1385 1386 mCommands.push(CmdType::SetTriangleFillMode).push(mode); 1387 1388 return *this; 1389} 1390RenderCommandEncoder &RenderCommandEncoder::setFrontFacingWinding(MTLWinding winding) 1391{ 1392 if (mStateCache.winding == winding) 1393 { 1394 return *this; 1395 } 1396 mStateCache.winding = winding; 1397 1398 mCommands.push(CmdType::SetFrontFacingWinding).push(winding); 1399 1400 return *this; 1401} 1402RenderCommandEncoder &RenderCommandEncoder::setCullMode(MTLCullMode mode) 1403{ 1404 if (mStateCache.cullMode == mode) 1405 { 1406 return *this; 1407 } 1408 mStateCache.cullMode = mode; 1409 1410 mCommands.push(CmdType::SetCullMode).push(mode); 1411 1412 return *this; 1413} 1414 1415RenderCommandEncoder &RenderCommandEncoder::setDepthStencilState(id<MTLDepthStencilState> state) 1416{ 1417 if (mStateCache.depthStencilState == state) 1418 { 1419 return *this; 1420 } 1421 mStateCache.depthStencilState = state; 1422 1423 mCommands.push(CmdType::SetDepthStencilState).push([state ANGLE_MTL_RETAIN]); 1424 1425 return *this; 1426} 1427RenderCommandEncoder &RenderCommandEncoder::setDepthBias(float depthBias, 1428 float slopeScale, 1429 float clamp) 1430{ 1431 if (mStateCache.depthBias == depthBias && mStateCache.depthSlopeScale == slopeScale && 1432 mStateCache.depthClamp == clamp) 1433 { 1434 return *this; 1435 } 1436 mStateCache.depthBias = depthBias; 1437 mStateCache.depthSlopeScale = slopeScale; 1438 mStateCache.depthClamp = clamp; 1439 1440 mCommands.push(CmdType::SetDepthBias).push(depthBias).push(slopeScale).push(clamp); 1441 1442 return *this; 1443} 1444RenderCommandEncoder &RenderCommandEncoder::setStencilRefVals(uint32_t frontRef, uint32_t backRef) 1445{ 1446 // Metal has some bugs when reference values are larger than 0xff 1447 ASSERT(frontRef == (frontRef & kStencilMaskAll)); 1448 ASSERT(backRef == (backRef & kStencilMaskAll)); 1449 1450 if (mStateCache.stencilFrontRef == frontRef && mStateCache.stencilBackRef == backRef) 1451 { 1452 return *this; 1453 } 1454 mStateCache.stencilFrontRef = frontRef; 1455 mStateCache.stencilBackRef = backRef; 1456 1457 mCommands.push(CmdType::SetStencilRefVals).push(frontRef).push(backRef); 1458 1459 return *this; 1460} 1461 1462RenderCommandEncoder &RenderCommandEncoder::setStencilRefVal(uint32_t ref) 1463{ 1464 return setStencilRefVals(ref, ref); 1465} 1466 1467RenderCommandEncoder &RenderCommandEncoder::setViewport(const MTLViewport &viewport) 1468{ 1469 if (mStateCache.viewport.valid() && mStateCache.viewport.value() == viewport) 1470 { 1471 return *this; 1472 } 1473 mStateCache.viewport = viewport; 1474 1475 mCommands.push(CmdType::SetViewport).push(viewport); 1476 1477 return *this; 1478} 1479 1480RenderCommandEncoder &RenderCommandEncoder::setScissorRect(const MTLScissorRect &rect) 1481{ 1482 NSUInteger clampedWidth = 1483 rect.x > mRenderPassMaxScissorRect.width ? 0 : mRenderPassMaxScissorRect.width - rect.x; 1484 NSUInteger clampedHeight = 1485 rect.y > mRenderPassMaxScissorRect.height ? 0 : mRenderPassMaxScissorRect.height - rect.y; 1486 1487 MTLScissorRect clampedRect = {rect.x, rect.y, std::min(rect.width, clampedWidth), 1488 std::min(rect.height, clampedHeight)}; 1489 1490 if (mStateCache.scissorRect.valid() && mStateCache.scissorRect.value() == clampedRect) 1491 { 1492 return *this; 1493 } 1494 1495 mStateCache.scissorRect = clampedRect; 1496 1497 mCommands.push(CmdType::SetScissorRect).push(clampedRect); 1498 1499 return *this; 1500} 1501 1502RenderCommandEncoder &RenderCommandEncoder::setBlendColor(float r, float g, float b, float a) 1503{ 1504 if (mStateCache.blendColor[0] == r && mStateCache.blendColor[1] == g && 1505 mStateCache.blendColor[2] == b && mStateCache.blendColor[3] == a) 1506 { 1507 return *this; 1508 } 1509 mStateCache.blendColor[0] = r; 1510 mStateCache.blendColor[1] = g; 1511 mStateCache.blendColor[2] = b; 1512 mStateCache.blendColor[3] = a; 1513 1514 mCommands.push(CmdType::SetBlendColor).push(r).push(g).push(b).push(a); 1515 1516 return *this; 1517} 1518 1519RenderCommandEncoder &RenderCommandEncoder::setBuffer(gl::ShaderType shaderType, 1520 const BufferRef &buffer, 1521 uint32_t offset, 1522 uint32_t index) 1523{ 1524 if (index >= kMaxShaderBuffers) 1525 { 1526 return *this; 1527 } 1528 1529 cmdBuffer().setReadDependency(buffer); 1530 1531 id<MTLBuffer> mtlBuffer = (buffer ? buffer->get() : nil); 1532 1533 return commonSetBuffer(shaderType, mtlBuffer, offset, index); 1534} 1535 1536RenderCommandEncoder &RenderCommandEncoder::setBufferForWrite(gl::ShaderType shaderType, 1537 const BufferRef &buffer, 1538 uint32_t offset, 1539 uint32_t index) 1540{ 1541 if (index >= kMaxShaderBuffers) 1542 { 1543 return *this; 1544 } 1545 1546 cmdBuffer().setWriteDependency(buffer); 1547 1548 id<MTLBuffer> mtlBuffer = (buffer ? buffer->get() : nil); 1549 1550 return commonSetBuffer(shaderType, mtlBuffer, offset, index); 1551} 1552 1553RenderCommandEncoder &RenderCommandEncoder::commonSetBuffer(gl::ShaderType shaderType, 1554 id<MTLBuffer> mtlBuffer, 1555 uint32_t offset, 1556 uint32_t index) 1557{ 1558 RenderCommandEncoderShaderStates &shaderStates = mStateCache.perShaderStates[shaderType]; 1559 if (shaderStates.buffers[index] == mtlBuffer) 1560 { 1561 if (shaderStates.bufferOffsets[index] == offset) 1562 { 1563 return *this; 1564 } 1565 1566 // If buffer already bound but with different offset, then update the offer only. 1567 shaderStates.bufferOffsets[index] = offset; 1568 1569 mCommands.push(static_cast<CmdType>(mSetBufferOffsetCmds[shaderType])) 1570 .push(offset) 1571 .push(index); 1572 1573 return *this; 1574 } 1575 1576 shaderStates.buffers[index] = mtlBuffer; 1577 shaderStates.bufferOffsets[index] = offset; 1578 1579 mCommands.push(static_cast<CmdType>(mSetBufferCmds[shaderType])) 1580 .push([mtlBuffer ANGLE_MTL_RETAIN]) 1581 .push(offset) 1582 .push(index); 1583 1584 return *this; 1585} 1586 1587RenderCommandEncoder &RenderCommandEncoder::setBytes(gl::ShaderType shaderType, 1588 const uint8_t *bytes, 1589 size_t size, 1590 uint32_t index) 1591{ 1592 if (index >= kMaxShaderBuffers) 1593 { 1594 return *this; 1595 } 1596 1597 RenderCommandEncoderShaderStates &shaderStates = mStateCache.perShaderStates[shaderType]; 1598 shaderStates.buffers[index] = nil; 1599 shaderStates.bufferOffsets[index] = 0; 1600 1601 mCommands.push(static_cast<CmdType>(mSetBytesCmds[shaderType])) 1602 .push(size) 1603 .push(bytes, size) 1604 .push(index); 1605 1606 return *this; 1607} 1608 1609RenderCommandEncoder &RenderCommandEncoder::setSamplerState(gl::ShaderType shaderType, 1610 id<MTLSamplerState> state, 1611 float lodMinClamp, 1612 float lodMaxClamp, 1613 uint32_t index) 1614{ 1615 if (index >= kMaxShaderSamplers) 1616 { 1617 return *this; 1618 } 1619 1620 RenderCommandEncoderShaderStates &shaderStates = mStateCache.perShaderStates[shaderType]; 1621 if (shaderStates.samplers[index] == state && shaderStates.samplerLodClamps[index].valid()) 1622 { 1623 const std::pair<float, float> ¤tLodClampRange = 1624 shaderStates.samplerLodClamps[index].value(); 1625 if (currentLodClampRange.first == lodMinClamp && currentLodClampRange.second == lodMaxClamp) 1626 { 1627 return *this; 1628 } 1629 } 1630 1631 shaderStates.samplers[index] = state; 1632 shaderStates.samplerLodClamps[index] = {lodMinClamp, lodMaxClamp}; 1633 1634 mCommands.push(static_cast<CmdType>(mSetSamplerCmds[shaderType])) 1635 .push([state ANGLE_MTL_RETAIN]) 1636 .push(lodMinClamp) 1637 .push(lodMaxClamp) 1638 .push(index); 1639 1640 return *this; 1641} 1642RenderCommandEncoder &RenderCommandEncoder::setTexture(gl::ShaderType shaderType, 1643 const TextureRef &texture, 1644 uint32_t index) 1645{ 1646 if (index >= kMaxShaderSamplers) 1647 { 1648 return *this; 1649 } 1650 1651 cmdBuffer().setReadDependency(texture); 1652 1653 id<MTLTexture> mtlTexture = (texture ? texture->get() : nil); 1654 1655 RenderCommandEncoderShaderStates &shaderStates = mStateCache.perShaderStates[shaderType]; 1656 if (shaderStates.textures[index] == mtlTexture) 1657 { 1658 return *this; 1659 } 1660 shaderStates.textures[index] = mtlTexture; 1661 1662 mCommands.push(static_cast<CmdType>(mSetTextureCmds[shaderType])) 1663 .push([mtlTexture ANGLE_MTL_RETAIN]) 1664 .push(index); 1665 1666 return *this; 1667} 1668 1669RenderCommandEncoder &RenderCommandEncoder::draw(MTLPrimitiveType primitiveType, 1670 uint32_t vertexStart, 1671 uint32_t vertexCount) 1672{ 1673 ASSERT(mPipelineStateSet && 1674 "Render Pipeline State was never set and we've issued a draw command."); 1675 mHasDrawCalls = true; 1676 mCommands.push(CmdType::Draw).push(primitiveType).push(vertexStart).push(vertexCount); 1677 1678 return *this; 1679} 1680 1681RenderCommandEncoder &RenderCommandEncoder::drawInstanced(MTLPrimitiveType primitiveType, 1682 uint32_t vertexStart, 1683 uint32_t vertexCount, 1684 uint32_t instances) 1685{ 1686 ASSERT(mPipelineStateSet && 1687 "Render Pipeline State was never set and we've issued a draw command."); 1688 mHasDrawCalls = true; 1689 mCommands.push(CmdType::DrawInstanced) 1690 .push(primitiveType) 1691 .push(vertexStart) 1692 .push(vertexCount) 1693 .push(instances); 1694 1695 return *this; 1696} 1697 1698RenderCommandEncoder &RenderCommandEncoder::drawInstancedBaseInstance( 1699 MTLPrimitiveType primitiveType, 1700 uint32_t vertexStart, 1701 uint32_t vertexCount, 1702 uint32_t instances, 1703 uint32_t baseInstance) 1704{ 1705 ASSERT(mPipelineStateSet && 1706 "Render Pipeline State was never set and we've issued a draw command."); 1707 mHasDrawCalls = true; 1708 mCommands.push(CmdType::DrawInstancedBaseInstance) 1709 .push(primitiveType) 1710 .push(vertexStart) 1711 .push(vertexCount) 1712 .push(instances) 1713 .push(baseInstance); 1714 1715 return *this; 1716} 1717 1718RenderCommandEncoder &RenderCommandEncoder::drawIndexed(MTLPrimitiveType primitiveType, 1719 uint32_t indexCount, 1720 MTLIndexType indexType, 1721 const BufferRef &indexBuffer, 1722 size_t bufferOffset) 1723{ 1724 ASSERT(mPipelineStateSet && 1725 "Render Pipeline State was never set and we've issued a draw command."); 1726 if (!indexBuffer) 1727 { 1728 return *this; 1729 } 1730 1731 mHasDrawCalls = true; 1732 cmdBuffer().setReadDependency(indexBuffer); 1733 1734 mCommands.push(CmdType::DrawIndexed) 1735 .push(primitiveType) 1736 .push(indexCount) 1737 .push(indexType) 1738 .push([indexBuffer->get() ANGLE_MTL_RETAIN]) 1739 .push(bufferOffset); 1740 1741 return *this; 1742} 1743 1744RenderCommandEncoder &RenderCommandEncoder::drawIndexedInstanced(MTLPrimitiveType primitiveType, 1745 uint32_t indexCount, 1746 MTLIndexType indexType, 1747 const BufferRef &indexBuffer, 1748 size_t bufferOffset, 1749 uint32_t instances) 1750{ 1751 ASSERT(mPipelineStateSet && 1752 "Render Pipeline State was never set and we've issued a draw command."); 1753 if (!indexBuffer) 1754 { 1755 return *this; 1756 } 1757 1758 mHasDrawCalls = true; 1759 cmdBuffer().setReadDependency(indexBuffer); 1760 1761 mCommands.push(CmdType::DrawIndexedInstanced) 1762 .push(primitiveType) 1763 .push(indexCount) 1764 .push(indexType) 1765 .push([indexBuffer->get() ANGLE_MTL_RETAIN]) 1766 .push(bufferOffset) 1767 .push(instances); 1768 1769 return *this; 1770} 1771 1772RenderCommandEncoder &RenderCommandEncoder::drawIndexedInstancedBaseVertexBaseInstance( 1773 MTLPrimitiveType primitiveType, 1774 uint32_t indexCount, 1775 MTLIndexType indexType, 1776 const BufferRef &indexBuffer, 1777 size_t bufferOffset, 1778 uint32_t instances, 1779 uint32_t baseVertex, 1780 uint32_t baseInstance) 1781{ 1782 ASSERT(mPipelineStateSet && 1783 "Render Pipeline State was never set and we've issued a draw command."); 1784 if (!indexBuffer) 1785 { 1786 return *this; 1787 } 1788 1789 mHasDrawCalls = true; 1790 cmdBuffer().setReadDependency(indexBuffer); 1791 1792 mCommands.push(CmdType::DrawIndexedInstancedBaseVertexBaseInstance) 1793 .push(primitiveType) 1794 .push(indexCount) 1795 .push(indexType) 1796 .push([indexBuffer->get() ANGLE_MTL_RETAIN]) 1797 .push(bufferOffset) 1798 .push(instances) 1799 .push(baseVertex) 1800 .push(baseInstance); 1801 1802 return *this; 1803} 1804 1805RenderCommandEncoder &RenderCommandEncoder::setVisibilityResultMode(MTLVisibilityResultMode mode, 1806 size_t offset) 1807{ 1808 if (mStateCache.visibilityResultMode == mode && 1809 mStateCache.visibilityResultBufferOffset == offset) 1810 { 1811 return *this; 1812 } 1813 mStateCache.visibilityResultMode = mode; 1814 mStateCache.visibilityResultBufferOffset = offset; 1815 1816 mCommands.push(CmdType::SetVisibilityResultMode).push(mode).push(offset); 1817 return *this; 1818} 1819 1820RenderCommandEncoder &RenderCommandEncoder::useResource(const BufferRef &resource, 1821 MTLResourceUsage usage, 1822 mtl::RenderStages states) 1823{ 1824 if (!resource) 1825 { 1826 return *this; 1827 } 1828 1829 cmdBuffer().setReadDependency(resource); 1830 1831 mCommands.push(CmdType::UseResource) 1832 .push([resource->get() ANGLE_MTL_RETAIN]) 1833 .push(usage) 1834 .push(states); 1835 1836 return *this; 1837} 1838 1839RenderCommandEncoder &RenderCommandEncoder::memoryBarrierWithResource(const BufferRef &resource, 1840 mtl::RenderStages after, 1841 mtl::RenderStages before) 1842{ 1843 if (!resource) 1844 { 1845 return *this; 1846 } 1847 1848 cmdBuffer().setWriteDependency(resource); 1849 1850 mCommands.push(CmdType::MemoryBarrierWithResource) 1851 .push([resource->get() ANGLE_MTL_RETAIN]) 1852 .push(after) 1853 .push(before); 1854 1855 return *this; 1856} 1857 1858void RenderCommandEncoder::insertDebugSignImpl(NSString *label) 1859{ 1860 // Defer the insertion until endEncoding() 1861 mCommands.push(CmdType::InsertDebugsign).push([label ANGLE_MTL_RETAIN]); 1862} 1863 1864void RenderCommandEncoder::pushDebugGroup(NSString *label) 1865{ 1866 // Defer the insertion until endEncoding() 1867 mCommands.push(CmdType::PushDebugGroup).push([label ANGLE_MTL_RETAIN]); 1868} 1869void RenderCommandEncoder::popDebugGroup() 1870{ 1871 mCommands.push(CmdType::PopDebugGroup); 1872} 1873 1874RenderCommandEncoder &RenderCommandEncoder::setColorStoreAction(MTLStoreAction action, 1875 uint32_t colorAttachmentIndex) 1876{ 1877 if (colorAttachmentIndex >= mRenderPassDesc.numColorAttachments) 1878 { 1879 return *this; 1880 } 1881 1882 // We only store the options, will defer the actual setting until the encoder finishes 1883 mRenderPassDesc.colorAttachments[colorAttachmentIndex].storeAction = action; 1884 1885 return *this; 1886} 1887 1888RenderCommandEncoder &RenderCommandEncoder::setColorStoreAction(MTLStoreAction action) 1889{ 1890 for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i) 1891 { 1892 setColorStoreAction(action, i); 1893 } 1894 return *this; 1895} 1896 1897RenderCommandEncoder &RenderCommandEncoder::setDepthStencilStoreAction( 1898 MTLStoreAction depthStoreAction, 1899 MTLStoreAction stencilStoreAction) 1900{ 1901 // We only store the options, will defer the actual setting until the encoder finishes 1902 mRenderPassDesc.depthAttachment.storeAction = depthStoreAction; 1903 mRenderPassDesc.stencilAttachment.storeAction = stencilStoreAction; 1904 1905 return *this; 1906} 1907 1908RenderCommandEncoder &RenderCommandEncoder::setDepthStoreAction(MTLStoreAction action) 1909{ 1910 // We only store the options, will defer the actual setting until the encoder finishes 1911 mRenderPassDesc.depthAttachment.storeAction = action; 1912 1913 return *this; 1914} 1915 1916RenderCommandEncoder &RenderCommandEncoder::setStencilStoreAction(MTLStoreAction action) 1917{ 1918 // We only store the options, will defer the actual setting until the encoder finishes 1919 mRenderPassDesc.stencilAttachment.storeAction = action; 1920 1921 return *this; 1922} 1923 1924RenderCommandEncoder &RenderCommandEncoder::setStoreAction(MTLStoreAction action) 1925{ 1926 setColorStoreAction(action); 1927 setDepthStencilStoreAction(action, action); 1928 return *this; 1929} 1930 1931RenderCommandEncoder &RenderCommandEncoder::setColorLoadAction(MTLLoadAction action, 1932 const MTLClearColor &clearValue, 1933 uint32_t colorAttachmentIndex) 1934{ 1935 ASSERT(!hasDrawCalls()); 1936 if (mCachedRenderPassDescObjC.get().colorAttachments[colorAttachmentIndex].texture) 1937 { 1938 mCachedRenderPassDescObjC.get().colorAttachments[colorAttachmentIndex].loadAction = action; 1939 mCachedRenderPassDescObjC.get().colorAttachments[colorAttachmentIndex].clearColor = 1940 clearValue; 1941 } 1942 return *this; 1943} 1944 1945RenderCommandEncoder &RenderCommandEncoder::setDepthLoadAction(MTLLoadAction action, 1946 double clearVal) 1947{ 1948 ASSERT(!hasDrawCalls()); 1949 if (mCachedRenderPassDescObjC.get().depthAttachment.texture) 1950 { 1951 mCachedRenderPassDescObjC.get().depthAttachment.loadAction = action; 1952 mCachedRenderPassDescObjC.get().depthAttachment.clearDepth = clearVal; 1953 } 1954 return *this; 1955} 1956 1957RenderCommandEncoder &RenderCommandEncoder::setStencilLoadAction(MTLLoadAction action, 1958 uint32_t clearVal) 1959{ 1960 ASSERT(!hasDrawCalls()); 1961 if (mCachedRenderPassDescObjC.get().stencilAttachment.texture) 1962 { 1963 mCachedRenderPassDescObjC.get().stencilAttachment.loadAction = action; 1964 mCachedRenderPassDescObjC.get().stencilAttachment.clearStencil = clearVal; 1965 } 1966 return *this; 1967} 1968 1969void RenderCommandEncoder::setLabel(NSString *label) 1970{ 1971 mLabel.retainAssign(label); 1972} 1973 1974// BlitCommandEncoder 1975BlitCommandEncoder::BlitCommandEncoder(CommandBuffer *cmdBuffer) : CommandEncoder(cmdBuffer, BLIT) 1976{} 1977 1978BlitCommandEncoder::~BlitCommandEncoder() {} 1979 1980BlitCommandEncoder &BlitCommandEncoder::restart() 1981{ 1982 ANGLE_MTL_OBJC_SCOPE 1983 { 1984 if (valid()) 1985 { 1986 // no change, skip 1987 return *this; 1988 } 1989 1990 if (!cmdBuffer().ready()) 1991 { 1992 reset(); 1993 return *this; 1994 } 1995 1996 // Create objective C object 1997 set([cmdBuffer().get() blitCommandEncoder]); 1998 1999 // Verify that it was created successfully 2000 ASSERT(get()); 2001 2002 return *this; 2003 } 2004} 2005 2006BlitCommandEncoder &BlitCommandEncoder::copyBuffer(const BufferRef &src, 2007 size_t srcOffset, 2008 const BufferRef &dst, 2009 size_t dstOffset, 2010 size_t size) 2011{ 2012 if (!src || !dst) 2013 { 2014 return *this; 2015 } 2016 2017 cmdBuffer().setReadDependency(src); 2018 cmdBuffer().setWriteDependency(dst); 2019 2020 [get() copyFromBuffer:src->get() 2021 sourceOffset:srcOffset 2022 toBuffer:dst->get() 2023 destinationOffset:dstOffset 2024 size:size]; 2025 2026 return *this; 2027} 2028 2029BlitCommandEncoder &BlitCommandEncoder::copyBufferToTexture(const BufferRef &src, 2030 size_t srcOffset, 2031 size_t srcBytesPerRow, 2032 size_t srcBytesPerImage, 2033 MTLSize srcSize, 2034 const TextureRef &dst, 2035 uint32_t dstSlice, 2036 MipmapNativeLevel dstLevel, 2037 MTLOrigin dstOrigin, 2038 MTLBlitOption blitOption) 2039{ 2040 if (!src || !dst) 2041 { 2042 return *this; 2043 } 2044 2045 cmdBuffer().setReadDependency(src); 2046 cmdBuffer().setWriteDependency(dst); 2047 2048 [get() copyFromBuffer:src->get() 2049 sourceOffset:srcOffset 2050 sourceBytesPerRow:srcBytesPerRow 2051 sourceBytesPerImage:srcBytesPerImage 2052 sourceSize:srcSize 2053 toTexture:dst->get() 2054 destinationSlice:dstSlice 2055 destinationLevel:dstLevel.get() 2056 destinationOrigin:dstOrigin 2057 options:blitOption]; 2058 2059 return *this; 2060} 2061 2062BlitCommandEncoder &BlitCommandEncoder::copyTextureToBuffer(const TextureRef &src, 2063 uint32_t srcSlice, 2064 MipmapNativeLevel srcLevel, 2065 MTLOrigin srcOrigin, 2066 MTLSize srcSize, 2067 const BufferRef &dst, 2068 size_t dstOffset, 2069 size_t dstBytesPerRow, 2070 size_t dstBytesPerImage, 2071 MTLBlitOption blitOption) 2072{ 2073 2074 if (!src || !dst) 2075 { 2076 return *this; 2077 } 2078 2079 cmdBuffer().setReadDependency(src); 2080 cmdBuffer().setWriteDependency(dst); 2081 2082 [get() copyFromTexture:src->get() 2083 sourceSlice:srcSlice 2084 sourceLevel:srcLevel.get() 2085 sourceOrigin:srcOrigin 2086 sourceSize:srcSize 2087 toBuffer:dst->get() 2088 destinationOffset:dstOffset 2089 destinationBytesPerRow:dstBytesPerRow 2090 destinationBytesPerImage:dstBytesPerImage 2091 options:blitOption]; 2092 2093 return *this; 2094} 2095 2096BlitCommandEncoder &BlitCommandEncoder::copyTexture(const TextureRef &src, 2097 uint32_t srcStartSlice, 2098 MipmapNativeLevel srcStartLevel, 2099 const TextureRef &dst, 2100 uint32_t dstStartSlice, 2101 MipmapNativeLevel dstStartLevel, 2102 uint32_t sliceCount, 2103 uint32_t levelCount) 2104{ 2105 if (!src || !dst) 2106 { 2107 return *this; 2108 } 2109 2110 cmdBuffer().setReadDependency(src); 2111 cmdBuffer().setWriteDependency(dst); 2112 2113 MTLOrigin origin = MTLOriginMake(0, 0, 0); 2114 for (uint32_t slice = 0; slice < sliceCount; ++slice) 2115 { 2116 uint32_t srcSlice = srcStartSlice + slice; 2117 uint32_t dstSlice = dstStartSlice + slice; 2118 for (uint32_t level = 0; level < levelCount; ++level) 2119 { 2120 MipmapNativeLevel srcLevel = srcStartLevel + level; 2121 MipmapNativeLevel dstLevel = dstStartLevel + level; 2122 MTLSize srcSize = 2123 MTLSizeMake(src->width(srcLevel), src->height(srcLevel), src->depth(srcLevel)); 2124 2125 [get() copyFromTexture:src->get() 2126 sourceSlice:srcSlice 2127 sourceLevel:srcLevel.get() 2128 sourceOrigin:origin 2129 sourceSize:srcSize 2130 toTexture:dst->get() 2131 destinationSlice:dstSlice 2132 destinationLevel:dstLevel.get() 2133 destinationOrigin:origin]; 2134 } 2135 } 2136 2137 return *this; 2138} 2139 2140BlitCommandEncoder &BlitCommandEncoder::fillBuffer(const BufferRef &buffer, 2141 NSRange range, 2142 uint8_t value) 2143{ 2144 if (!buffer) 2145 { 2146 return *this; 2147 } 2148 2149 [get() fillBuffer:buffer->get() range:range value:value]; 2150 return *this; 2151} 2152 2153BlitCommandEncoder &BlitCommandEncoder::generateMipmapsForTexture(const TextureRef &texture) 2154{ 2155 if (!texture) 2156 { 2157 return *this; 2158 } 2159 2160 cmdBuffer().setWriteDependency(texture); 2161 [get() generateMipmapsForTexture:texture->get()]; 2162 2163 return *this; 2164} 2165BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(Buffer *buffer) 2166{ 2167 if (!buffer) 2168 { 2169 return *this; 2170 } 2171 2172#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 2173 // Only MacOS has separated storage for resource on CPU and GPU and needs explicit 2174 // synchronization 2175 cmdBuffer().setReadDependency(buffer); 2176 [get() synchronizeResource:buffer->get()]; 2177#endif 2178 return *this; 2179} 2180BlitCommandEncoder &BlitCommandEncoder::synchronizeResource(Texture *texture) 2181{ 2182 if (!texture) 2183 { 2184 return *this; 2185 } 2186 2187#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 2188 // Only MacOS has separated storage for resource on CPU and GPU and needs explicit 2189 // synchronization 2190 cmdBuffer().setReadDependency(texture); 2191 if (texture->get().parentTexture) 2192 { 2193 [get() synchronizeResource:texture->get().parentTexture]; 2194 } 2195 else 2196 { 2197 [get() synchronizeResource:texture->get()]; 2198 } 2199#endif 2200 return *this; 2201} 2202 2203// ComputeCommandEncoder implementation 2204ComputeCommandEncoder::ComputeCommandEncoder(CommandBuffer *cmdBuffer) 2205 : CommandEncoder(cmdBuffer, COMPUTE) 2206{} 2207ComputeCommandEncoder::~ComputeCommandEncoder() {} 2208 2209ComputeCommandEncoder &ComputeCommandEncoder::restart() 2210{ 2211 ANGLE_MTL_OBJC_SCOPE 2212 { 2213 if (valid()) 2214 { 2215 // no change, skip 2216 return *this; 2217 } 2218 2219 if (!cmdBuffer().ready()) 2220 { 2221 reset(); 2222 return *this; 2223 } 2224 2225 // Create objective C object 2226 set([cmdBuffer().get() computeCommandEncoder]); 2227 2228 // Verify that it was created successfully 2229 ASSERT(get()); 2230 2231 return *this; 2232 } 2233} 2234 2235ComputeCommandEncoder &ComputeCommandEncoder::setComputePipelineState( 2236 id<MTLComputePipelineState> state) 2237{ 2238 [get() setComputePipelineState:state]; 2239 return *this; 2240} 2241 2242ComputeCommandEncoder &ComputeCommandEncoder::setBuffer(const BufferRef &buffer, 2243 uint32_t offset, 2244 uint32_t index) 2245{ 2246 if (index >= kMaxShaderBuffers) 2247 { 2248 return *this; 2249 } 2250 2251 cmdBuffer().setReadDependency(buffer); 2252 2253 [get() setBuffer:(buffer ? buffer->get() : nil) offset:offset atIndex:index]; 2254 2255 return *this; 2256} 2257 2258ComputeCommandEncoder &ComputeCommandEncoder::setBufferForWrite(const BufferRef &buffer, 2259 uint32_t offset, 2260 uint32_t index) 2261{ 2262 if (index >= kMaxShaderBuffers) 2263 { 2264 return *this; 2265 } 2266 2267 cmdBuffer().setWriteDependency(buffer); 2268 return setBuffer(buffer, offset, index); 2269} 2270 2271ComputeCommandEncoder &ComputeCommandEncoder::setBytes(const uint8_t *bytes, 2272 size_t size, 2273 uint32_t index) 2274{ 2275 if (index >= kMaxShaderBuffers) 2276 { 2277 return *this; 2278 } 2279 2280 [get() setBytes:bytes length:size atIndex:index]; 2281 2282 return *this; 2283} 2284 2285ComputeCommandEncoder &ComputeCommandEncoder::setSamplerState(id<MTLSamplerState> state, 2286 float lodMinClamp, 2287 float lodMaxClamp, 2288 uint32_t index) 2289{ 2290 if (index >= kMaxShaderSamplers) 2291 { 2292 return *this; 2293 } 2294 2295 [get() setSamplerState:state lodMinClamp:lodMinClamp lodMaxClamp:lodMaxClamp atIndex:index]; 2296 2297 return *this; 2298} 2299ComputeCommandEncoder &ComputeCommandEncoder::setTexture(const TextureRef &texture, uint32_t index) 2300{ 2301 if (index >= kMaxShaderSamplers) 2302 { 2303 return *this; 2304 } 2305 2306 cmdBuffer().setReadDependency(texture); 2307 [get() setTexture:(texture ? texture->get() : nil) atIndex:index]; 2308 2309 return *this; 2310} 2311ComputeCommandEncoder &ComputeCommandEncoder::setTextureForWrite(const TextureRef &texture, 2312 uint32_t index) 2313{ 2314 if (index >= kMaxShaderSamplers) 2315 { 2316 return *this; 2317 } 2318 2319 cmdBuffer().setWriteDependency(texture); 2320 return setTexture(texture, index); 2321} 2322 2323ComputeCommandEncoder &ComputeCommandEncoder::dispatch(const MTLSize &threadGroupsPerGrid, 2324 const MTLSize &threadsPerGroup) 2325{ 2326 [get() dispatchThreadgroups:threadGroupsPerGrid threadsPerThreadgroup:threadsPerGroup]; 2327 return *this; 2328} 2329 2330ComputeCommandEncoder &ComputeCommandEncoder::dispatchNonUniform(const MTLSize &threadsPerGrid, 2331 const MTLSize &threadsPerGroup) 2332{ 2333#if TARGET_OS_TV 2334 UNREACHABLE(); 2335#else 2336 [get() dispatchThreads:threadsPerGrid threadsPerThreadgroup:threadsPerGroup]; 2337#endif 2338 return *this; 2339} 2340} 2341} 2342