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 getNextRenderPassEncoderSerial(); 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 // Queues the event and returns the current command buffer queue serial. 173 uint64_t queueEventSignal(id<MTLEvent> event, uint64_t value); 174 void serverWaitEvent(id<MTLEvent> event, uint64_t value); 175 176 void insertDebugSign(const std::string &marker); 177 void pushDebugGroup(const std::string &marker); 178 void popDebugGroup(); 179 cmdQueue()180 CommandQueue &cmdQueue() { return mCmdQueue; } cmdQueue()181 const CommandQueue &cmdQueue() const { return mCmdQueue; } 182 183 // Private use only 184 void setActiveCommandEncoder(CommandEncoder *encoder); 185 void invalidateActiveCommandEncoder(CommandEncoder *encoder); 186 187 bool needsFlushForDrawCallLimits() const; 188 189 uint64_t getQueueSerial() const; 190 191 private: 192 void set(id<MTLCommandBuffer> metalBuffer); 193 194 // This function returns either blit/compute encoder (if active) or render encoder. 195 // If both types of encoders are active (blit/compute and render), the former will be returned. 196 CommandEncoder *getPendingCommandEncoder(); 197 198 void cleanup(); 199 200 bool readyImpl() const; 201 bool commitImpl(); 202 void forceEndingAllEncoders(); 203 204 void setPendingEvents(); 205 void setEventImpl(id<MTLEvent> event, uint64_t value); 206 207 void pushDebugGroupImpl(const std::string &marker); 208 void popDebugGroupImpl(); 209 210 void setResourceUsedByCommandBuffer(const ResourceRef &resource); 211 void clearResourceListAndSize(); 212 213 using ParentClass = WrappedObject<id<MTLCommandBuffer>>; 214 215 CommandQueue &mCmdQueue; 216 217 // Note: due to render command encoder being a deferred encoder, it can coexist with 218 // blit/compute encoder. When submitting, blit/compute encoder will be executed before the 219 // render encoder. 220 CommandEncoder *mActiveRenderEncoder = nullptr; 221 CommandEncoder *mActiveBlitOrComputeEncoder = nullptr; 222 223 uint64_t mQueueSerial = 0; 224 225 mutable std::mutex mLock; 226 227 std::vector<std::string> mPendingDebugSigns; 228 struct PendingEvent 229 { 230 AutoObjCPtr<id<MTLEvent>> event; 231 uint64_t signalValue = 0; 232 }; 233 std::vector<PendingEvent> mPendingSignalEvents; 234 std::vector<std::string> mDebugGroups; 235 236 angle::HashSet<id> mResourceList; 237 size_t mWorkingResourceSize = 0; 238 bool mCommitted = false; 239 CommandBufferFinishOperation mLastWaitOp = mtl::NoWait; 240 }; 241 242 class CommandEncoder : public WrappedObject<id<MTLCommandEncoder>>, angle::NonCopyable 243 { 244 public: 245 enum Type 246 { 247 RENDER, 248 BLIT, 249 COMPUTE, 250 }; 251 252 virtual ~CommandEncoder(); 253 254 virtual void endEncoding(); 255 256 virtual void reset(); getType()257 Type getType() const { return mType; } 258 259 CommandEncoder &markResourceBeingWrittenByGPU(const BufferRef &buffer); 260 CommandEncoder &markResourceBeingWrittenByGPU(const TextureRef &texture); 261 262 void insertDebugSign(NSString *label); 263 264 virtual void pushDebugGroup(NSString *label); 265 virtual void popDebugGroup(); 266 267 protected: 268 using ParentClass = WrappedObject<id<MTLCommandEncoder>>; 269 270 CommandEncoder(CommandBuffer *cmdBuffer, Type type); 271 cmdBuffer()272 CommandBuffer &cmdBuffer() { return mCmdBuffer; } cmdQueue()273 CommandQueue &cmdQueue() { return mCmdBuffer.cmdQueue(); } 274 275 void set(id<MTLCommandEncoder> metalCmdEncoder); 276 277 virtual void insertDebugSignImpl(NSString *marker); 278 279 private: isRenderEncoder()280 bool isRenderEncoder() const { return getType() == Type::RENDER; } 281 282 const Type mType; 283 CommandBuffer &mCmdBuffer; 284 }; 285 286 // Stream to store commands before encoding them into the real MTLCommandEncoder 287 class IntermediateCommandStream 288 { 289 public: 290 template <typename T> push(const T & val)291 inline IntermediateCommandStream &push(const T &val) 292 { 293 auto ptr = reinterpret_cast<const uint8_t *>(&val); 294 mBuffer.insert(mBuffer.end(), ptr, ptr + sizeof(T)); 295 return *this; 296 } 297 push(const uint8_t * bytes,size_t len)298 inline IntermediateCommandStream &push(const uint8_t *bytes, size_t len) 299 { 300 mBuffer.insert(mBuffer.end(), bytes, bytes + len); 301 return *this; 302 } 303 304 template <typename T> peek()305 inline T peek() 306 { 307 ASSERT(mReadPtr <= mBuffer.size() - sizeof(T)); 308 T re; 309 auto ptr = reinterpret_cast<uint8_t *>(&re); 310 std::copy(mBuffer.data() + mReadPtr, mBuffer.data() + mReadPtr + sizeof(T), ptr); 311 return re; 312 } 313 314 template <typename T> fetch()315 inline T fetch() 316 { 317 auto re = peek<T>(); 318 mReadPtr += sizeof(T); 319 return re; 320 } 321 fetch(size_t bytes)322 inline const uint8_t *fetch(size_t bytes) 323 { 324 ASSERT(mReadPtr <= mBuffer.size() - bytes); 325 auto cur = mReadPtr; 326 mReadPtr += bytes; 327 return mBuffer.data() + cur; 328 } 329 clear()330 inline void clear() 331 { 332 mBuffer.clear(); 333 mReadPtr = 0; 334 } 335 resetReadPtr(size_t readPtr)336 inline void resetReadPtr(size_t readPtr) 337 { 338 ASSERT(readPtr <= mBuffer.size()); 339 mReadPtr = readPtr; 340 } 341 good()342 inline bool good() const { return mReadPtr < mBuffer.size(); } 343 344 private: 345 std::vector<uint8_t> mBuffer; 346 size_t mReadPtr = 0; 347 }; 348 349 // Per shader stage's states 350 struct RenderCommandEncoderShaderStates 351 { 352 RenderCommandEncoderShaderStates(); 353 354 void reset(); 355 356 std::array<id<MTLBuffer>, kMaxShaderBuffers> buffers; 357 std::array<uint32_t, kMaxShaderBuffers> bufferOffsets; 358 std::array<id<MTLSamplerState>, kMaxShaderSamplers> samplers; 359 std::array<Optional<std::pair<float, float>>, kMaxShaderSamplers> samplerLodClamps; 360 std::array<id<MTLTexture>, kMaxShaderSamplers> textures; 361 }; 362 363 // Per render pass's states 364 struct RenderCommandEncoderStates 365 { 366 RenderCommandEncoderStates(); 367 368 void reset(); 369 370 id<MTLRenderPipelineState> renderPipeline; 371 372 MTLTriangleFillMode triangleFillMode; 373 MTLWinding winding; 374 MTLCullMode cullMode; 375 376 id<MTLDepthStencilState> depthStencilState; 377 float depthBias, depthSlopeScale, depthClamp; 378 379 MTLDepthClipMode depthClipMode; 380 381 uint32_t stencilFrontRef, stencilBackRef; 382 383 Optional<MTLViewport> viewport; 384 Optional<MTLScissorRect> scissorRect; 385 386 std::array<float, 4> blendColor; 387 388 gl::ShaderMap<RenderCommandEncoderShaderStates> perShaderStates; 389 390 MTLVisibilityResultMode visibilityResultMode; 391 size_t visibilityResultBufferOffset; 392 }; 393 394 // Encoder for encoding render commands 395 class RenderCommandEncoder final : public CommandEncoder 396 { 397 public: 398 RenderCommandEncoder(CommandBuffer *cmdBuffer, 399 const OcclusionQueryPool &queryPool, 400 bool emulateDontCareLoadOpWithRandomClear); 401 ~RenderCommandEncoder() override; 402 403 // override CommandEncoder valid()404 bool valid() const { return mRecording; } 405 void reset() override; 406 void endEncoding() override; 407 408 // Restart the encoder so that new commands can be encoded. 409 // NOTE: parent CommandBuffer's restart() must be called before this. 410 RenderCommandEncoder &restart(const RenderPassDesc &desc, uint32_t deviceMaxRenderTargets); 411 412 RenderCommandEncoder &setRenderPipelineState(id<MTLRenderPipelineState> state); 413 RenderCommandEncoder &setTriangleFillMode(MTLTriangleFillMode mode); 414 RenderCommandEncoder &setFrontFacingWinding(MTLWinding winding); 415 RenderCommandEncoder &setCullMode(MTLCullMode mode); 416 417 RenderCommandEncoder &setDepthStencilState(id<MTLDepthStencilState> state); 418 RenderCommandEncoder &setDepthBias(float depthBias, float slopeScale, float clamp); 419 RenderCommandEncoder &setDepthClipMode(MTLDepthClipMode depthClipMode); 420 RenderCommandEncoder &setStencilRefVals(uint32_t frontRef, uint32_t backRef); 421 RenderCommandEncoder &setStencilRefVal(uint32_t ref); 422 423 RenderCommandEncoder &setViewport(const MTLViewport &viewport); 424 RenderCommandEncoder &setScissorRect(const MTLScissorRect &rect); 425 426 RenderCommandEncoder &setBlendColor(float r, float g, float b, float a); 427 setVertexBuffer(const BufferRef & buffer,uint32_t offset,uint32_t index)428 RenderCommandEncoder &setVertexBuffer(const BufferRef &buffer, uint32_t offset, uint32_t index) 429 { 430 return setBuffer(gl::ShaderType::Vertex, buffer, offset, index); 431 } setVertexBytes(const uint8_t * bytes,size_t size,uint32_t index)432 RenderCommandEncoder &setVertexBytes(const uint8_t *bytes, size_t size, uint32_t index) 433 { 434 return setBytes(gl::ShaderType::Vertex, bytes, size, index); 435 } 436 template <typename T> setVertexData(const T & data,uint32_t index)437 RenderCommandEncoder &setVertexData(const T &data, uint32_t index) 438 { 439 return setVertexBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); 440 } setVertexSamplerState(id<MTLSamplerState> state,float lodMinClamp,float lodMaxClamp,uint32_t index)441 RenderCommandEncoder &setVertexSamplerState(id<MTLSamplerState> state, 442 float lodMinClamp, 443 float lodMaxClamp, 444 uint32_t index) 445 { 446 return setSamplerState(gl::ShaderType::Vertex, state, lodMinClamp, lodMaxClamp, index); 447 } setVertexTexture(const TextureRef & texture,uint32_t index)448 RenderCommandEncoder &setVertexTexture(const TextureRef &texture, uint32_t index) 449 { 450 return setTexture(gl::ShaderType::Vertex, texture, index); 451 } 452 setFragmentBuffer(const BufferRef & buffer,uint32_t offset,uint32_t index)453 RenderCommandEncoder &setFragmentBuffer(const BufferRef &buffer, 454 uint32_t offset, 455 uint32_t index) 456 { 457 return setBuffer(gl::ShaderType::Fragment, buffer, offset, index); 458 } setFragmentBytes(const uint8_t * bytes,size_t size,uint32_t index)459 RenderCommandEncoder &setFragmentBytes(const uint8_t *bytes, size_t size, uint32_t index) 460 { 461 return setBytes(gl::ShaderType::Fragment, bytes, size, index); 462 } 463 template <typename T> setFragmentData(const T & data,uint32_t index)464 RenderCommandEncoder &setFragmentData(const T &data, uint32_t index) 465 { 466 return setFragmentBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); 467 } setFragmentSamplerState(id<MTLSamplerState> state,float lodMinClamp,float lodMaxClamp,uint32_t index)468 RenderCommandEncoder &setFragmentSamplerState(id<MTLSamplerState> state, 469 float lodMinClamp, 470 float lodMaxClamp, 471 uint32_t index) 472 { 473 return setSamplerState(gl::ShaderType::Fragment, state, lodMinClamp, lodMaxClamp, index); 474 } setFragmentTexture(const TextureRef & texture,uint32_t index)475 RenderCommandEncoder &setFragmentTexture(const TextureRef &texture, uint32_t index) 476 { 477 return setTexture(gl::ShaderType::Fragment, texture, index); 478 } 479 480 RenderCommandEncoder &setBuffer(gl::ShaderType shaderType, 481 const BufferRef &buffer, 482 uint32_t offset, 483 uint32_t index); 484 RenderCommandEncoder &setBufferForWrite(gl::ShaderType shaderType, 485 const BufferRef &buffer, 486 uint32_t offset, 487 uint32_t index); 488 RenderCommandEncoder &setBytes(gl::ShaderType shaderType, 489 const uint8_t *bytes, 490 size_t size, 491 uint32_t index); 492 template <typename T> setData(gl::ShaderType shaderType,const T & data,uint32_t index)493 RenderCommandEncoder &setData(gl::ShaderType shaderType, const T &data, uint32_t index) 494 { 495 return setBytes(shaderType, reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); 496 } 497 RenderCommandEncoder &setSamplerState(gl::ShaderType shaderType, 498 id<MTLSamplerState> state, 499 float lodMinClamp, 500 float lodMaxClamp, 501 uint32_t index); 502 RenderCommandEncoder &setTexture(gl::ShaderType shaderType, 503 const TextureRef &texture, 504 uint32_t index); 505 RenderCommandEncoder &setRWTexture(gl::ShaderType, const TextureRef &, uint32_t index); 506 507 RenderCommandEncoder &draw(MTLPrimitiveType primitiveType, 508 uint32_t vertexStart, 509 uint32_t vertexCount); 510 RenderCommandEncoder &drawInstanced(MTLPrimitiveType primitiveType, 511 uint32_t vertexStart, 512 uint32_t vertexCount, 513 uint32_t instances); 514 RenderCommandEncoder &drawInstancedBaseInstance(MTLPrimitiveType primitiveType, 515 uint32_t vertexStart, 516 uint32_t vertexCount, 517 uint32_t instances, 518 uint32_t baseInstance); 519 RenderCommandEncoder &drawIndexed(MTLPrimitiveType primitiveType, 520 uint32_t indexCount, 521 MTLIndexType indexType, 522 const BufferRef &indexBuffer, 523 size_t bufferOffset); 524 RenderCommandEncoder &drawIndexedInstanced(MTLPrimitiveType primitiveType, 525 uint32_t indexCount, 526 MTLIndexType indexType, 527 const BufferRef &indexBuffer, 528 size_t bufferOffset, 529 uint32_t instances); 530 RenderCommandEncoder &drawIndexedInstancedBaseVertexBaseInstance(MTLPrimitiveType primitiveType, 531 uint32_t indexCount, 532 MTLIndexType indexType, 533 const BufferRef &indexBuffer, 534 size_t bufferOffset, 535 uint32_t instances, 536 uint32_t baseVertex, 537 uint32_t baseInstance); 538 539 RenderCommandEncoder &setVisibilityResultMode(MTLVisibilityResultMode mode, size_t offset); 540 541 RenderCommandEncoder &useResource(const BufferRef &resource, 542 MTLResourceUsage usage, 543 MTLRenderStages stages); 544 545 RenderCommandEncoder &memoryBarrier(MTLBarrierScope scope, 546 MTLRenderStages after, 547 MTLRenderStages before); 548 549 RenderCommandEncoder &memoryBarrierWithResource(const BufferRef &resource, 550 MTLRenderStages after, 551 MTLRenderStages before); 552 553 RenderCommandEncoder &setColorStoreAction(MTLStoreAction action, uint32_t colorAttachmentIndex); 554 // Set store action for every color attachment. 555 RenderCommandEncoder &setColorStoreAction(MTLStoreAction action); 556 557 RenderCommandEncoder &setDepthStencilStoreAction(MTLStoreAction depthStoreAction, 558 MTLStoreAction stencilStoreAction); 559 RenderCommandEncoder &setDepthStoreAction(MTLStoreAction action); 560 RenderCommandEncoder &setStencilStoreAction(MTLStoreAction action); 561 562 // Set storeaction for every color & depth & stencil attachment. 563 RenderCommandEncoder &setStoreAction(MTLStoreAction action); 564 565 // Change the render pass's loadAction. Note that this operation is only allowed when there 566 // is no draw call recorded yet. 567 RenderCommandEncoder &setColorLoadAction(MTLLoadAction action, 568 const MTLClearColor &clearValue, 569 uint32_t colorAttachmentIndex); 570 RenderCommandEncoder &setDepthLoadAction(MTLLoadAction action, double clearValue); 571 RenderCommandEncoder &setStencilLoadAction(MTLLoadAction action, uint32_t clearValue); 572 573 void setLabel(NSString *label); 574 575 void pushDebugGroup(NSString *label) override; 576 void popDebugGroup() override; 577 renderPassDesc()578 const RenderPassDesc &renderPassDesc() const { return mRenderPassDesc; } hasDrawCalls()579 bool hasDrawCalls() const { return mHasDrawCalls; } 580 getSerial()581 uint64_t getSerial() const { return mSerial; } 582 583 private: 584 // Override CommandEncoder get()585 id<MTLRenderCommandEncoder> get() 586 { 587 return static_cast<id<MTLRenderCommandEncoder>>(CommandEncoder::get()); 588 } 589 void insertDebugSignImpl(NSString *label) override; 590 591 void initAttachmentWriteDependencyAndScissorRect(const RenderPassAttachmentDesc &attachment); 592 void initWriteDependency(const TextureRef &texture); 593 594 template <typename ObjCAttachmentDescriptor> 595 bool finalizeLoadStoreAction(const RenderPassAttachmentDesc &cppRenderPassAttachment, 596 ObjCAttachmentDescriptor *objCRenderPassAttachment); 597 598 void encodeMetalEncoder(); 599 void simulateDiscardFramebuffer(); 600 void endEncodingImpl(bool considerDiscardSimulation); 601 602 RenderCommandEncoder &commonSetBuffer(gl::ShaderType shaderType, 603 id<MTLBuffer> mtlBuffer, 604 uint32_t offset, 605 uint32_t index); 606 607 RenderPassDesc mRenderPassDesc; 608 // Cached Objective-C render pass desc to avoid re-allocate every frame. 609 mtl::AutoObjCObj<MTLRenderPassDescriptor> mCachedRenderPassDescObjC; 610 611 mtl::AutoObjCObj<NSString> mLabel; 612 613 MTLScissorRect mRenderPassMaxScissorRect; 614 615 const OcclusionQueryPool &mOcclusionQueryPool; 616 bool mRecording = false; 617 bool mHasDrawCalls = false; 618 IntermediateCommandStream mCommands; 619 620 gl::ShaderMap<uint8_t> mSetBufferCmds; 621 gl::ShaderMap<uint8_t> mSetBufferOffsetCmds; 622 gl::ShaderMap<uint8_t> mSetBytesCmds; 623 gl::ShaderMap<uint8_t> mSetTextureCmds; 624 gl::ShaderMap<uint8_t> mSetSamplerCmds; 625 626 RenderCommandEncoderStates mStateCache = {}; 627 628 bool mPipelineStateSet = false; 629 uint64_t mSerial = 0; 630 631 const bool mEmulateDontCareLoadOpWithRandomClear; 632 }; 633 634 class BlitCommandEncoder final : public CommandEncoder 635 { 636 public: 637 BlitCommandEncoder(CommandBuffer *cmdBuffer); 638 ~BlitCommandEncoder() override; 639 640 // Restart the encoder so that new commands can be encoded. 641 // NOTE: parent CommandBuffer's restart() must be called before this. 642 BlitCommandEncoder &restart(); 643 644 BlitCommandEncoder ©Buffer(const BufferRef &src, 645 size_t srcOffset, 646 const BufferRef &dst, 647 size_t dstOffset, 648 size_t size); 649 650 BlitCommandEncoder ©BufferToTexture(const BufferRef &src, 651 size_t srcOffset, 652 size_t srcBytesPerRow, 653 size_t srcBytesPerImage, 654 MTLSize srcSize, 655 const TextureRef &dst, 656 uint32_t dstSlice, 657 MipmapNativeLevel dstLevel, 658 MTLOrigin dstOrigin, 659 MTLBlitOption blitOption); 660 661 BlitCommandEncoder ©TextureToBuffer(const TextureRef &src, 662 uint32_t srcSlice, 663 MipmapNativeLevel srcLevel, 664 MTLOrigin srcOrigin, 665 MTLSize srcSize, 666 const BufferRef &dst, 667 size_t dstOffset, 668 size_t dstBytesPerRow, 669 size_t dstBytesPerImage, 670 MTLBlitOption blitOption); 671 672 BlitCommandEncoder ©Texture(const TextureRef &src, 673 uint32_t srcSlice, 674 MipmapNativeLevel srcLevel, 675 const TextureRef &dst, 676 uint32_t dstSlice, 677 MipmapNativeLevel dstLevel, 678 uint32_t sliceCount, 679 uint32_t levelCount); 680 681 BlitCommandEncoder &fillBuffer(const BufferRef &buffer, NSRange range, uint8_t value); 682 683 BlitCommandEncoder &generateMipmapsForTexture(const TextureRef &texture); 684 BlitCommandEncoder &synchronizeResource(Buffer *bufferPtr); 685 BlitCommandEncoder &synchronizeResource(Texture *texturePtr); 686 687 private: get()688 id<MTLBlitCommandEncoder> get() 689 { 690 return static_cast<id<MTLBlitCommandEncoder>>(CommandEncoder::get()); 691 } 692 }; 693 694 class ComputeCommandEncoder final : public CommandEncoder 695 { 696 public: 697 ComputeCommandEncoder(CommandBuffer *cmdBuffer); 698 ~ComputeCommandEncoder() override; 699 700 // Restart the encoder so that new commands can be encoded. 701 // NOTE: parent CommandBuffer's restart() must be called before this. 702 ComputeCommandEncoder &restart(); 703 704 ComputeCommandEncoder &setComputePipelineState(id<MTLComputePipelineState> state); 705 706 ComputeCommandEncoder &setBuffer(const BufferRef &buffer, uint32_t offset, uint32_t index); 707 ComputeCommandEncoder &setBufferForWrite(const BufferRef &buffer, 708 uint32_t offset, 709 uint32_t index); 710 ComputeCommandEncoder &setBytes(const uint8_t *bytes, size_t size, uint32_t index); 711 template <typename T> setData(const T & data,uint32_t index)712 ComputeCommandEncoder &setData(const T &data, uint32_t index) 713 { 714 return setBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); 715 } 716 ComputeCommandEncoder &setSamplerState(id<MTLSamplerState> state, 717 float lodMinClamp, 718 float lodMaxClamp, 719 uint32_t index); 720 ComputeCommandEncoder &setTexture(const TextureRef &texture, uint32_t index); 721 ComputeCommandEncoder &setTextureForWrite(const TextureRef &texture, uint32_t index); 722 723 ComputeCommandEncoder &dispatch(const MTLSize &threadGroupsPerGrid, 724 const MTLSize &threadsPerGroup); 725 726 ComputeCommandEncoder &dispatchNonUniform(const MTLSize &threadsPerGrid, 727 const MTLSize &threadsPerGroup); 728 729 private: get()730 id<MTLComputeCommandEncoder> get() 731 { 732 return static_cast<id<MTLComputeCommandEncoder>>(CommandEncoder::get()); 733 } 734 }; 735 736 } // namespace mtl 737 } // namespace rx 738 739 #endif /* LIBANGLE_RENDERER_METAL_COMMANDENBUFFERMTL_H_ */ 740