Memory areas was requested to be preferable host visible. On some platforms this would fail to allocate. Best is to not add preferable host visible for typically large allocations. This PR also gives the caller the responsibility to set the allocation flags. Pull Request: https://projects.blender.org/blender/blender/pulls/133528
203 lines
5.3 KiB
C++
203 lines
5.3 KiB
C++
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup gpu
|
|
*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "vk_data_conversion.hh"
|
|
#include "vk_shader.hh"
|
|
#include "vk_shader_interface.hh"
|
|
#include "vk_staging_buffer.hh"
|
|
#include "vk_state_manager.hh"
|
|
#include "vk_vertex_buffer.hh"
|
|
|
|
namespace blender::gpu {
|
|
|
|
VKVertexBuffer::~VKVertexBuffer()
|
|
{
|
|
release_data();
|
|
}
|
|
|
|
void VKVertexBuffer::bind_as_ssbo(uint binding)
|
|
{
|
|
VKContext &context = *VKContext::get();
|
|
VKStateManager &state_manager = context.state_manager_get();
|
|
state_manager.storage_buffer_bind(BindSpaceStorageBuffers::Type::VertexBuffer, this, binding);
|
|
}
|
|
|
|
void VKVertexBuffer::bind_as_texture(uint binding)
|
|
{
|
|
VKContext &context = *VKContext::get();
|
|
VKStateManager &state_manager = context.state_manager_get();
|
|
state_manager.texel_buffer_bind(*this, binding);
|
|
}
|
|
|
|
void VKVertexBuffer::ensure_updated()
|
|
{
|
|
upload_data();
|
|
}
|
|
|
|
void VKVertexBuffer::ensure_buffer_view()
|
|
{
|
|
if (vk_buffer_view_ != VK_NULL_HANDLE) {
|
|
return;
|
|
}
|
|
|
|
VkBufferViewCreateInfo buffer_view_info = {};
|
|
eGPUTextureFormat texture_format = to_texture_format(&format);
|
|
|
|
buffer_view_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
|
|
buffer_view_info.buffer = buffer_.vk_handle();
|
|
buffer_view_info.format = to_vk_format(texture_format);
|
|
buffer_view_info.range = buffer_.size_in_bytes();
|
|
|
|
const VKDevice &device = VKBackend::get().device;
|
|
vkCreateBufferView(device.vk_handle(), &buffer_view_info, nullptr, &vk_buffer_view_);
|
|
debug::object_label(vk_buffer_view_, "VertexBufferView");
|
|
}
|
|
|
|
void VKVertexBuffer::wrap_handle(uint64_t /*handle*/)
|
|
{
|
|
NOT_YET_IMPLEMENTED
|
|
}
|
|
|
|
void VKVertexBuffer::update_sub(uint /*start*/, uint /*len*/, const void * /*data*/)
|
|
{
|
|
NOT_YET_IMPLEMENTED
|
|
}
|
|
|
|
void VKVertexBuffer::read(void *data) const
|
|
{
|
|
VKContext &context = *VKContext::get();
|
|
if (buffer_.is_mapped()) {
|
|
buffer_.read(context, data);
|
|
return;
|
|
}
|
|
|
|
VKStagingBuffer staging_buffer(buffer_, VKStagingBuffer::Direction::DeviceToHost);
|
|
staging_buffer.copy_from_device(context);
|
|
staging_buffer.host_buffer_get().read(context, data);
|
|
}
|
|
|
|
void VKVertexBuffer::acquire_data()
|
|
{
|
|
if (usage_ == GPU_USAGE_DEVICE_ONLY) {
|
|
return;
|
|
}
|
|
|
|
/* Discard previous data if any. */
|
|
/* TODO: Use mapped memory. */
|
|
MEM_SAFE_FREE(data_);
|
|
data_ = (uchar *)MEM_mallocN(sizeof(uchar) * this->size_alloc_get(), __func__);
|
|
}
|
|
|
|
void VKVertexBuffer::resize_data()
|
|
{
|
|
if (usage_ == GPU_USAGE_DEVICE_ONLY) {
|
|
return;
|
|
}
|
|
|
|
data_ = (uchar *)MEM_reallocN(data_, sizeof(uchar) * this->size_alloc_get());
|
|
}
|
|
|
|
void VKVertexBuffer::release_data()
|
|
{
|
|
if (vk_buffer_view_ != VK_NULL_HANDLE) {
|
|
const VKDevice &device = VKBackend::get().device;
|
|
vkDestroyBufferView(device.vk_handle(), vk_buffer_view_, nullptr);
|
|
vk_buffer_view_ = VK_NULL_HANDLE;
|
|
}
|
|
|
|
MEM_SAFE_FREE(data_);
|
|
}
|
|
|
|
void VKVertexBuffer::upload_data_direct(const VKBuffer &host_buffer)
|
|
{
|
|
device_format_ensure();
|
|
if (vertex_format_converter.needs_conversion()) {
|
|
if (G.debug & G_DEBUG_GPU) {
|
|
std::cout << "PERFORMANCE: Vertex buffer requires conversion.\n";
|
|
}
|
|
vertex_format_converter.convert(host_buffer.mapped_memory_get(), data_, vertex_len);
|
|
host_buffer.flush();
|
|
}
|
|
else {
|
|
host_buffer.update_immediately(data_);
|
|
}
|
|
}
|
|
|
|
void VKVertexBuffer::upload_data_via_staging_buffer(VKContext &context)
|
|
{
|
|
VKStagingBuffer staging_buffer(buffer_, VKStagingBuffer::Direction::HostToDevice);
|
|
upload_data_direct(staging_buffer.host_buffer_get());
|
|
staging_buffer.copy_to_device(context);
|
|
}
|
|
|
|
void VKVertexBuffer::upload_data()
|
|
{
|
|
if (!buffer_.is_allocated()) {
|
|
allocate();
|
|
}
|
|
if (!ELEM(usage_, GPU_USAGE_STATIC, GPU_USAGE_STREAM, GPU_USAGE_DYNAMIC)) {
|
|
return;
|
|
}
|
|
|
|
if (flag & GPU_VERTBUF_DATA_DIRTY) {
|
|
device_format_ensure();
|
|
if (buffer_.is_mapped() && !data_uploaded_) {
|
|
upload_data_direct(buffer_);
|
|
}
|
|
else {
|
|
VKContext &context = *VKContext::get();
|
|
upload_data_via_staging_buffer(context);
|
|
}
|
|
if (usage_ == GPU_USAGE_STATIC) {
|
|
MEM_SAFE_FREE(data_);
|
|
}
|
|
data_uploaded_ = true;
|
|
|
|
flag &= ~GPU_VERTBUF_DATA_DIRTY;
|
|
flag |= GPU_VERTBUF_DATA_UPLOADED;
|
|
}
|
|
}
|
|
|
|
void VKVertexBuffer::duplicate_data(VertBuf * /*dst*/)
|
|
{
|
|
NOT_YET_IMPLEMENTED
|
|
}
|
|
|
|
void VKVertexBuffer::device_format_ensure()
|
|
{
|
|
if (!vertex_format_converter.is_initialized()) {
|
|
const VKWorkarounds &workarounds = VKBackend::get().device.workarounds_get();
|
|
vertex_format_converter.init(&format, workarounds);
|
|
}
|
|
}
|
|
|
|
const GPUVertFormat &VKVertexBuffer::device_format_get() const
|
|
{
|
|
return vertex_format_converter.device_format_get();
|
|
}
|
|
|
|
void VKVertexBuffer::allocate()
|
|
{
|
|
VkBufferUsageFlags vk_buffer_usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
|
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
|
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
|
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
|
|
|
buffer_.create(size_alloc_get(),
|
|
vk_buffer_usage,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
|
|
VmaAllocationCreateFlags(0));
|
|
debug::object_label(buffer_.vk_handle(), "VertexBuffer");
|
|
}
|
|
|
|
} // namespace blender::gpu
|