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