• 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 
17 #include <deque>
18 #include <memory>
19 #include <mutex>
20 #include <thread>
21 #include <unordered_set>
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 class CommandBuffer;
36 class CommandEncoder;
37 class RenderCommandEncoder;
38 
39 class CommandQueue final : public WrappedObject<id<MTLCommandQueue>>, angle::NonCopyable
40 {
41   public:
42     void reset();
43     void set(id<MTLCommandQueue> metalQueue);
44 
45     void finishAllCommands();
46 
47     // This method will ensure that every GPU command buffer using this resource will finish before
48     // returning. Note: this doesn't include the "in-progress" command buffer, i.e. the one hasn't
49     // been commmitted yet. It's the responsibility of caller to make sure that command buffer is
50     // commited/flushed first before calling this method.
51     void ensureResourceReadyForCPU(const ResourceRef &resource);
52     void ensureResourceReadyForCPU(Resource *resource);
53 
54     // Check whether the resource is being used by any command buffer still running on GPU.
55     // This must be called before attempting to read the content of resource on CPU side.
isResourceBeingUsedByGPU(const ResourceRef & resource)56     bool isResourceBeingUsedByGPU(const ResourceRef &resource) const
57     {
58         return isResourceBeingUsedByGPU(resource.get());
59     }
60     bool isResourceBeingUsedByGPU(const Resource *resource) const;
61 
62     CommandQueue &operator=(id<MTLCommandQueue> metalQueue)
63     {
64         set(metalQueue);
65         return *this;
66     }
67 
68     AutoObjCPtr<id<MTLCommandBuffer>> makeMetalCommandBuffer(uint64_t *queueSerialOut);
69 
70   private:
71     void onCommandBufferCompleted(id<MTLCommandBuffer> buf, uint64_t serial);
72     using ParentClass = WrappedObject<id<MTLCommandQueue>>;
73 
74     struct CmdBufferQueueEntry
75     {
76         AutoObjCPtr<id<MTLCommandBuffer>> buffer;
77         uint64_t serial;
78     };
79     std::deque<CmdBufferQueueEntry> mMetalCmdBuffers;
80     std::deque<CmdBufferQueueEntry> mMetalCmdBuffersTmp;
81 
82     uint64_t mQueueSerialCounter = 1;
83     std::atomic<uint64_t> mCompletedBufferSerial{0};
84 
85     mutable std::mutex mLock;
86 };
87 
88 class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::NonCopyable
89 {
90   public:
91     CommandBuffer(CommandQueue *cmdQueue);
92     ~CommandBuffer();
93 
94     void restart();
95 
96     bool valid() const;
97     void commit();
98     void finish();
99 
100     void present(id<CAMetalDrawable> presentationDrawable);
101 
102     void setWriteDependency(const ResourceRef &resource);
103     void setReadDependency(const ResourceRef &resource);
104 
cmdQueue()105     CommandQueue &cmdQueue() { return mCmdQueue; }
106 
107     void setActiveCommandEncoder(CommandEncoder *encoder);
108     void invalidateActiveCommandEncoder(CommandEncoder *encoder);
109 
110   private:
111     void set(id<MTLCommandBuffer> metalBuffer);
112     void cleanup();
113 
114     bool validImpl() const;
115     void commitImpl();
116 
117     using ParentClass = WrappedObject<id<MTLCommandBuffer>>;
118 
119     CommandQueue &mCmdQueue;
120 
121     std::atomic<CommandEncoder *> mActiveCommandEncoder{nullptr};
122 
123     uint64_t mQueueSerial = 0;
124 
125     mutable std::mutex mLock;
126 
127     bool mCommitted = false;
128 };
129 
130 class CommandEncoder : public WrappedObject<id<MTLCommandEncoder>>, angle::NonCopyable
131 {
132   public:
133     enum Type
134     {
135         RENDER,
136         BLIT,
137         COMPUTE,
138     };
139 
140     virtual ~CommandEncoder();
141 
142     virtual void endEncoding();
143 
144     void reset();
getType()145     Type getType() const { return mType; }
146 
147     CommandEncoder &markResourceBeingWrittenByGPU(const BufferRef &buffer);
148     CommandEncoder &markResourceBeingWrittenByGPU(const TextureRef &texture);
149 
150   protected:
151     using ParentClass = WrappedObject<id<MTLCommandEncoder>>;
152 
153     CommandEncoder(CommandBuffer *cmdBuffer, Type type);
154 
cmdBuffer()155     CommandBuffer &cmdBuffer() { return mCmdBuffer; }
cmdQueue()156     CommandQueue &cmdQueue() { return mCmdBuffer.cmdQueue(); }
157 
158     void set(id<MTLCommandEncoder> metalCmdEncoder);
159 
160   private:
161     const Type mType;
162     CommandBuffer &mCmdBuffer;
163 };
164 
165 class RenderCommandEncoder final : public CommandEncoder
166 {
167   public:
168     RenderCommandEncoder(CommandBuffer *cmdBuffer);
169     ~RenderCommandEncoder() override;
170 
171     void endEncoding() override;
172 
173     RenderCommandEncoder &restart(const RenderPassDesc &desc);
174 
175     RenderCommandEncoder &setRenderPipelineState(id<MTLRenderPipelineState> state);
176     RenderCommandEncoder &setTriangleFillMode(MTLTriangleFillMode mode);
177     RenderCommandEncoder &setFrontFacingWinding(MTLWinding winding);
178     RenderCommandEncoder &setCullMode(MTLCullMode mode);
179 
180     RenderCommandEncoder &setDepthStencilState(id<MTLDepthStencilState> state);
181     RenderCommandEncoder &setDepthBias(float depthBias, float slopeScale, float clamp);
182     RenderCommandEncoder &setStencilRefVals(uint32_t frontRef, uint32_t backRef);
183     RenderCommandEncoder &setStencilRefVal(uint32_t ref);
184 
185     RenderCommandEncoder &setViewport(const MTLViewport &viewport);
186     RenderCommandEncoder &setScissorRect(const MTLScissorRect &rect);
187 
188     RenderCommandEncoder &setBlendColor(float r, float g, float b, float a);
189 
190     RenderCommandEncoder &setVertexBuffer(const BufferRef &buffer, uint32_t offset, uint32_t index);
191     RenderCommandEncoder &setVertexBytes(const uint8_t *bytes, size_t size, uint32_t index);
192     template <typename T>
setVertexData(const T & data,uint32_t index)193     RenderCommandEncoder &setVertexData(const T &data, uint32_t index)
194     {
195         return setVertexBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index);
196     }
197     RenderCommandEncoder &setVertexSamplerState(id<MTLSamplerState> state,
198                                                 float lodMinClamp,
199                                                 float lodMaxClamp,
200                                                 uint32_t index);
201     RenderCommandEncoder &setVertexTexture(const TextureRef &texture, uint32_t index);
202 
203     RenderCommandEncoder &setFragmentBuffer(const BufferRef &buffer,
204                                             uint32_t offset,
205                                             uint32_t index);
206     RenderCommandEncoder &setFragmentBytes(const uint8_t *bytes, size_t size, uint32_t index);
207     template <typename T>
setFragmentData(const T & data,uint32_t index)208     RenderCommandEncoder &setFragmentData(const T &data, uint32_t index)
209     {
210         return setFragmentBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index);
211     }
212     RenderCommandEncoder &setFragmentSamplerState(id<MTLSamplerState> state,
213                                                   float lodMinClamp,
214                                                   float lodMaxClamp,
215                                                   uint32_t index);
216     RenderCommandEncoder &setFragmentTexture(const TextureRef &texture, uint32_t index);
217 
218     RenderCommandEncoder &draw(MTLPrimitiveType primitiveType,
219                                uint32_t vertexStart,
220                                uint32_t vertexCount);
221     RenderCommandEncoder &drawInstanced(MTLPrimitiveType primitiveType,
222                                         uint32_t vertexStart,
223                                         uint32_t vertexCount,
224                                         uint32_t instances);
225     RenderCommandEncoder &drawIndexed(MTLPrimitiveType primitiveType,
226                                       uint32_t indexCount,
227                                       MTLIndexType indexType,
228                                       const BufferRef &indexBuffer,
229                                       size_t bufferOffset);
230     RenderCommandEncoder &drawIndexedInstanced(MTLPrimitiveType primitiveType,
231                                                uint32_t indexCount,
232                                                MTLIndexType indexType,
233                                                const BufferRef &indexBuffer,
234                                                size_t bufferOffset,
235                                                uint32_t instances);
236     RenderCommandEncoder &drawIndexedInstancedBaseVertex(MTLPrimitiveType primitiveType,
237                                                          uint32_t indexCount,
238                                                          MTLIndexType indexType,
239                                                          const BufferRef &indexBuffer,
240                                                          size_t bufferOffset,
241                                                          uint32_t instances,
242                                                          uint32_t baseVertex);
243 
244     RenderCommandEncoder &setColorStoreAction(MTLStoreAction action, uint32_t colorAttachmentIndex);
245     // Set store action for every color attachment.
246     RenderCommandEncoder &setColorStoreAction(MTLStoreAction action);
247 
248     RenderCommandEncoder &setDepthStencilStoreAction(MTLStoreAction depthStoreAction,
249                                                      MTLStoreAction stencilStoreAction);
250     RenderCommandEncoder &setDepthStoreAction(MTLStoreAction action);
251     RenderCommandEncoder &setStencilStoreAction(MTLStoreAction action);
252 
renderPassDesc()253     const RenderPassDesc &renderPassDesc() const { return mRenderPassDesc; }
254 
255   private:
get()256     id<MTLRenderCommandEncoder> get()
257     {
258         return static_cast<id<MTLRenderCommandEncoder>>(CommandEncoder::get());
259     }
260     inline void initWriteDependencyAndStoreAction(const TextureRef &texture,
261                                                   MTLStoreAction *storeActionOut);
262 
263     RenderPassDesc mRenderPassDesc;
264     MTLStoreAction mColorInitialStoreActions[kMaxRenderTargets];
265     MTLStoreAction mDepthInitialStoreAction;
266     MTLStoreAction mStencilInitialStoreAction;
267 };
268 
269 class BlitCommandEncoder final : public CommandEncoder
270 {
271   public:
272     BlitCommandEncoder(CommandBuffer *cmdBuffer);
273     ~BlitCommandEncoder() override;
274 
275     BlitCommandEncoder &restart();
276 
277     BlitCommandEncoder &copyBufferToTexture(const BufferRef &src,
278                                             size_t srcOffset,
279                                             size_t srcBytesPerRow,
280                                             size_t srcBytesPerImage,
281                                             MTLSize srcSize,
282                                             const TextureRef &dst,
283                                             uint32_t dstSlice,
284                                             uint32_t dstLevel,
285                                             MTLOrigin dstOrigin,
286                                             MTLBlitOption blitOption);
287 
288     BlitCommandEncoder &copyTexture(const TextureRef &dst,
289                                     uint32_t dstSlice,
290                                     uint32_t dstLevel,
291                                     MTLOrigin dstOrigin,
292                                     MTLSize dstSize,
293                                     const TextureRef &src,
294                                     uint32_t srcSlice,
295                                     uint32_t srcLevel,
296                                     MTLOrigin srcOrigin);
297 
298     BlitCommandEncoder &generateMipmapsForTexture(const TextureRef &texture);
299     BlitCommandEncoder &synchronizeResource(const TextureRef &texture);
300 
301   private:
get()302     id<MTLBlitCommandEncoder> get()
303     {
304         return static_cast<id<MTLBlitCommandEncoder>>(CommandEncoder::get());
305     }
306 };
307 
308 class ComputeCommandEncoder final : public CommandEncoder
309 {
310   public:
311     ComputeCommandEncoder(CommandBuffer *cmdBuffer);
312     ~ComputeCommandEncoder() override;
313 
314     ComputeCommandEncoder &restart();
315 
316     ComputeCommandEncoder &setComputePipelineState(id<MTLComputePipelineState> state);
317 
318     ComputeCommandEncoder &setBuffer(const BufferRef &buffer, uint32_t offset, uint32_t index);
319     ComputeCommandEncoder &setBytes(const uint8_t *bytes, size_t size, uint32_t index);
320     template <typename T>
setData(const T & data,uint32_t index)321     ComputeCommandEncoder &setData(const T &data, uint32_t index)
322     {
323         return setBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index);
324     }
325     ComputeCommandEncoder &setSamplerState(id<MTLSamplerState> state,
326                                            float lodMinClamp,
327                                            float lodMaxClamp,
328                                            uint32_t index);
329     ComputeCommandEncoder &setTexture(const TextureRef &texture, uint32_t index);
330 
331     ComputeCommandEncoder &dispatch(MTLSize threadGroupsPerGrid, MTLSize threadsPerGroup);
332 
333     ComputeCommandEncoder &dispatchNonUniform(MTLSize threadsPerGrid, MTLSize threadsPerGroup);
334 
335   private:
get()336     id<MTLComputeCommandEncoder> get()
337     {
338         return static_cast<id<MTLComputeCommandEncoder>>(CommandEncoder::get());
339     }
340 };
341 
342 }  // namespace mtl
343 }  // namespace rx
344 
345 #endif /* LIBANGLE_RENDERER_METAL_COMMANDENBUFFERMTL_H_ */
346