// // Copyright 2016 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // BufferVk.h: // Defines the class interface for BufferVk, implementing BufferImpl. // #ifndef LIBANGLE_RENDERER_VULKAN_BUFFERVK_H_ #define LIBANGLE_RENDERER_VULKAN_BUFFERVK_H_ #include "libANGLE/Buffer.h" #include "libANGLE/Observer.h" #include "libANGLE/renderer/BufferImpl.h" #include "libANGLE/renderer/vulkan/vk_helpers.h" namespace rx { class RendererVk; // Conversion buffers hold translated index and vertex data. struct ConversionBuffer { ConversionBuffer(RendererVk *renderer, VkBufferUsageFlags usageFlags, size_t initialSize, size_t alignment, bool hostVisible); ~ConversionBuffer(); ConversionBuffer(ConversionBuffer &&other); // One state value determines if we need to re-stream vertex data. bool dirty; // Where the conversion data is stored. std::unique_ptr data; }; enum class BufferUpdateType { StorageRedefined, ContentsUpdate, }; struct BufferDataSource { // Buffer data can come from two sources: // glBufferData and glBufferSubData upload through a CPU pointer const void *data = nullptr; // glCopyBufferSubData copies data from another buffer vk::BufferHelper *buffer = nullptr; VkDeviceSize bufferOffset = 0; }; VkBufferUsageFlags GetDefaultBufferUsageFlags(RendererVk *renderer); class BufferVk : public BufferImpl { public: BufferVk(const gl::BufferState &state); ~BufferVk() override; void destroy(const gl::Context *context) override; angle::Result setExternalBufferData(const gl::Context *context, gl::BufferBinding target, GLeglClientBufferEXT clientBuffer, size_t size, VkMemoryPropertyFlags memoryPropertyFlags); angle::Result setDataWithUsageFlags(const gl::Context *context, gl::BufferBinding target, GLeglClientBufferEXT clientBuffer, const void *data, size_t size, gl::BufferUsage usage, GLbitfield flags) override; angle::Result setData(const gl::Context *context, gl::BufferBinding target, const void *data, size_t size, gl::BufferUsage usage) override; angle::Result setSubData(const gl::Context *context, gl::BufferBinding target, const void *data, size_t size, size_t offset) override; angle::Result copySubData(const gl::Context *context, BufferImpl *source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) override; angle::Result map(const gl::Context *context, GLenum access, void **mapPtr) override; angle::Result mapRange(const gl::Context *context, size_t offset, size_t length, GLbitfield access, void **mapPtr) override; angle::Result unmap(const gl::Context *context, GLboolean *result) override; angle::Result getSubData(const gl::Context *context, GLintptr offset, GLsizeiptr size, void *outData) override; angle::Result getIndexRange(const gl::Context *context, gl::DrawElementsType type, size_t offset, size_t count, bool primitiveRestartEnabled, gl::IndexRange *outRange) override; GLint64 getSize() const { return mState.getSize(); } void onDataChanged() override; vk::BufferHelper &getBuffer() { ASSERT(isBufferValid()); return mBuffer; } vk::BufferSerial getBufferSerial() { return mBuffer.getBufferSerial(); } bool isBufferValid() const { return mBuffer.valid(); } bool isCurrentlyInUse(RendererVk *renderer) const; angle::Result mapImpl(ContextVk *contextVk, GLbitfield access, void **mapPtr); angle::Result mapRangeImpl(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize length, GLbitfield access, void **mapPtr); angle::Result unmapImpl(ContextVk *contextVk); angle::Result ghostMappedBuffer(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize length, GLbitfield access, void **mapPtr); ConversionBuffer *getVertexConversionBuffer(RendererVk *renderer, angle::FormatID formatID, GLuint stride, size_t offset, bool hostVisible); private: angle::Result updateBuffer(ContextVk *contextVk, size_t bufferSize, const BufferDataSource &dataSource, size_t size, size_t offset); angle::Result directUpdate(ContextVk *contextVk, const BufferDataSource &dataSource, size_t size, size_t offset); angle::Result stagedUpdate(ContextVk *contextVk, const BufferDataSource &dataSource, size_t size, size_t offset); angle::Result allocStagingBuffer(ContextVk *contextVk, vk::MemoryCoherency coherency, VkDeviceSize size, uint8_t **mapPtr); angle::Result flushStagingBuffer(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize size); angle::Result acquireAndUpdate(ContextVk *contextVk, size_t bufferSize, const BufferDataSource &dataSource, size_t updateSize, size_t updateOffset, BufferUpdateType updateType); angle::Result setDataWithMemoryType(const gl::Context *context, gl::BufferBinding target, const void *data, size_t size, VkMemoryPropertyFlags memoryPropertyFlags, gl::BufferUsage usage); angle::Result handleDeviceLocalBufferMap(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize size, uint8_t **mapPtr); angle::Result setDataImpl(ContextVk *contextVk, size_t bufferSize, const BufferDataSource &dataSource, size_t updateSize, size_t updateOffset, BufferUpdateType updateType); void release(ContextVk *context); void dataUpdated(); angle::Result acquireBufferHelper(ContextVk *contextVk, size_t sizeInBytes, BufferUsageType usageType); bool isExternalBuffer() const { return mClientBuffer != nullptr; } BufferUpdateType calculateBufferUpdateTypeOnFullUpdate( RendererVk *renderer, size_t size, VkMemoryPropertyFlags memoryPropertyFlags, BufferUsageType usageType, const void *data) const; bool shouldRedefineStorage(RendererVk *renderer, BufferUsageType usageType, VkMemoryPropertyFlags memoryPropertyFlags, size_t size) const; struct VertexConversionBuffer : public ConversionBuffer { VertexConversionBuffer(RendererVk *renderer, angle::FormatID formatIDIn, GLuint strideIn, size_t offsetIn, bool hostVisible); ~VertexConversionBuffer(); VertexConversionBuffer(VertexConversionBuffer &&other); // The conversion is identified by the triple of {format, stride, offset}. angle::FormatID formatID; GLuint stride; size_t offset; }; vk::BufferHelper mBuffer; // If not null, this is the external memory pointer passed from client API. void *mClientBuffer; uint32_t mMemoryTypeIndex; // Memory/Usage property that will be used for memory allocation. VkMemoryPropertyFlags mMemoryPropertyFlags; // The staging buffer to aid map operations. This is used when buffers are not host visible or // for performance optimization when only a smaller range of buffer is mapped. vk::BufferHelper mStagingBuffer; // A cache of converted vertex data. std::vector mVertexConversionBuffers; // Tracks whether mStagingBuffer has been mapped to user or not bool mIsStagingBufferMapped; // Tracks if BufferVk object has valid data or not. bool mHasValidData; // True if the buffer is currently mapped for CPU write access. If the map call is originated // from OpenGLES API call, then this should be consistent with mState.getAccessFlags() bits. // Otherwise it is mapped from ANGLE internal and will not be consistent with mState access // bits, so we have to keep record of it. bool mIsMappedForWrite; // True if usage is dynamic. May affect how we allocate memory. BufferUsageType mUsageType; // Similar as mIsMappedForWrite, this maybe different from mState's getMapOffset/getMapLength if // mapped from angle internal. VkDeviceSize mMappedOffset; VkDeviceSize mMappedLength; }; } // namespace rx #endif // LIBANGLE_RENDERER_VULKAN_BUFFERVK_H_