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 <optional> 16 #include <utility> 17 18 #include "libANGLE/Buffer.h" 19 #include "libANGLE/Observer.h" 20 #include "libANGLE/angletypes.h" 21 #include "libANGLE/renderer/BufferImpl.h" 22 #include "libANGLE/renderer/Format.h" 23 #include "libANGLE/renderer/metal/mtl_buffer_pool.h" 24 #include "libANGLE/renderer/metal/mtl_resources.h" 25 26 namespace rx 27 { 28 29 struct DrawCommandRange 30 { 31 uint32_t count; 32 size_t offset; 33 }; 34 35 // Inclusive range of consecutive primitive restart value indexes. 36 struct IndexRange 37 { IndexRangeIndexRange38 IndexRange(size_t begin, size_t end) : restartBegin(begin), restartEnd(end) {} 39 size_t restartBegin; 40 size_t restartEnd; 41 }; 42 // Conversion buffers hold translated index and vertex data. 43 struct ConversionBufferMtl 44 { 45 ConversionBufferMtl(ContextMtl *context, size_t initialSize, size_t alignment); 46 ~ConversionBufferMtl(); 47 48 // One state value determines if we need to re-stream vertex data. 49 bool dirty; 50 51 // The conversion is stored in a dynamic buffer. 52 mtl::BufferPool data; 53 // These properties are to be filled by user of this buffer conversion 54 mtl::BufferRef convertedBuffer; 55 size_t convertedOffset; 56 }; 57 58 struct VertexConversionBufferMtl : public ConversionBufferMtl 59 { 60 VertexConversionBufferMtl(ContextMtl *context, 61 angle::FormatID formatIDIn, 62 GLuint strideIn, 63 size_t offsetIn); 64 65 // The conversion is identified by the triple of {format, stride, offset}. 66 angle::FormatID formatID; 67 GLuint stride; 68 size_t offset; 69 }; 70 71 struct IndexConversionBufferMtl : public ConversionBufferMtl 72 { 73 IndexConversionBufferMtl(ContextMtl *context, 74 gl::DrawElementsType elemType, 75 bool primitiveRestartEnabled, 76 size_t offsetIn); 77 const gl::DrawElementsType elemType; 78 const size_t offset; 79 bool primitiveRestartEnabled; 80 IndexRange getRangeForConvertedBuffer(size_t count); 81 }; 82 83 struct UniformConversionBufferMtl : public ConversionBufferMtl 84 { 85 UniformConversionBufferMtl(ContextMtl *context, 86 std::pair<size_t, size_t> offsetIn, 87 size_t blockSize); 88 initialSrcOffsetUniformConversionBufferMtl89 size_t initialSrcOffset() { return offset.second; } 90 91 const size_t uniformBufferBlockSize; 92 const std::pair<size_t, size_t> offset; 93 }; 94 95 class BufferHolderMtl 96 { 97 public: 98 virtual ~BufferHolderMtl() = default; 99 100 // Due to the complication of synchronizing accesses between CPU and GPU, 101 // a mtl::Buffer might be under used by GPU but CPU wants to modify its content through 102 // map() method, this could lead to GPU stalling. The more efficient method is maintain 103 // a queue of mtl::Buffer and only let CPU modifies a free mtl::Buffer. 104 // So, in order to let GPU use the most recent modified content, one must call this method 105 // right before the draw call to retrieved the most up-to-date mtl::Buffer. getCurrentBuffer()106 mtl::BufferRef getCurrentBuffer() const { return mIsWeak ? mBufferWeakRef.lock() : mBuffer; } 107 108 protected: 109 mtl::BufferRef mBuffer; 110 mtl::BufferWeakRef mBufferWeakRef; 111 bool mIsWeak = false; 112 }; 113 114 class BufferMtl : public BufferImpl, public BufferHolderMtl 115 { 116 public: 117 BufferMtl(const gl::BufferState &state); 118 ~BufferMtl() override; 119 void destroy(const gl::Context *context) override; 120 121 angle::Result setData(const gl::Context *context, 122 gl::BufferBinding target, 123 const void *data, 124 size_t size, 125 gl::BufferUsage usage) override; 126 angle::Result setSubData(const gl::Context *context, 127 gl::BufferBinding target, 128 const void *data, 129 size_t size, 130 size_t offset) override; 131 angle::Result copySubData(const gl::Context *context, 132 BufferImpl *source, 133 GLintptr sourceOffset, 134 GLintptr destOffset, 135 GLsizeiptr size) override; 136 angle::Result map(const gl::Context *context, GLenum access, void **mapPtr) override; 137 angle::Result mapRange(const gl::Context *context, 138 size_t offset, 139 size_t length, 140 GLbitfield access, 141 void **mapPtr) override; 142 angle::Result unmap(const gl::Context *context, GLboolean *result) override; 143 144 angle::Result getIndexRange(const gl::Context *context, 145 gl::DrawElementsType type, 146 size_t offset, 147 size_t count, 148 bool primitiveRestartEnabled, 149 gl::IndexRange *outRange) override; 150 151 void onDataChanged() override; 152 153 angle::Result getFirstLastIndices(ContextMtl *contextMtl, 154 gl::DrawElementsType type, 155 size_t offset, 156 size_t count, 157 std::pair<uint32_t, uint32_t> *outIndices); 158 159 const uint8_t *getBufferDataReadOnly(ContextMtl *contextMtl); 160 bool isSafeToReadFromBufferViaBlit(ContextMtl *contextMtl); 161 162 ConversionBufferMtl *getVertexConversionBuffer(ContextMtl *context, 163 angle::FormatID formatID, 164 GLuint stride, 165 size_t offset); 166 167 IndexConversionBufferMtl *getIndexConversionBuffer(ContextMtl *context, 168 gl::DrawElementsType elemType, 169 bool primitiveRestartEnabled, 170 size_t offset); 171 172 ConversionBufferMtl *getUniformConversionBuffer(ContextMtl *context, 173 std::pair<size_t, size_t> offset, 174 size_t blockSize); 175 size()176 size_t size() const { return static_cast<size_t>(mState.getSize()); } 177 178 const std::vector<IndexRange> &getRestartIndices(ContextMtl *ctx, 179 gl::DrawElementsType indexType); 180 181 static const std::vector<IndexRange> getRestartIndicesFromClientData( 182 ContextMtl *ctx, 183 gl::DrawElementsType indexType, 184 const mtl::BufferRef clientBuffer); 185 186 private: 187 angle::Result allocateNewMetalBuffer(ContextMtl *contextMtl, 188 MTLStorageMode storageMode, 189 size_t size, 190 bool returnOldBufferImmediately); 191 192 angle::Result setDataImpl(const gl::Context *context, 193 gl::BufferBinding target, 194 const void *data, 195 size_t size, 196 gl::BufferUsage usage); 197 angle::Result setSubDataImpl(const gl::Context *context, 198 const void *data, 199 size_t size, 200 size_t offset); 201 202 angle::Result commitShadowCopy(ContextMtl *contextMtl); 203 angle::Result commitShadowCopy(ContextMtl *contextMtl, size_t size); 204 205 void markConversionBuffersDirty(); 206 void clearConversionBuffers(); 207 208 angle::Result putDataInNewBufferAndStartUsingNewBuffer(ContextMtl *contextMtl, 209 const uint8_t *srcPtr, 210 size_t sizeToCopy, 211 size_t offset); 212 angle::Result updateExistingBufferViaBlitFromStagingBuffer(ContextMtl *contextMtl, 213 const uint8_t *srcPtr, 214 size_t sizeToCopy, 215 size_t offset); 216 angle::Result copyDataToExistingBufferViaCPU(ContextMtl *contextMtl, 217 const uint8_t *srcPtr, 218 size_t sizeToCopy, 219 size_t offset); 220 angle::Result updateShadowCopyThenCopyShadowToNewBuffer(ContextMtl *contextMtl, 221 const uint8_t *srcPtr, 222 size_t sizeToCopy, 223 size_t offset); 224 225 bool clientShadowCopyDataNeedSync(ContextMtl *contextMtl); 226 void ensureShadowCopySyncedFromGPU(ContextMtl *contextMtl); 227 uint8_t *syncAndObtainShadowCopy(ContextMtl *contextMtl); 228 229 // Optional client side shadow buffer 230 angle::MemoryBuffer mShadowCopy; 231 232 // A cache of converted vertex data. 233 std::vector<VertexConversionBufferMtl> mVertexConversionBuffers; 234 235 std::vector<IndexConversionBufferMtl> mIndexConversionBuffers; 236 237 std::vector<UniformConversionBufferMtl> mUniformConversionBuffers; 238 239 struct RestartRangeCache 240 { RestartRangeCacheRestartRangeCache241 RestartRangeCache(std::vector<IndexRange> &&ranges_, gl::DrawElementsType indexType_) 242 : ranges(ranges_), indexType(indexType_) 243 {} 244 const std::vector<IndexRange> ranges; 245 const gl::DrawElementsType indexType; 246 }; 247 std::optional<RestartRangeCache> mRestartRangeCache; 248 std::vector<IndexRange> mRestartIndices; 249 size_t mGLSize = 0; // size GL asked for (vs size we actually allocated) 250 size_t mRevisionCount = 0; // for generating labels only 251 gl::BufferUsage mUsage; 252 }; 253 254 class SimpleWeakBufferHolderMtl : public BufferHolderMtl 255 { 256 public: 257 SimpleWeakBufferHolderMtl(); 258 set(const mtl::BufferRef & buffer)259 void set(const mtl::BufferRef &buffer) { mBufferWeakRef = buffer; } 260 }; 261 262 } // namespace rx 263 264 #endif /* LIBANGLE_RENDERER_METAL_BUFFERMTL_H_ */ 265