• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 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 // BufferVk.h:
7 //    Defines the class interface for BufferVk, implementing BufferImpl.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_VULKAN_BUFFERVK_H_
11 #define LIBANGLE_RENDERER_VULKAN_BUFFERVK_H_
12 
13 #include "libANGLE/Buffer.h"
14 #include "libANGLE/Observer.h"
15 #include "libANGLE/renderer/BufferImpl.h"
16 #include "libANGLE/renderer/vulkan/vk_helpers.h"
17 
18 namespace rx
19 {
20 class RendererVk;
21 
22 // Conversion buffers hold translated index and vertex data.
23 struct ConversionBuffer
24 {
25     ConversionBuffer(RendererVk *renderer,
26                      VkBufferUsageFlags usageFlags,
27                      size_t initialSize,
28                      size_t alignment,
29                      bool hostVisible);
30     ~ConversionBuffer();
31 
32     ConversionBuffer(ConversionBuffer &&other);
33 
34     // One state value determines if we need to re-stream vertex data.
35     bool dirty;
36 
37     // One additional state value keeps the last allocation offset.
38     VkDeviceSize lastAllocationOffset;
39 
40     // The conversion is stored in a dynamic buffer.
41     vk::DynamicBuffer data;
42 };
43 
44 enum BufferUpdateType
45 {
46     StorageRedefined,
47     ContentsUpdate,
48 };
49 
50 class BufferVk : public BufferImpl
51 {
52   public:
53     BufferVk(const gl::BufferState &state);
54     ~BufferVk() override;
55     void destroy(const gl::Context *context) override;
56 
57     angle::Result setExternalBufferData(const gl::Context *context,
58                                         gl::BufferBinding target,
59                                         GLeglClientBufferEXT clientBuffer,
60                                         size_t size,
61                                         VkMemoryPropertyFlags memoryPropertyFlags);
62     angle::Result setDataWithUsageFlags(const gl::Context *context,
63                                         gl::BufferBinding target,
64                                         GLeglClientBufferEXT clientBuffer,
65                                         const void *data,
66                                         size_t size,
67                                         gl::BufferUsage usage,
68                                         GLbitfield flags) override;
69     angle::Result setData(const gl::Context *context,
70                           gl::BufferBinding target,
71                           const void *data,
72                           size_t size,
73                           gl::BufferUsage usage) override;
74     angle::Result setSubData(const gl::Context *context,
75                              gl::BufferBinding target,
76                              const void *data,
77                              size_t size,
78                              size_t offset) override;
79     angle::Result copySubData(const gl::Context *context,
80                               BufferImpl *source,
81                               GLintptr sourceOffset,
82                               GLintptr destOffset,
83                               GLsizeiptr size) override;
84     angle::Result map(const gl::Context *context, GLenum access, void **mapPtr) override;
85     angle::Result mapRange(const gl::Context *context,
86                            size_t offset,
87                            size_t length,
88                            GLbitfield access,
89                            void **mapPtr) override;
90     angle::Result unmap(const gl::Context *context, GLboolean *result) override;
91     angle::Result getSubData(const gl::Context *context,
92                              GLintptr offset,
93                              GLsizeiptr size,
94                              void *outData) override;
95 
96     angle::Result getIndexRange(const gl::Context *context,
97                                 gl::DrawElementsType type,
98                                 size_t offset,
99                                 size_t count,
100                                 bool primitiveRestartEnabled,
101                                 gl::IndexRange *outRange) override;
102 
getSize()103     GLint64 getSize() const { return mState.getSize(); }
104 
105     void onDataChanged() override;
106 
getBufferAndOffset(VkDeviceSize * offsetOut)107     vk::BufferHelper &getBufferAndOffset(VkDeviceSize *offsetOut)
108     {
109         ASSERT(isBufferValid());
110         *offsetOut = mBufferOffset;
111         // Every place try to use the buffer, it will have to call this API to get hold of the
112         // underline BufferHelper object. So this is the safe place to tell that this has ever been
113         // referenced by GPU command, whether pending submission or not.
114         mHasBeenReferencedByGPU = true;
115         return *mBuffer;
116     }
117 
isBufferValid()118     bool isBufferValid() const { return mBuffer && mBuffer->valid(); }
119     bool isCurrentlyInUse(ContextVk *contextVk) const;
120 
121     angle::Result mapImpl(ContextVk *contextVk, GLbitfield access, void **mapPtr);
122     angle::Result mapRangeImpl(ContextVk *contextVk,
123                                VkDeviceSize offset,
124                                VkDeviceSize length,
125                                GLbitfield access,
126                                void **mapPtr);
127     angle::Result unmapImpl(ContextVk *contextVk);
128     angle::Result ghostMappedBuffer(ContextVk *contextVk,
129                                     VkDeviceSize offset,
130                                     VkDeviceSize length,
131                                     GLbitfield access,
132                                     void **mapPtr);
133 
134     ConversionBuffer *getVertexConversionBuffer(RendererVk *renderer,
135                                                 angle::FormatID formatID,
136                                                 GLuint stride,
137                                                 size_t offset,
138                                                 bool hostVisible);
139 
140   private:
141     angle::Result initializeShadowBuffer(ContextVk *contextVk,
142                                          gl::BufferBinding target,
143                                          size_t size);
144     void initializeHostVisibleBufferPool(ContextVk *contextVk);
145 
getShadowBuffer(size_t offset)146     ANGLE_INLINE uint8_t *getShadowBuffer(size_t offset)
147     {
148         return (mShadowBuffer.getCurrentBuffer() + offset);
149     }
150 
getShadowBuffer(size_t offset)151     ANGLE_INLINE const uint8_t *getShadowBuffer(size_t offset) const
152     {
153         return (mShadowBuffer.getCurrentBuffer() + offset);
154     }
155 
156     void updateShadowBuffer(const uint8_t *data, size_t size, size_t offset);
157     angle::Result updateBuffer(ContextVk *contextVk,
158                                const uint8_t *data,
159                                size_t size,
160                                size_t offset);
161     angle::Result directUpdate(ContextVk *contextVk,
162                                const uint8_t *data,
163                                size_t size,
164                                size_t offset);
165     angle::Result stagedUpdate(ContextVk *contextVk,
166                                const uint8_t *data,
167                                size_t size,
168                                size_t offset);
169     angle::Result allocMappedStagingBuffer(ContextVk *contextVk,
170                                            size_t size,
171                                            vk::DynamicBuffer **stagingBuffer,
172                                            VkDeviceSize *stagingBufferOffset,
173                                            uint8_t **mapPtr);
174     angle::Result flushMappedStagingBuffer(ContextVk *contextVk,
175                                            vk::DynamicBuffer *stagingBuffer,
176                                            VkDeviceSize stagingBufferOffset,
177                                            size_t size,
178                                            size_t offset);
179     angle::Result acquireAndUpdate(ContextVk *contextVk,
180                                    const uint8_t *data,
181                                    size_t updateSize,
182                                    size_t offset,
183                                    BufferUpdateType updateType);
184     angle::Result setDataWithMemoryType(const gl::Context *context,
185                                         gl::BufferBinding target,
186                                         const void *data,
187                                         size_t size,
188                                         VkMemoryPropertyFlags memoryPropertyFlags,
189                                         bool persistentMapRequired,
190                                         gl::BufferUsage usage);
191     angle::Result handleDeviceLocalBufferMap(ContextVk *contextVk,
192                                              VkDeviceSize offset,
193                                              VkDeviceSize size,
194                                              uint8_t **mapPtr);
195     angle::Result handleDeviceLocalBufferUnmap(ContextVk *contextVk,
196                                                VkDeviceSize offset,
197                                                VkDeviceSize size);
198     angle::Result setDataImpl(ContextVk *contextVk,
199                               const uint8_t *data,
200                               size_t size,
201                               size_t offset,
202                               BufferUpdateType updateType);
203     void release(ContextVk *context);
204     void dataUpdated();
205 
206     angle::Result acquireBufferHelper(ContextVk *contextVk,
207                                       size_t sizeInBytes,
208                                       BufferUpdateType updateType);
209 
210     struct VertexConversionBuffer : public ConversionBuffer
211     {
212         VertexConversionBuffer(RendererVk *renderer,
213                                angle::FormatID formatIDIn,
214                                GLuint strideIn,
215                                size_t offsetIn,
216                                bool hostVisible);
217         ~VertexConversionBuffer();
218 
219         VertexConversionBuffer(VertexConversionBuffer &&other);
220 
221         // The conversion is identified by the triple of {format, stride, offset}.
222         angle::FormatID formatID;
223         GLuint stride;
224         size_t offset;
225     };
226 
227     vk::BufferHelper *mBuffer;
228     VkDeviceSize mBufferOffset;
229 
230     // Pool of BufferHelpers for mBuffer to acquire from
231     vk::DynamicBuffer mBufferPool;
232 
233     // DynamicBuffer to aid map operations of buffers when they are not host visible.
234     vk::DynamicBuffer mHostVisibleBufferPool;
235     VkDeviceSize mHostVisibleBufferOffset;
236 
237     // For GPU-read only buffers glMap* latency is reduced by maintaining a copy
238     // of the buffer which is writeable only by the CPU. The contents are updated on all
239     // glData/glSubData/glCopy calls. With this, a glMap* call becomes a non-blocking
240     // operation by elimnating the need to wait on any recorded or in-flight GPU commands.
241     // We use DynamicShadowBuffer class to encapsulate all the bookeeping logic.
242     vk::DynamicShadowBuffer mShadowBuffer;
243 
244     // A buffer pool to service GL_MAP_INVALIDATE_RANGE_BIT -style uploads.
245     vk::DynamicBuffer *mMapInvalidateRangeStagingBuffer;
246     VkDeviceSize mMapInvalidateRangeStagingBufferOffset;
247     uint8_t *mMapInvalidateRangeMappedPtr;
248 
249     // A cache of converted vertex data.
250     std::vector<VertexConversionBuffer> mVertexConversionBuffers;
251 
252     // Tracks if BufferVk object has valid data or not.
253     bool mHasValidData;
254 
255     // TODO: https://issuetracker.google.com/201826021 Remove this once we have a full fix.
256     // Tracks if BufferVk's data is ever been referenced by GPU since new storage has been
257     // allocated. Due to sub-allocation, we may get a new sub-allocated range in the same
258     // BufferHelper object. Because we track GPU progress by the BufferHelper object, this flag will
259     // help us to avoid detecting we are still GPU busy even though no one has used it yet since
260     // we got last sub-allocation.
261     bool mHasBeenReferencedByGPU;
262 };
263 
264 }  // namespace rx
265 
266 #endif  // LIBANGLE_RENDERER_VULKAN_BUFFERVK_H_
267