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