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 // BufferMtl.h: 7 // Defines the class interface for BufferMtl, implementing BufferImpl. 8 // 9 10 #ifndef LIBANGLE_RENDERER_METAL_BUFFERMTL_H_ 11 #define LIBANGLE_RENDERER_METAL_BUFFERMTL_H_ 12 13 #import <Metal/Metal.h> 14 15 #include <utility> 16 17 #include "libANGLE/Buffer.h" 18 #include "libANGLE/Observer.h" 19 #include "libANGLE/angletypes.h" 20 #include "libANGLE/renderer/BufferImpl.h" 21 #include "libANGLE/renderer/Format.h" 22 #include "libANGLE/renderer/metal/mtl_buffer_pool.h" 23 #include "libANGLE/renderer/metal/mtl_resources.h" 24 25 namespace rx 26 { 27 struct IndexRange 28 { 29 size_t restartBegin; 30 size_t restartEnd; 31 }; 32 // Conversion buffers hold translated index and vertex data. 33 struct ConversionBufferMtl 34 { 35 ConversionBufferMtl(ContextMtl *context, size_t initialSize, size_t alignment); 36 ~ConversionBufferMtl(); 37 38 // One state value determines if we need to re-stream vertex data. 39 bool dirty; 40 41 // The conversion is stored in a dynamic buffer. 42 mtl::BufferPool data; 43 // These properties are to be filled by user of this buffer conversion 44 mtl::BufferRef convertedBuffer; 45 size_t convertedOffset; 46 }; 47 48 struct VertexConversionBufferMtl : public ConversionBufferMtl 49 { 50 VertexConversionBufferMtl(ContextMtl *context, 51 angle::FormatID formatIDIn, 52 GLuint strideIn, 53 size_t offsetIn); 54 55 // The conversion is identified by the triple of {format, stride, offset}. 56 angle::FormatID formatID; 57 GLuint stride; 58 size_t offset; 59 }; 60 61 struct IndexConversionBufferMtl : public ConversionBufferMtl 62 { 63 IndexConversionBufferMtl(ContextMtl *context, 64 gl::DrawElementsType elemType, 65 bool primitiveRestartEnabled, 66 size_t offsetIn, 67 std::vector<IndexRange> restartRangesIn = std::vector<IndexRange>()); 68 const gl::DrawElementsType elemType; 69 const size_t offset; 70 bool primitiveRestartEnabled; 71 std::vector<IndexRange> restartRanges; 72 IndexRange getRangeForConvertedBuffer(size_t count); 73 }; 74 75 struct UniformConversionBufferMtl : public ConversionBufferMtl 76 { 77 UniformConversionBufferMtl(ContextMtl *context, size_t offsetIn); 78 79 const size_t offset; 80 }; 81 82 class BufferHolderMtl 83 { 84 public: 85 virtual ~BufferHolderMtl() = default; 86 87 // Due to the complication of synchronizing accesses between CPU and GPU, 88 // a mtl::Buffer might be under used by GPU but CPU wants to modify its content through 89 // map() method, this could lead to GPU stalling. The more efficient method is maintain 90 // a queue of mtl::Buffer and only let CPU modifies a free mtl::Buffer. 91 // So, in order to let GPU use the most recent modified content, one must call this method 92 // right before the draw call to retrieved the most up-to-date mtl::Buffer. getCurrentBuffer()93 mtl::BufferRef getCurrentBuffer() { return mIsWeak ? mBufferWeakRef.lock() : mBuffer; } 94 95 protected: 96 mtl::BufferRef mBuffer; 97 mtl::BufferWeakRef mBufferWeakRef; 98 bool mIsWeak = false; 99 }; 100 101 class BufferMtl : public BufferImpl, public BufferHolderMtl 102 { 103 public: 104 BufferMtl(const gl::BufferState &state); 105 ~BufferMtl() override; 106 void destroy(const gl::Context *context) override; 107 108 angle::Result setData(const gl::Context *context, 109 gl::BufferBinding target, 110 const void *data, 111 size_t size, 112 gl::BufferUsage usage) override; 113 angle::Result setSubData(const gl::Context *context, 114 gl::BufferBinding target, 115 const void *data, 116 size_t size, 117 size_t offset) override; 118 angle::Result copySubData(const gl::Context *context, 119 BufferImpl *source, 120 GLintptr sourceOffset, 121 GLintptr destOffset, 122 GLsizeiptr size) override; 123 angle::Result map(const gl::Context *context, GLenum access, void **mapPtr) override; 124 angle::Result mapRange(const gl::Context *context, 125 size_t offset, 126 size_t length, 127 GLbitfield access, 128 void **mapPtr) override; 129 angle::Result unmap(const gl::Context *context, GLboolean *result) override; 130 131 angle::Result getIndexRange(const gl::Context *context, 132 gl::DrawElementsType type, 133 size_t offset, 134 size_t count, 135 bool primitiveRestartEnabled, 136 gl::IndexRange *outRange) override; 137 138 void onDataChanged() override; 139 140 angle::Result getFirstLastIndices(ContextMtl *contextMtl, 141 gl::DrawElementsType type, 142 size_t offset, 143 size_t count, 144 std::pair<uint32_t, uint32_t> *outIndices); 145 146 const uint8_t *getClientShadowCopyData(ContextMtl *contextMtl); 147 148 ConversionBufferMtl *getVertexConversionBuffer(ContextMtl *context, 149 angle::FormatID formatID, 150 GLuint stride, 151 size_t offset); 152 153 IndexConversionBufferMtl *getIndexConversionBuffer(ContextMtl *context, 154 gl::DrawElementsType elemType, 155 bool primitiveRestartEnabled, 156 size_t offset); 157 158 ConversionBufferMtl *getUniformConversionBuffer(ContextMtl *context, size_t offset); 159 size()160 size_t size() const { return static_cast<size_t>(mState.getSize()); } 161 162 private: 163 angle::Result setDataImpl(const gl::Context *context, 164 gl::BufferBinding target, 165 const void *data, 166 size_t size, 167 gl::BufferUsage usage); 168 angle::Result setSubDataImpl(const gl::Context *context, 169 const void *data, 170 size_t size, 171 size_t offset); 172 173 angle::Result commitShadowCopy(const gl::Context *context); 174 angle::Result commitShadowCopy(const gl::Context *context, size_t size); 175 176 void markConversionBuffersDirty(); 177 178 void clearConversionBuffers(); 179 bool clientShadowCopyDataNeedSync(ContextMtl *contextMtl); 180 void ensureShadowCopySyncedFromGPU(ContextMtl *contextMtl); 181 uint8_t *syncAndObtainShadowCopy(ContextMtl *contextMtl); 182 183 // Convenient method getClientShadowCopyData(const gl::Context * context)184 const uint8_t *getClientShadowCopyData(const gl::Context *context) 185 { 186 return getClientShadowCopyData(mtl::GetImpl(context)); 187 } 188 // Client side shadow buffer 189 angle::MemoryBuffer mShadowCopy; 190 191 // GPU side buffers pool 192 mtl::BufferPool mBufferPool; 193 194 // A cache of converted vertex data. 195 std::vector<VertexConversionBufferMtl> mVertexConversionBuffers; 196 197 std::vector<IndexConversionBufferMtl> mIndexConversionBuffers; 198 199 std::vector<UniformConversionBufferMtl> mUniformConversionBuffers; 200 }; 201 202 class SimpleWeakBufferHolderMtl : public BufferHolderMtl 203 { 204 public: 205 SimpleWeakBufferHolderMtl(); 206 set(const mtl::BufferRef & buffer)207 void set(const mtl::BufferRef &buffer) { mBufferWeakRef = buffer; } 208 }; 209 210 } // namespace rx 211 212 #endif /* LIBANGLE_RENDERER_METAL_BUFFERMTL_H_ */ 213