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.h: 7 // Defines the wrapper classes for Metal's MTLCommandEncoder, MTLCommandQueue and 8 // MTLCommandBuffer. 9 // 10 11 #ifndef LIBANGLE_RENDERER_METAL_COMMANDENBUFFERMTL_H_ 12 #define LIBANGLE_RENDERER_METAL_COMMANDENBUFFERMTL_H_ 13 14 #import <Metal/Metal.h> 15 #import <QuartzCore/CAMetalLayer.h> 16 #include <cstdint> 17 18 #include <deque> 19 #include <memory> 20 #include <mutex> 21 #include <thread> 22 #include <vector> 23 24 #include "common/FixedVector.h" 25 #include "common/angleutils.h" 26 #include "libANGLE/renderer/metal/mtl_common.h" 27 #include "libANGLE/renderer/metal/mtl_resources.h" 28 #include "libANGLE/renderer/metal/mtl_state_cache.h" 29 30 namespace rx 31 { 32 namespace mtl 33 { 34 35 enum CommandBufferFinishOperation 36 { 37 NoWait, 38 WaitUntilScheduled, 39 WaitUntilFinished 40 }; 41 42 class CommandBuffer; 43 class CommandEncoder; 44 class RenderCommandEncoder; 45 class OcclusionQueryPool; 46 47 class AtomicSerial : angle::NonCopyable 48 { 49 public: load()50 uint64_t load() const { return mValue.load(std::memory_order_consume); } increment(uint64_t value)51 void increment(uint64_t value) { mValue.fetch_add(1, std::memory_order_release); } 52 void storeMaxValue(uint64_t value); 53 54 private: 55 std::atomic<uint64_t> mValue{0}; 56 }; 57 58 class CommandQueue final : public WrappedObject<id<MTLCommandQueue>>, angle::NonCopyable 59 { 60 public: 61 void reset(); 62 void set(id<MTLCommandQueue> metalQueue); 63 64 void finishAllCommands(); 65 66 // This method will ensure that every GPU command buffer using this resource will finish before 67 // returning. Note: this doesn't include the "in-progress" command buffer, i.e. the one hasn't 68 // been commmitted yet. It's the responsibility of caller to make sure that command buffer is 69 // commited/flushed first before calling this method. 70 void ensureResourceReadyForCPU(const ResourceRef &resource); 71 void ensureResourceReadyForCPU(Resource *resource); 72 73 // Check whether the resource is being used by any command buffer still running on GPU. 74 // This must be called before attempting to read the content of resource on CPU side. isResourceBeingUsedByGPU(const ResourceRef & resource)75 bool isResourceBeingUsedByGPU(const ResourceRef &resource) const 76 { 77 return isResourceBeingUsedByGPU(resource.get()); 78 } 79 bool isResourceBeingUsedByGPU(const Resource *resource) const; 80 81 // Checks whether the last command buffer that uses the given resource has been committed or not 82 bool resourceHasPendingWorks(const Resource *resource) const; 83 // Checks whether the last command buffer that uses the given resource (in a render encoder) has 84 // been committed or not 85 bool resourceHasPendingRenderWorks(const Resource *resource) const; 86 87 bool isSerialCompleted(uint64_t serial) const; 88 bool waitUntilSerialCompleted(uint64_t serial, uint64_t timeoutNs) const; 89 90 CommandQueue &operator=(id<MTLCommandQueue> metalQueue) 91 { 92 set(metalQueue); 93 return *this; 94 } 95 96 AutoObjCPtr<id<MTLCommandBuffer>> makeMetalCommandBuffer(uint64_t *queueSerialOut); 97 void onCommandBufferCommitted(id<MTLCommandBuffer> buf, uint64_t serial); 98 99 uint64_t getNextRenderEncoderSerial(); 100 101 uint64_t allocateTimeElapsedEntry(); 102 bool deleteTimeElapsedEntry(uint64_t id); 103 void setActiveTimeElapsedEntry(uint64_t id); 104 bool isTimeElapsedEntryComplete(uint64_t id); 105 double getTimeElapsedEntryInSeconds(uint64_t id); 106 107 private: 108 void onCommandBufferCompleted(id<MTLCommandBuffer> buf, 109 uint64_t serial, 110 uint64_t timeElapsedEntry); 111 using ParentClass = WrappedObject<id<MTLCommandQueue>>; 112 113 struct CmdBufferQueueEntry 114 { 115 AutoObjCPtr<id<MTLCommandBuffer>> buffer; 116 uint64_t serial; 117 }; 118 std::deque<CmdBufferQueueEntry> mMetalCmdBuffers; 119 120 uint64_t mQueueSerialCounter = 1; 121 AtomicSerial mCommittedBufferSerial; 122 AtomicSerial mCompletedBufferSerial; 123 uint64_t mRenderEncoderCounter = 1; 124 125 // The bookkeeping for TIME_ELAPSED queries must be managed under 126 // the cover of a lock because it's accessed by multiple threads: 127 // the application, and the internal thread which dispatches the 128 // command buffer completed handlers. The QueryMtl object 129 // allocates and deallocates the IDs and associated storage. 130 // In-flight CommandBuffers might refer to IDs that have been 131 // deallocated. ID 0 is used as a sentinel. 132 struct TimeElapsedEntry 133 { 134 double elapsed_seconds = 0.0; 135 int32_t pending_command_buffers = 0; 136 uint64_t id = 0; 137 }; 138 angle::HashMap<uint64_t, TimeElapsedEntry> mTimeElapsedEntries; 139 uint64_t mTimeElapsedNextId = 1; 140 uint64_t mActiveTimeElapsedId = 0; 141 142 mutable std::mutex mLock; 143 mutable std::condition_variable mCompletedBufferSerialCv; 144 145 void addCommandBufferToTimeElapsedEntry(std::lock_guard<std::mutex> &lg, uint64_t id); 146 void recordCommandBufferTimeElapsed(std::lock_guard<std::mutex> &lg, 147 uint64_t id, 148 double seconds); 149 }; 150 151 class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::NonCopyable 152 { 153 public: 154 CommandBuffer(CommandQueue *cmdQueue); 155 ~CommandBuffer(); 156 157 // This method must be called so that command encoder can be used. 158 void restart(); 159 160 // Return true if command buffer can be encoded into. Return false if it has been committed 161 // and hasn't been restarted. 162 bool ready() const; 163 void commit(CommandBufferFinishOperation operation); 164 void wait(CommandBufferFinishOperation operation); 165 166 void present(id<CAMetalDrawable> presentationDrawable); 167 168 void setWriteDependency(const ResourceRef &resource, bool isRenderCommand); 169 void setReadDependency(const ResourceRef &resource, bool isRenderCommand); 170 void setReadDependency(Resource *resourcePtr, bool isRenderCommand); 171 172 #if ANGLE_MTL_EVENT_AVAILABLE 173 // Queues the event and returns the current command buffer queue serial. 174 uint64_t queueEventSignal(id<MTLEvent> event, uint64_t value); 175 void serverWaitEvent(id<MTLEvent> event, uint64_t value); 176 #endif // ANGLE_MTL_EVENT_AVAILABLE 177 178 void insertDebugSign(const std::string &marker); 179 void pushDebugGroup(const std::string &marker); 180 void popDebugGroup(); 181 cmdQueue()182 CommandQueue &cmdQueue() { return mCmdQueue; } cmdQueue()183 const CommandQueue &cmdQueue() const { return mCmdQueue; } 184 185 // Private use only 186 void setActiveCommandEncoder(CommandEncoder *encoder); 187 void invalidateActiveCommandEncoder(CommandEncoder *encoder); 188 189 bool needsFlushForDrawCallLimits() const; 190 191 uint64_t getQueueSerial() const; 192 193 private: 194 void set(id<MTLCommandBuffer> metalBuffer); 195 196 // This function returns either blit/compute encoder (if active) or render encoder. 197 // If both types of encoders are active (blit/compute and render), the former will be returned. 198 CommandEncoder *getPendingCommandEncoder(); 199 200 void cleanup(); 201 202 bool readyImpl() const; 203 bool commitImpl(); 204 void forceEndingAllEncoders(); 205 206 void setPendingEvents(); 207 #if ANGLE_MTL_EVENT_AVAILABLE 208 void setEventImpl(id<MTLEvent> event, uint64_t value); 209 #endif // ANGLE_MTL_EVENT_AVAILABLE 210 211 void pushDebugGroupImpl(const std::string &marker); 212 void popDebugGroupImpl(); 213 214 void setResourceUsedByCommandBuffer(const ResourceRef &resource); 215 void clearResourceListAndSize(); 216 217 using ParentClass = WrappedObject<id<MTLCommandBuffer>>; 218 219 CommandQueue &mCmdQueue; 220 221 // Note: due to render command encoder being a deferred encoder, it can coexist with 222 // blit/compute encoder. When submitting, blit/compute encoder will be executed before the 223 // render encoder. 224 CommandEncoder *mActiveRenderEncoder = nullptr; 225 CommandEncoder *mActiveBlitOrComputeEncoder = nullptr; 226 227 uint64_t mQueueSerial = 0; 228 229 mutable std::mutex mLock; 230 231 std::vector<std::string> mPendingDebugSigns; 232 233 #if ANGLE_MTL_EVENT_AVAILABLE 234 struct PendingEvent 235 { 236 AutoObjCPtr<id<MTLEvent>> event; 237 uint64_t signalValue = 0; 238 }; 239 std::vector<PendingEvent> mPendingSignalEvents; 240 #endif // ANGLE_MTL_EVENT_AVAILABLE 241 242 std::vector<std::string> mDebugGroups; 243 244 angle::HashSet<id> mResourceList; 245 size_t mWorkingResourceSize = 0; 246 bool mCommitted = false; 247 CommandBufferFinishOperation mLastWaitOp = mtl::NoWait; 248 }; 249 250 class CommandEncoder : public WrappedObject<id<MTLCommandEncoder>>, angle::NonCopyable 251 { 252 public: 253 enum Type 254 { 255 RENDER, 256 BLIT, 257 COMPUTE, 258 }; 259 260 virtual ~CommandEncoder(); 261 262 virtual void endEncoding(); 263 264 virtual void reset(); getType()265 Type getType() const { return mType; } 266 267 CommandEncoder &markResourceBeingWrittenByGPU(const BufferRef &buffer); 268 CommandEncoder &markResourceBeingWrittenByGPU(const TextureRef &texture); 269 270 void insertDebugSign(NSString *label); 271 272 virtual void pushDebugGroup(NSString *label); 273 virtual void popDebugGroup(); 274 275 protected: 276 using ParentClass = WrappedObject<id<MTLCommandEncoder>>; 277 278 CommandEncoder(CommandBuffer *cmdBuffer, Type type); 279 cmdBuffer()280 CommandBuffer &cmdBuffer() { return mCmdBuffer; } cmdQueue()281 CommandQueue &cmdQueue() { return mCmdBuffer.cmdQueue(); } 282 283 void set(id<MTLCommandEncoder> metalCmdEncoder); 284 285 virtual void insertDebugSignImpl(NSString *marker); 286 287 private: isRenderEncoder()288 bool isRenderEncoder() const { return getType() == Type::RENDER; } 289 290 const Type mType; 291 CommandBuffer &mCmdBuffer; 292 }; 293 294 // Stream to store commands before encoding them into the real MTLCommandEncoder 295 class IntermediateCommandStream 296 { 297 public: 298 template <typename T> push(const T & val)299 inline IntermediateCommandStream &push(const T &val) 300 { 301 auto ptr = reinterpret_cast<const uint8_t *>(&val); 302 mBuffer.insert(mBuffer.end(), ptr, ptr + sizeof(T)); 303 return *this; 304 } 305 push(const uint8_t * bytes,size_t len)306 inline IntermediateCommandStream &push(const uint8_t *bytes, size_t len) 307 { 308 mBuffer.insert(mBuffer.end(), bytes, bytes + len); 309 return *this; 310 } 311 312 template <typename T> peek()313 inline T peek() 314 { 315 ASSERT(mReadPtr <= mBuffer.size() - sizeof(T)); 316 T re; 317 auto ptr = reinterpret_cast<uint8_t *>(&re); 318 std::copy(mBuffer.data() + mReadPtr, mBuffer.data() + mReadPtr + sizeof(T), ptr); 319 return re; 320 } 321 322 template <typename T> fetch()323 inline T fetch() 324 { 325 auto re = peek<T>(); 326 mReadPtr += sizeof(T); 327 return re; 328 } 329 fetch(size_t bytes)330 inline const uint8_t *fetch(size_t bytes) 331 { 332 ASSERT(mReadPtr <= mBuffer.size() - bytes); 333 auto cur = mReadPtr; 334 mReadPtr += bytes; 335 return mBuffer.data() + cur; 336 } 337 clear()338 inline void clear() 339 { 340 mBuffer.clear(); 341 mReadPtr = 0; 342 } 343 resetReadPtr(size_t readPtr)344 inline void resetReadPtr(size_t readPtr) 345 { 346 ASSERT(readPtr <= mBuffer.size()); 347 mReadPtr = readPtr; 348 } 349 good()350 inline bool good() const { return mReadPtr < mBuffer.size(); } 351 352 private: 353 std::vector<uint8_t> mBuffer; 354 size_t mReadPtr = 0; 355 }; 356 357 // Per shader stage's states 358 struct RenderCommandEncoderShaderStates 359 { 360 RenderCommandEncoderShaderStates(); 361 362 void reset(); 363 364 std::array<id<MTLBuffer>, kMaxShaderBuffers> buffers; 365 std::array<uint32_t, kMaxShaderBuffers> bufferOffsets; 366 std::array<id<MTLSamplerState>, kMaxShaderSamplers> samplers; 367 std::array<Optional<std::pair<float, float>>, kMaxShaderSamplers> samplerLodClamps; 368 std::array<id<MTLTexture>, kMaxShaderSamplers> textures; 369 }; 370 371 // Per render pass's states 372 struct RenderCommandEncoderStates 373 { 374 RenderCommandEncoderStates(); 375 376 void reset(); 377 378 id<MTLRenderPipelineState> renderPipeline; 379 380 MTLTriangleFillMode triangleFillMode; 381 MTLWinding winding; 382 MTLCullMode cullMode; 383 384 id<MTLDepthStencilState> depthStencilState; 385 float depthBias, depthSlopeScale, depthClamp; 386 387 MTLDepthClipMode depthClipMode; 388 389 uint32_t stencilFrontRef, stencilBackRef; 390 391 Optional<MTLViewport> viewport; 392 Optional<MTLScissorRect> scissorRect; 393 394 std::array<float, 4> blendColor; 395 396 gl::ShaderMap<RenderCommandEncoderShaderStates> perShaderStates; 397 398 MTLVisibilityResultMode visibilityResultMode; 399 size_t visibilityResultBufferOffset; 400 }; 401 402 // Encoder for encoding render commands 403 class RenderCommandEncoder final : public CommandEncoder 404 { 405 public: 406 RenderCommandEncoder(CommandBuffer *cmdBuffer, const OcclusionQueryPool &queryPool); 407 ~RenderCommandEncoder() override; 408 409 // override CommandEncoder valid()410 bool valid() const { return mRecording; } 411 void reset() override; 412 void endEncoding() override; 413 414 // Restart the encoder so that new commands can be encoded. 415 // NOTE: parent CommandBuffer's restart() must be called before this. 416 RenderCommandEncoder &restart(const RenderPassDesc &desc, uint32_t deviceMaxRenderTargets); 417 418 RenderCommandEncoder &setRenderPipelineState(id<MTLRenderPipelineState> state); 419 RenderCommandEncoder &setTriangleFillMode(MTLTriangleFillMode mode); 420 RenderCommandEncoder &setFrontFacingWinding(MTLWinding winding); 421 RenderCommandEncoder &setCullMode(MTLCullMode mode); 422 423 RenderCommandEncoder &setDepthStencilState(id<MTLDepthStencilState> state); 424 RenderCommandEncoder &setDepthBias(float depthBias, float slopeScale, float clamp); 425 RenderCommandEncoder &setDepthClipMode(MTLDepthClipMode depthClipMode); 426 RenderCommandEncoder &setStencilRefVals(uint32_t frontRef, uint32_t backRef); 427 RenderCommandEncoder &setStencilRefVal(uint32_t ref); 428 429 RenderCommandEncoder &setViewport(const MTLViewport &viewport); 430 RenderCommandEncoder &setScissorRect(const MTLScissorRect &rect); 431 432 RenderCommandEncoder &setBlendColor(float r, float g, float b, float a); 433 setVertexBuffer(const BufferRef & buffer,uint32_t offset,uint32_t index)434 RenderCommandEncoder &setVertexBuffer(const BufferRef &buffer, uint32_t offset, uint32_t index) 435 { 436 return setBuffer(gl::ShaderType::Vertex, buffer, offset, index); 437 } setVertexBytes(const uint8_t * bytes,size_t size,uint32_t index)438 RenderCommandEncoder &setVertexBytes(const uint8_t *bytes, size_t size, uint32_t index) 439 { 440 return setBytes(gl::ShaderType::Vertex, bytes, size, index); 441 } 442 template <typename T> setVertexData(const T & data,uint32_t index)443 RenderCommandEncoder &setVertexData(const T &data, uint32_t index) 444 { 445 return setVertexBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); 446 } setVertexSamplerState(id<MTLSamplerState> state,float lodMinClamp,float lodMaxClamp,uint32_t index)447 RenderCommandEncoder &setVertexSamplerState(id<MTLSamplerState> state, 448 float lodMinClamp, 449 float lodMaxClamp, 450 uint32_t index) 451 { 452 return setSamplerState(gl::ShaderType::Vertex, state, lodMinClamp, lodMaxClamp, index); 453 } setVertexTexture(const TextureRef & texture,uint32_t index)454 RenderCommandEncoder &setVertexTexture(const TextureRef &texture, uint32_t index) 455 { 456 return setTexture(gl::ShaderType::Vertex, texture, index); 457 } 458 setFragmentBuffer(const BufferRef & buffer,uint32_t offset,uint32_t index)459 RenderCommandEncoder &setFragmentBuffer(const BufferRef &buffer, 460 uint32_t offset, 461 uint32_t index) 462 { 463 return setBuffer(gl::ShaderType::Fragment, buffer, offset, index); 464 } setFragmentBytes(const uint8_t * bytes,size_t size,uint32_t index)465 RenderCommandEncoder &setFragmentBytes(const uint8_t *bytes, size_t size, uint32_t index) 466 { 467 return setBytes(gl::ShaderType::Fragment, bytes, size, index); 468 } 469 template <typename T> setFragmentData(const T & data,uint32_t index)470 RenderCommandEncoder &setFragmentData(const T &data, uint32_t index) 471 { 472 return setFragmentBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); 473 } setFragmentSamplerState(id<MTLSamplerState> state,float lodMinClamp,float lodMaxClamp,uint32_t index)474 RenderCommandEncoder &setFragmentSamplerState(id<MTLSamplerState> state, 475 float lodMinClamp, 476 float lodMaxClamp, 477 uint32_t index) 478 { 479 return setSamplerState(gl::ShaderType::Fragment, state, lodMinClamp, lodMaxClamp, index); 480 } setFragmentTexture(const TextureRef & texture,uint32_t index)481 RenderCommandEncoder &setFragmentTexture(const TextureRef &texture, uint32_t index) 482 { 483 return setTexture(gl::ShaderType::Fragment, texture, index); 484 } 485 486 RenderCommandEncoder &setBuffer(gl::ShaderType shaderType, 487 const BufferRef &buffer, 488 uint32_t offset, 489 uint32_t index); 490 RenderCommandEncoder &setBufferForWrite(gl::ShaderType shaderType, 491 const BufferRef &buffer, 492 uint32_t offset, 493 uint32_t index); 494 RenderCommandEncoder &setBytes(gl::ShaderType shaderType, 495 const uint8_t *bytes, 496 size_t size, 497 uint32_t index); 498 template <typename T> setData(gl::ShaderType shaderType,const T & data,uint32_t index)499 RenderCommandEncoder &setData(gl::ShaderType shaderType, const T &data, uint32_t index) 500 { 501 return setBytes(shaderType, reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); 502 } 503 RenderCommandEncoder &setSamplerState(gl::ShaderType shaderType, 504 id<MTLSamplerState> state, 505 float lodMinClamp, 506 float lodMaxClamp, 507 uint32_t index); 508 RenderCommandEncoder &setTexture(gl::ShaderType shaderType, 509 const TextureRef &texture, 510 uint32_t index); 511 RenderCommandEncoder &setRWTexture(gl::ShaderType, const TextureRef &, uint32_t index); 512 513 RenderCommandEncoder &draw(MTLPrimitiveType primitiveType, 514 uint32_t vertexStart, 515 uint32_t vertexCount); 516 RenderCommandEncoder &drawInstanced(MTLPrimitiveType primitiveType, 517 uint32_t vertexStart, 518 uint32_t vertexCount, 519 uint32_t instances); 520 RenderCommandEncoder &drawInstancedBaseInstance(MTLPrimitiveType primitiveType, 521 uint32_t vertexStart, 522 uint32_t vertexCount, 523 uint32_t instances, 524 uint32_t baseInstance); 525 RenderCommandEncoder &drawIndexed(MTLPrimitiveType primitiveType, 526 uint32_t indexCount, 527 MTLIndexType indexType, 528 const BufferRef &indexBuffer, 529 size_t bufferOffset); 530 RenderCommandEncoder &drawIndexedInstanced(MTLPrimitiveType primitiveType, 531 uint32_t indexCount, 532 MTLIndexType indexType, 533 const BufferRef &indexBuffer, 534 size_t bufferOffset, 535 uint32_t instances); 536 RenderCommandEncoder &drawIndexedInstancedBaseVertexBaseInstance(MTLPrimitiveType primitiveType, 537 uint32_t indexCount, 538 MTLIndexType indexType, 539 const BufferRef &indexBuffer, 540 size_t bufferOffset, 541 uint32_t instances, 542 uint32_t baseVertex, 543 uint32_t baseInstance); 544 545 RenderCommandEncoder &setVisibilityResultMode(MTLVisibilityResultMode mode, size_t offset); 546 547 RenderCommandEncoder &useResource(const BufferRef &resource, 548 MTLResourceUsage usage, 549 mtl::RenderStages states); 550 551 RenderCommandEncoder &memoryBarrier(mtl::BarrierScope, 552 mtl::RenderStages after, 553 mtl::RenderStages before); 554 555 RenderCommandEncoder &memoryBarrierWithResource(const BufferRef &resource, 556 mtl::RenderStages after, 557 mtl::RenderStages before); 558 559 RenderCommandEncoder &setColorStoreAction(MTLStoreAction action, uint32_t colorAttachmentIndex); 560 // Set store action for every color attachment. 561 RenderCommandEncoder &setColorStoreAction(MTLStoreAction action); 562 563 RenderCommandEncoder &setDepthStencilStoreAction(MTLStoreAction depthStoreAction, 564 MTLStoreAction stencilStoreAction); 565 RenderCommandEncoder &setDepthStoreAction(MTLStoreAction action); 566 RenderCommandEncoder &setStencilStoreAction(MTLStoreAction action); 567 568 // Set storeaction for every color & depth & stencil attachment. 569 RenderCommandEncoder &setStoreAction(MTLStoreAction action); 570 571 // Change the render pass's loadAction. Note that this operation is only allowed when there 572 // is no draw call recorded yet. 573 RenderCommandEncoder &setColorLoadAction(MTLLoadAction action, 574 const MTLClearColor &clearValue, 575 uint32_t colorAttachmentIndex); 576 RenderCommandEncoder &setDepthLoadAction(MTLLoadAction action, double clearValue); 577 RenderCommandEncoder &setStencilLoadAction(MTLLoadAction action, uint32_t clearValue); 578 579 void setLabel(NSString *label); 580 581 void pushDebugGroup(NSString *label) override; 582 void popDebugGroup() override; 583 renderPassDesc()584 const RenderPassDesc &renderPassDesc() const { return mRenderPassDesc; } hasDrawCalls()585 bool hasDrawCalls() const { return mHasDrawCalls; } 586 getSerial()587 uint64_t getSerial() const { return mSerial; } 588 589 private: 590 // Override CommandEncoder get()591 id<MTLRenderCommandEncoder> get() 592 { 593 return static_cast<id<MTLRenderCommandEncoder>>(CommandEncoder::get()); 594 } 595 void insertDebugSignImpl(NSString *label) override; 596 597 void initAttachmentWriteDependencyAndScissorRect(const RenderPassAttachmentDesc &attachment); 598 void initWriteDependency(const TextureRef &texture); 599 600 bool finalizeLoadStoreAction(MTLRenderPassAttachmentDescriptor *objCRenderPassAttachment); 601 602 void encodeMetalEncoder(); 603 void simulateDiscardFramebuffer(); 604 void endEncodingImpl(bool considerDiscardSimulation); 605 606 RenderCommandEncoder &commonSetBuffer(gl::ShaderType shaderType, 607 id<MTLBuffer> mtlBuffer, 608 uint32_t offset, 609 uint32_t index); 610 611 RenderPassDesc mRenderPassDesc; 612 // Cached Objective-C render pass desc to avoid re-allocate every frame. 613 mtl::AutoObjCObj<MTLRenderPassDescriptor> mCachedRenderPassDescObjC; 614 615 mtl::AutoObjCObj<NSString> mLabel; 616 617 MTLScissorRect mRenderPassMaxScissorRect; 618 619 const OcclusionQueryPool &mOcclusionQueryPool; 620 bool mRecording = false; 621 bool mHasDrawCalls = false; 622 IntermediateCommandStream mCommands; 623 624 gl::ShaderMap<uint8_t> mSetBufferCmds; 625 gl::ShaderMap<uint8_t> mSetBufferOffsetCmds; 626 gl::ShaderMap<uint8_t> mSetBytesCmds; 627 gl::ShaderMap<uint8_t> mSetTextureCmds; 628 gl::ShaderMap<uint8_t> mSetSamplerCmds; 629 630 RenderCommandEncoderStates mStateCache = {}; 631 632 bool mPipelineStateSet = false; 633 const uint64_t mSerial = 0; 634 }; 635 636 class BlitCommandEncoder final : public CommandEncoder 637 { 638 public: 639 BlitCommandEncoder(CommandBuffer *cmdBuffer); 640 ~BlitCommandEncoder() override; 641 642 // Restart the encoder so that new commands can be encoded. 643 // NOTE: parent CommandBuffer's restart() must be called before this. 644 BlitCommandEncoder &restart(); 645 646 BlitCommandEncoder ©Buffer(const BufferRef &src, 647 size_t srcOffset, 648 const BufferRef &dst, 649 size_t dstOffset, 650 size_t size); 651 652 BlitCommandEncoder ©BufferToTexture(const BufferRef &src, 653 size_t srcOffset, 654 size_t srcBytesPerRow, 655 size_t srcBytesPerImage, 656 MTLSize srcSize, 657 const TextureRef &dst, 658 uint32_t dstSlice, 659 MipmapNativeLevel dstLevel, 660 MTLOrigin dstOrigin, 661 MTLBlitOption blitOption); 662 663 BlitCommandEncoder ©TextureToBuffer(const TextureRef &src, 664 uint32_t srcSlice, 665 MipmapNativeLevel srcLevel, 666 MTLOrigin srcOrigin, 667 MTLSize srcSize, 668 const BufferRef &dst, 669 size_t dstOffset, 670 size_t dstBytesPerRow, 671 size_t dstBytesPerImage, 672 MTLBlitOption blitOption); 673 674 BlitCommandEncoder ©Texture(const TextureRef &src, 675 uint32_t srcSlice, 676 MipmapNativeLevel srcLevel, 677 const TextureRef &dst, 678 uint32_t dstSlice, 679 MipmapNativeLevel dstLevel, 680 uint32_t sliceCount, 681 uint32_t levelCount); 682 683 BlitCommandEncoder &fillBuffer(const BufferRef &buffer, NSRange range, uint8_t value); 684 685 BlitCommandEncoder &generateMipmapsForTexture(const TextureRef &texture); 686 BlitCommandEncoder &synchronizeResource(Buffer *bufferPtr); 687 BlitCommandEncoder &synchronizeResource(Texture *texturePtr); 688 689 private: get()690 id<MTLBlitCommandEncoder> get() 691 { 692 return static_cast<id<MTLBlitCommandEncoder>>(CommandEncoder::get()); 693 } 694 }; 695 696 class ComputeCommandEncoder final : public CommandEncoder 697 { 698 public: 699 ComputeCommandEncoder(CommandBuffer *cmdBuffer); 700 ~ComputeCommandEncoder() override; 701 702 // Restart the encoder so that new commands can be encoded. 703 // NOTE: parent CommandBuffer's restart() must be called before this. 704 ComputeCommandEncoder &restart(); 705 706 ComputeCommandEncoder &setComputePipelineState(id<MTLComputePipelineState> state); 707 708 ComputeCommandEncoder &setBuffer(const BufferRef &buffer, uint32_t offset, uint32_t index); 709 ComputeCommandEncoder &setBufferForWrite(const BufferRef &buffer, 710 uint32_t offset, 711 uint32_t index); 712 ComputeCommandEncoder &setBytes(const uint8_t *bytes, size_t size, uint32_t index); 713 template <typename T> setData(const T & data,uint32_t index)714 ComputeCommandEncoder &setData(const T &data, uint32_t index) 715 { 716 return setBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); 717 } 718 ComputeCommandEncoder &setSamplerState(id<MTLSamplerState> state, 719 float lodMinClamp, 720 float lodMaxClamp, 721 uint32_t index); 722 ComputeCommandEncoder &setTexture(const TextureRef &texture, uint32_t index); 723 ComputeCommandEncoder &setTextureForWrite(const TextureRef &texture, uint32_t index); 724 725 ComputeCommandEncoder &dispatch(const MTLSize &threadGroupsPerGrid, 726 const MTLSize &threadsPerGroup); 727 728 ComputeCommandEncoder &dispatchNonUniform(const MTLSize &threadsPerGrid, 729 const MTLSize &threadsPerGroup); 730 731 private: get()732 id<MTLComputeCommandEncoder> get() 733 { 734 return static_cast<id<MTLComputeCommandEncoder>>(CommandEncoder::get()); 735 } 736 }; 737 738 } // namespace mtl 739 } // namespace rx 740 741 #endif /* LIBANGLE_RENDERER_METAL_COMMANDENBUFFERMTL_H_ */ 742