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