blob: bdfa32cd24579a9c8da458e1c03fdec25616f8b6 [file] [log] [blame]
//
// 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