| // |
| // 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.cpp: |
| // Implements the class methods for BufferVk. |
| // |
| |
| #include "libANGLE/renderer/vulkan/BufferVk.h" |
| |
| #include "common/debug.h" |
| #include "libANGLE/renderer/vulkan/ContextVk.h" |
| #include "libANGLE/renderer/vulkan/RendererVk.h" |
| |
| namespace rx |
| { |
| |
| BufferVk::BufferVk(const gl::BufferState &state) : BufferImpl(state), mRequiredSize(0) |
| { |
| } |
| |
| BufferVk::~BufferVk() |
| { |
| } |
| |
| void BufferVk::destroy(ContextImpl *contextImpl) |
| { |
| VkDevice device = GetAs<ContextVk>(contextImpl)->getDevice(); |
| |
| mBuffer.destroy(device); |
| } |
| |
| gl::Error BufferVk::setData(ContextImpl *context, |
| GLenum target, |
| const void *data, |
| size_t size, |
| GLenum usage) |
| { |
| ContextVk *contextVk = GetAs<ContextVk>(context); |
| auto device = contextVk->getDevice(); |
| |
| // TODO(jmadill): Proper usage bit implementation. Likely will involve multiple backing buffers |
| // like in D3D11. |
| VkBufferCreateInfo createInfo; |
| createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| createInfo.pNext = nullptr; |
| createInfo.flags = 0; |
| createInfo.size = size; |
| createInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; |
| createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| createInfo.queueFamilyIndexCount = 0; |
| createInfo.pQueueFamilyIndices = nullptr; |
| |
| vk::Buffer newBuffer; |
| ANGLE_TRY(newBuffer.init(device, createInfo)); |
| |
| // Find a compatible memory pool index. If the index doesn't change, we could cache it. |
| // Not finding a valid memory pool means an out-of-spec driver, or internal error. |
| // TODO(jmadill): More efficient memory allocation. |
| VkMemoryRequirements memoryRequirements; |
| vkGetBufferMemoryRequirements(device, newBuffer.getHandle(), &memoryRequirements); |
| |
| // The requirements size is not always equal to the specified API size. |
| ASSERT(memoryRequirements.size >= size); |
| mRequiredSize = static_cast<size_t>(memoryRequirements.size); |
| |
| VkPhysicalDeviceMemoryProperties memoryProperties; |
| vkGetPhysicalDeviceMemoryProperties(contextVk->getRenderer()->getPhysicalDevice(), |
| &memoryProperties); |
| |
| auto memoryTypeIndex = |
| FindMemoryType(memoryProperties, memoryRequirements, |
| VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); |
| ANGLE_VK_CHECK(memoryTypeIndex.valid(), VK_ERROR_INCOMPATIBLE_DRIVER); |
| |
| VkMemoryAllocateInfo allocInfo; |
| allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| allocInfo.pNext = nullptr; |
| allocInfo.memoryTypeIndex = memoryTypeIndex.value(); |
| allocInfo.allocationSize = memoryRequirements.size; |
| |
| ANGLE_TRY(newBuffer.getMemory().allocate(device, allocInfo)); |
| ANGLE_TRY(newBuffer.bindMemory(device)); |
| |
| mBuffer.retain(device, std::move(newBuffer)); |
| |
| if (data) |
| { |
| ANGLE_TRY(setDataImpl(device, static_cast<const uint8_t *>(data), size, 0)); |
| } |
| |
| return gl::NoError(); |
| } |
| |
| gl::Error BufferVk::setSubData(ContextImpl *context, |
| GLenum target, |
| const void *data, |
| size_t size, |
| size_t offset) |
| { |
| ASSERT(mBuffer.getHandle() != VK_NULL_HANDLE); |
| ASSERT(mBuffer.getMemory().getHandle() != VK_NULL_HANDLE); |
| |
| VkDevice device = GetAs<ContextVk>(context)->getDevice(); |
| |
| ANGLE_TRY(setDataImpl(device, static_cast<const uint8_t *>(data), size, offset)); |
| |
| return gl::NoError(); |
| } |
| |
| gl::Error BufferVk::copySubData(ContextImpl *context, |
| BufferImpl *source, |
| GLintptr sourceOffset, |
| GLintptr destOffset, |
| GLsizeiptr size) |
| { |
| UNIMPLEMENTED(); |
| return gl::Error(GL_INVALID_OPERATION); |
| } |
| |
| gl::Error BufferVk::map(ContextImpl *context, GLenum access, void **mapPtr) |
| { |
| ASSERT(mBuffer.getHandle() != VK_NULL_HANDLE); |
| ASSERT(mBuffer.getMemory().getHandle() != VK_NULL_HANDLE); |
| |
| VkDevice device = GetAs<ContextVk>(context)->getDevice(); |
| |
| ANGLE_TRY(mBuffer.getMemory().map(device, 0, mState.getSize(), 0, |
| reinterpret_cast<uint8_t **>(mapPtr))); |
| |
| return gl::NoError(); |
| } |
| |
| gl::Error BufferVk::mapRange(ContextImpl *context, |
| size_t offset, |
| size_t length, |
| GLbitfield access, |
| void **mapPtr) |
| { |
| ASSERT(mBuffer.getHandle() != VK_NULL_HANDLE); |
| ASSERT(mBuffer.getMemory().getHandle() != VK_NULL_HANDLE); |
| |
| VkDevice device = GetAs<ContextVk>(context)->getDevice(); |
| |
| ANGLE_TRY( |
| mBuffer.getMemory().map(device, offset, length, 0, reinterpret_cast<uint8_t **>(mapPtr))); |
| |
| return gl::NoError(); |
| } |
| |
| gl::Error BufferVk::unmap(ContextImpl *context, GLboolean *result) |
| { |
| ASSERT(mBuffer.getHandle() != VK_NULL_HANDLE); |
| ASSERT(mBuffer.getMemory().getHandle() != VK_NULL_HANDLE); |
| |
| VkDevice device = GetAs<ContextVk>(context)->getDevice(); |
| |
| mBuffer.getMemory().unmap(device); |
| |
| return gl::NoError(); |
| } |
| |
| gl::Error BufferVk::getIndexRange(GLenum type, |
| size_t offset, |
| size_t count, |
| bool primitiveRestartEnabled, |
| gl::IndexRange *outRange) |
| { |
| UNIMPLEMENTED(); |
| return gl::Error(GL_INVALID_OPERATION); |
| } |
| |
| vk::Error BufferVk::setDataImpl(VkDevice device, const uint8_t *data, size_t size, size_t offset) |
| { |
| uint8_t *mapPointer = nullptr; |
| ANGLE_TRY(mBuffer.getMemory().map(device, offset, size, 0, &mapPointer)); |
| ASSERT(mapPointer); |
| |
| memcpy(mapPointer, data, size); |
| |
| mBuffer.getMemory().unmap(device); |
| |
| return vk::NoError(); |
| } |
| |
| const vk::Buffer &BufferVk::getVkBuffer() const |
| { |
| return mBuffer; |
| } |
| |
| } // namespace rx |