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