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 ©BufferToTexture(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 ©Texture(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