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