• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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