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