xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/BufferMtl.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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