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