| // |
| // 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. |
| // |
| // BufferMtl.h: |
| // Defines the class interface for BufferMtl, implementing BufferImpl. |
| // |
| |
| #ifndef LIBANGLE_RENDERER_METAL_BUFFERMTL_H_ |
| #define LIBANGLE_RENDERER_METAL_BUFFERMTL_H_ |
| |
| #import <Metal/Metal.h> |
| |
| #include <utility> |
| |
| #include "libANGLE/Buffer.h" |
| #include "libANGLE/Observer.h" |
| #include "libANGLE/angletypes.h" |
| #include "libANGLE/renderer/BufferImpl.h" |
| #include "libANGLE/renderer/Format.h" |
| #include "libANGLE/renderer/metal/mtl_buffer_pool.h" |
| #include "libANGLE/renderer/metal/mtl_resources.h" |
| |
| namespace rx |
| { |
| |
| // Conversion buffers hold translated index and vertex data. |
| struct ConversionBufferMtl |
| { |
| ConversionBufferMtl(const gl::Context *context, size_t initialSize, size_t alignment); |
| ~ConversionBufferMtl(); |
| |
| // One state value determines if we need to re-stream vertex data. |
| bool dirty; |
| |
| // The conversion is stored in a dynamic buffer. |
| mtl::BufferPool data; |
| }; |
| |
| struct IndexConversionBufferMtl : public ConversionBufferMtl |
| { |
| IndexConversionBufferMtl(const gl::Context *context, |
| gl::DrawElementsType type, |
| size_t offsetIn); |
| |
| const gl::DrawElementsType type; |
| const size_t offset; |
| |
| // These properties are to be filled by user of this buffer conversion |
| mtl::BufferRef convertedBuffer; |
| size_t convertedOffset; |
| }; |
| |
| class BufferHolderMtl |
| { |
| public: |
| virtual ~BufferHolderMtl() = default; |
| |
| // Due to the complication of synchronizing accesses between CPU and GPU, |
| // a mtl::Buffer might be under used by GPU but CPU wants to modify its content through |
| // map() method, this could lead to GPU stalling. The more efficient method is maintain |
| // a queue of mtl::Buffer and only let CPU modifies a free mtl::Buffer. |
| // So, in order to let GPU use the most recent modified content, one must call this method |
| // right before the draw call to retrieved the most up-to-date mtl::Buffer. |
| mtl::BufferRef getCurrentBuffer(const gl::Context *context) |
| { |
| return mIsWeak ? mBufferWeakRef.lock() : mBuffer; |
| } |
| |
| protected: |
| mtl::BufferRef mBuffer; |
| mtl::BufferWeakRef mBufferWeakRef; |
| bool mIsWeak = false; |
| }; |
| |
| class BufferMtl : public BufferImpl, public BufferHolderMtl |
| { |
| public: |
| BufferMtl(const gl::BufferState &state); |
| ~BufferMtl() override; |
| void destroy(const gl::Context *context) override; |
| |
| angle::Result setData(const gl::Context *context, |
| gl::BufferBinding target, |
| const void *data, |
| size_t size, |
| gl::BufferUsage usage) override; |
| angle::Result setSubData(const gl::Context *context, |
| gl::BufferBinding target, |
| const void *data, |
| size_t size, |
| size_t offset) override; |
| angle::Result copySubData(const gl::Context *context, |
| BufferImpl *source, |
| GLintptr sourceOffset, |
| GLintptr destOffset, |
| GLsizeiptr size) override; |
| angle::Result map(const gl::Context *context, GLenum access, void **mapPtr) override; |
| angle::Result mapRange(const gl::Context *context, |
| size_t offset, |
| size_t length, |
| GLbitfield access, |
| void **mapPtr) override; |
| angle::Result unmap(const gl::Context *context, GLboolean *result) override; |
| |
| angle::Result getIndexRange(const gl::Context *context, |
| gl::DrawElementsType type, |
| size_t offset, |
| size_t count, |
| bool primitiveRestartEnabled, |
| gl::IndexRange *outRange) override; |
| |
| angle::Result getFirstLastIndices(const gl::Context *context, |
| gl::DrawElementsType type, |
| size_t offset, |
| size_t count, |
| std::pair<uint32_t, uint32_t> *outIndices) const; |
| |
| const uint8_t *getClientShadowCopyData(const gl::Context *context); |
| |
| ConversionBufferMtl *getVertexConversionBuffer(const gl::Context *context, |
| angle::FormatID formatID, |
| GLuint stride, |
| size_t offset); |
| |
| IndexConversionBufferMtl *getIndexConversionBuffer(const gl::Context *context, |
| gl::DrawElementsType type, |
| size_t offset); |
| |
| size_t size() const { return mState.getSize(); } |
| |
| private: |
| angle::Result setSubDataImpl(const gl::Context *context, |
| const void *data, |
| size_t size, |
| size_t offset); |
| |
| angle::Result commitShadowCopy(const gl::Context *context); |
| |
| void markConversionBuffersDirty(); |
| |
| // Client side shadow buffer |
| angle::MemoryBuffer mShadowCopy; |
| |
| // GPU side buffers pool |
| mtl::BufferPool mBufferPool; |
| |
| struct VertexConversionBuffer : public ConversionBufferMtl |
| { |
| VertexConversionBuffer(const gl::Context *context, |
| angle::FormatID formatIDIn, |
| GLuint strideIn, |
| size_t offsetIn); |
| |
| // The conversion is identified by the triple of {format, stride, offset}. |
| angle::FormatID formatID; |
| GLuint stride; |
| size_t offset; |
| }; |
| |
| // A cache of converted vertex data. |
| std::vector<VertexConversionBuffer> mVertexConversionBuffers; |
| |
| std::vector<IndexConversionBufferMtl> mIndexConversionBuffers; |
| }; |
| |
| class SimpleWeakBufferHolderMtl : public BufferHolderMtl |
| { |
| public: |
| SimpleWeakBufferHolderMtl(); |
| |
| void set(const mtl::BufferRef &buffer) { mBufferWeakRef = buffer; } |
| }; |
| |
| } // namespace rx |
| |
| #endif /* LIBANGLE_RENDERER_METAL_BUFFERMTL_H_ */ |