| // | |
| // Copyright 2019 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // mtl_command_buffer.h: | |
| // Defines the wrapper classes for Metal's MTLCommandEncoder, MTLCommandQueue and | |
| // MTLCommandBuffer. | |
| // | |
| #ifndef LIBANGLE_RENDERER_METAL_COMMANDENBUFFERMTL_H_ | |
| #define LIBANGLE_RENDERER_METAL_COMMANDENBUFFERMTL_H_ | |
| #import <Metal/Metal.h> | |
| #import <QuartzCore/CAMetalLayer.h> | |
| #include <deque> | |
| #include <memory> | |
| #include <mutex> | |
| #include <thread> | |
| #include <unordered_set> | |
| #include <vector> | |
| #include "common/FixedVector.h" | |
| #include "common/angleutils.h" | |
| #include "libANGLE/renderer/metal/mtl_common.h" | |
| #include "libANGLE/renderer/metal/mtl_resources.h" | |
| #include "libANGLE/renderer/metal/mtl_state_cache.h" | |
| namespace rx | |
| { | |
| namespace mtl | |
| { | |
| class CommandBuffer; | |
| class CommandEncoder; | |
| class RenderCommandEncoder; | |
| class CommandQueue final : public WrappedObject<id<MTLCommandQueue>>, angle::NonCopyable | |
| { | |
| public: | |
| void reset(); | |
| void set(id<MTLCommandQueue> metalQueue); | |
| void finishAllCommands(); | |
| // This method will ensure that every GPU command buffer using this resource will finish before | |
| // returning. Note: this doesn't include the "in-progress" command buffer, i.e. the one hasn't | |
| // been commmitted yet. It's the responsibility of caller to make sure that command buffer is | |
| // commited/flushed first before calling this method. | |
| void ensureResourceReadyForCPU(const ResourceRef &resource); | |
| void ensureResourceReadyForCPU(Resource *resource); | |
| // Check whether the resource is being used by any command buffer still running on GPU. | |
| // This must be called before attempting to read the content of resource on CPU side. | |
| bool isResourceBeingUsedByGPU(const ResourceRef &resource) const | |
| { | |
| return isResourceBeingUsedByGPU(resource.get()); | |
| } | |
| bool isResourceBeingUsedByGPU(const Resource *resource) const; | |
| CommandQueue &operator=(id<MTLCommandQueue> metalQueue) | |
| { | |
| set(metalQueue); | |
| return *this; | |
| } | |
| AutoObjCPtr<id<MTLCommandBuffer>> makeMetalCommandBuffer(uint64_t *queueSerialOut); | |
| private: | |
| void onCommandBufferCompleted(id<MTLCommandBuffer> buf, uint64_t serial); | |
| using ParentClass = WrappedObject<id<MTLCommandQueue>>; | |
| struct CmdBufferQueueEntry | |
| { | |
| AutoObjCPtr<id<MTLCommandBuffer>> buffer; | |
| uint64_t serial; | |
| }; | |
| std::deque<CmdBufferQueueEntry> mMetalCmdBuffers; | |
| std::deque<CmdBufferQueueEntry> mMetalCmdBuffersTmp; | |
| uint64_t mQueueSerialCounter = 1; | |
| std::atomic<uint64_t> mCompletedBufferSerial{0}; | |
| mutable std::mutex mLock; | |
| }; | |
| class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::NonCopyable | |
| { | |
| public: | |
| CommandBuffer(CommandQueue *cmdQueue); | |
| ~CommandBuffer(); | |
| void restart(); | |
| bool valid() const; | |
| void commit(); | |
| void finish(); | |
| void present(id<CAMetalDrawable> presentationDrawable); | |
| void setWriteDependency(const ResourceRef &resource); | |
| void setReadDependency(const ResourceRef &resource); | |
| CommandQueue &cmdQueue() { return mCmdQueue; } | |
| void setActiveCommandEncoder(CommandEncoder *encoder); | |
| void invalidateActiveCommandEncoder(CommandEncoder *encoder); | |
| private: | |
| void set(id<MTLCommandBuffer> metalBuffer); | |
| void cleanup(); | |
| bool validImpl() const; | |
| void commitImpl(); | |
| using ParentClass = WrappedObject<id<MTLCommandBuffer>>; | |
| CommandQueue &mCmdQueue; | |
| std::atomic<CommandEncoder *> mActiveCommandEncoder{nullptr}; | |
| uint64_t mQueueSerial = 0; | |
| mutable std::mutex mLock; | |
| bool mCommitted = false; | |
| }; | |
| class CommandEncoder : public WrappedObject<id<MTLCommandEncoder>>, angle::NonCopyable | |
| { | |
| public: | |
| enum Type | |
| { | |
| RENDER, | |
| BLIT, | |
| COMPUTE, | |
| }; | |
| virtual ~CommandEncoder(); | |
| virtual void endEncoding(); | |
| void reset(); | |
| Type getType() const { return mType; } | |
| CommandEncoder &markResourceBeingWrittenByGPU(const BufferRef &buffer); | |
| CommandEncoder &markResourceBeingWrittenByGPU(const TextureRef &texture); | |
| protected: | |
| using ParentClass = WrappedObject<id<MTLCommandEncoder>>; | |
| CommandEncoder(CommandBuffer *cmdBuffer, Type type); | |
| CommandBuffer &cmdBuffer() { return mCmdBuffer; } | |
| CommandQueue &cmdQueue() { return mCmdBuffer.cmdQueue(); } | |
| void set(id<MTLCommandEncoder> metalCmdEncoder); | |
| private: | |
| const Type mType; | |
| CommandBuffer &mCmdBuffer; | |
| }; | |
| class RenderCommandEncoder final : public CommandEncoder | |
| { | |
| public: | |
| RenderCommandEncoder(CommandBuffer *cmdBuffer); | |
| ~RenderCommandEncoder() override; | |
| void endEncoding() override; | |
| RenderCommandEncoder &restart(const RenderPassDesc &desc); | |
| RenderCommandEncoder &setRenderPipelineState(id<MTLRenderPipelineState> state); | |
| RenderCommandEncoder &setTriangleFillMode(MTLTriangleFillMode mode); | |
| RenderCommandEncoder &setFrontFacingWinding(MTLWinding winding); | |
| RenderCommandEncoder &setCullMode(MTLCullMode mode); | |
| RenderCommandEncoder &setDepthStencilState(id<MTLDepthStencilState> state); | |
| RenderCommandEncoder &setDepthBias(float depthBias, float slopeScale, float clamp); | |
| RenderCommandEncoder &setStencilRefVals(uint32_t frontRef, uint32_t backRef); | |
| RenderCommandEncoder &setStencilRefVal(uint32_t ref); | |
| RenderCommandEncoder &setViewport(const MTLViewport &viewport); | |
| RenderCommandEncoder &setScissorRect(const MTLScissorRect &rect); | |
| RenderCommandEncoder &setBlendColor(float r, float g, float b, float a); | |
| RenderCommandEncoder &setVertexBuffer(const BufferRef &buffer, uint32_t offset, uint32_t index); | |
| RenderCommandEncoder &setVertexBytes(const uint8_t *bytes, size_t size, uint32_t index); | |
| template <typename T> | |
| RenderCommandEncoder &setVertexData(const T &data, uint32_t index) | |
| { | |
| return setVertexBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); | |
| } | |
| RenderCommandEncoder &setVertexSamplerState(id<MTLSamplerState> state, | |
| float lodMinClamp, | |
| float lodMaxClamp, | |
| uint32_t index); | |
| RenderCommandEncoder &setVertexTexture(const TextureRef &texture, uint32_t index); | |
| RenderCommandEncoder &setFragmentBuffer(const BufferRef &buffer, | |
| uint32_t offset, | |
| uint32_t index); | |
| RenderCommandEncoder &setFragmentBytes(const uint8_t *bytes, size_t size, uint32_t index); | |
| template <typename T> | |
| RenderCommandEncoder &setFragmentData(const T &data, uint32_t index) | |
| { | |
| return setFragmentBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); | |
| } | |
| RenderCommandEncoder &setFragmentSamplerState(id<MTLSamplerState> state, | |
| float lodMinClamp, | |
| float lodMaxClamp, | |
| uint32_t index); | |
| RenderCommandEncoder &setFragmentTexture(const TextureRef &texture, uint32_t index); | |
| RenderCommandEncoder &draw(MTLPrimitiveType primitiveType, | |
| uint32_t vertexStart, | |
| uint32_t vertexCount); | |
| RenderCommandEncoder &drawInstanced(MTLPrimitiveType primitiveType, | |
| uint32_t vertexStart, | |
| uint32_t vertexCount, | |
| uint32_t instances); | |
| RenderCommandEncoder &drawIndexed(MTLPrimitiveType primitiveType, | |
| uint32_t indexCount, | |
| MTLIndexType indexType, | |
| const BufferRef &indexBuffer, | |
| size_t bufferOffset); | |
| RenderCommandEncoder &drawIndexedInstanced(MTLPrimitiveType primitiveType, | |
| uint32_t indexCount, | |
| MTLIndexType indexType, | |
| const BufferRef &indexBuffer, | |
| size_t bufferOffset, | |
| uint32_t instances); | |
| RenderCommandEncoder &drawIndexedInstancedBaseVertex(MTLPrimitiveType primitiveType, | |
| uint32_t indexCount, | |
| MTLIndexType indexType, | |
| const BufferRef &indexBuffer, | |
| size_t bufferOffset, | |
| uint32_t instances, | |
| uint32_t baseVertex); | |
| RenderCommandEncoder &setColorStoreAction(MTLStoreAction action, uint32_t colorAttachmentIndex); | |
| // Set store action for every color attachment. | |
| RenderCommandEncoder &setColorStoreAction(MTLStoreAction action); | |
| RenderCommandEncoder &setDepthStencilStoreAction(MTLStoreAction depthStoreAction, | |
| MTLStoreAction stencilStoreAction); | |
| RenderCommandEncoder &setDepthStoreAction(MTLStoreAction action); | |
| RenderCommandEncoder &setStencilStoreAction(MTLStoreAction action); | |
| const RenderPassDesc &renderPassDesc() const { return mRenderPassDesc; } | |
| private: | |
| id<MTLRenderCommandEncoder> get() | |
| { | |
| return static_cast<id<MTLRenderCommandEncoder>>(CommandEncoder::get()); | |
| } | |
| inline void initWriteDependencyAndStoreAction(const TextureRef &texture, | |
| MTLStoreAction *storeActionOut); | |
| RenderPassDesc mRenderPassDesc; | |
| MTLStoreAction mColorInitialStoreActions[kMaxRenderTargets]; | |
| MTLStoreAction mDepthInitialStoreAction; | |
| MTLStoreAction mStencilInitialStoreAction; | |
| }; | |
| class BlitCommandEncoder final : public CommandEncoder | |
| { | |
| public: | |
| BlitCommandEncoder(CommandBuffer *cmdBuffer); | |
| ~BlitCommandEncoder() override; | |
| BlitCommandEncoder &restart(); | |
| BlitCommandEncoder ©Texture(const TextureRef &dst, | |
| uint32_t dstSlice, | |
| uint32_t dstLevel, | |
| MTLOrigin dstOrigin, | |
| MTLSize dstSize, | |
| const TextureRef &src, | |
| uint32_t srcSlice, | |
| uint32_t srcLevel, | |
| MTLOrigin srcOrigin); | |
| BlitCommandEncoder &generateMipmapsForTexture(const TextureRef &texture); | |
| BlitCommandEncoder &synchronizeResource(const TextureRef &texture); | |
| private: | |
| id<MTLBlitCommandEncoder> get() | |
| { | |
| return static_cast<id<MTLBlitCommandEncoder>>(CommandEncoder::get()); | |
| } | |
| }; | |
| class ComputeCommandEncoder final : public CommandEncoder | |
| { | |
| public: | |
| ComputeCommandEncoder(CommandBuffer *cmdBuffer); | |
| ~ComputeCommandEncoder() override; | |
| ComputeCommandEncoder &restart(); | |
| ComputeCommandEncoder &setComputePipelineState(id<MTLComputePipelineState> state); | |
| ComputeCommandEncoder &setBuffer(const BufferRef &buffer, uint32_t offset, uint32_t index); | |
| ComputeCommandEncoder &setBytes(const uint8_t *bytes, size_t size, uint32_t index); | |
| template <typename T> | |
| ComputeCommandEncoder &setData(const T &data, uint32_t index) | |
| { | |
| return setBytes(reinterpret_cast<const uint8_t *>(&data), sizeof(T), index); | |
| } | |
| ComputeCommandEncoder &setSamplerState(id<MTLSamplerState> state, | |
| float lodMinClamp, | |
| float lodMaxClamp, | |
| uint32_t index); | |
| ComputeCommandEncoder &setTexture(const TextureRef &texture, uint32_t index); | |
| ComputeCommandEncoder &dispatch(MTLSize threadGroupsPerGrid, MTLSize threadsPerGroup); | |
| ComputeCommandEncoder &dispatchNonUniform(MTLSize threadsPerGrid, MTLSize threadsPerGroup); | |
| private: | |
| id<MTLComputeCommandEncoder> get() | |
| { | |
| return static_cast<id<MTLComputeCommandEncoder>>(CommandEncoder::get()); | |
| } | |
| }; | |
| } // namespace mtl | |
| } // namespace rx | |
| #endif /* LIBANGLE_RENDERER_METAL_COMMANDENBUFFERMTL_H_ */ |