Blender V5.0
vk_vertex_buffer.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "vk_data_conversion.hh"
12#include "vk_shader.hh"
14#include "vk_staging_buffer.hh"
15#include "vk_state_manager.hh"
16#include "vk_vertex_buffer.hh"
17
18#include "CLG_log.h"
19
20static CLG_LogRef LOG = {"gpu.vulkan"};
21
22namespace blender::gpu {
23
28
30{
31 VKContext &context = *VKContext::get();
32 VKStateManager &state_manager = context.state_manager_get();
34}
35
37{
38 VKContext &context = *VKContext::get();
39 VKStateManager &state_manager = context.state_manager_get();
40 state_manager.texel_buffer_bind(*this, binding);
41}
42
47
49{
50 if (vk_buffer_view_ != VK_NULL_HANDLE) {
51 return;
52 }
53
54 VkBufferViewCreateInfo buffer_view_info = {};
55 buffer_view_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
56 buffer_view_info.buffer = buffer_.vk_handle();
57 buffer_view_info.format = to_vk_format();
58 buffer_view_info.range = buffer_.size_in_bytes();
59
60 const VKDevice &device = VKBackend::get().device;
61 vkCreateBufferView(device.vk_handle(), &buffer_view_info, nullptr, &vk_buffer_view_);
62 debug::object_label(vk_buffer_view_, "VertexBufferView");
63}
64
69
70void VKVertexBuffer::update_sub(uint start_offset, uint data_size_in_bytes, const void *data)
71{
72 if (!buffer_.is_allocated()) {
73 /* Allocating huge buffers can fail, in that case we skip copying data. */
74 return;
75 }
76 BLI_assert_msg(start_offset + data_size_in_bytes <= buffer_.size_in_bytes(),
77 "Out of bound write to vertex buffer");
78 if (buffer_.is_mapped()) {
79 buffer_.update_sub_immediately(start_offset, data_size_in_bytes, data);
80 }
81 else {
82 VKContext &context = *VKContext::get();
83 VKStagingBuffer staging_buffer(
84 buffer_, VKStagingBuffer::Direction::HostToDevice, start_offset, data_size_in_bytes);
85 memcpy(staging_buffer.host_buffer_get().mapped_memory_get(), data, data_size_in_bytes);
86 staging_buffer.copy_to_device(context);
87 }
88}
89
90void VKVertexBuffer::read(void *data) const
91{
92 VKContext &context = *VKContext::get();
93 if (buffer_.is_mapped()) {
94 buffer_.read(context, data);
95 return;
96 }
97
98 /* Allocating huge buffers can fail, in that case we skip copying data. */
99 if (buffer_.is_allocated()) {
101 VKBuffer &buffer = staging_buffer.host_buffer_get();
102 if (buffer.is_mapped()) {
103 staging_buffer.copy_from_device(context);
104 staging_buffer.host_buffer_get().read(context, data);
105 }
106 else {
108 &LOG,
109 "Unable to read data from vertex buffer via a staging buffer as the staging buffer "
110 "could not be allocated. ");
111 }
112 }
113}
114
116{
118 return;
119 }
120
121 /* Discard previous data if any. */
122 /* TODO: Use mapped memory. */
124 data_ = MEM_malloc_arrayN<uchar>(this->size_alloc_get(), __func__);
125}
126
128{
130 return;
131 }
132
133 data_ = (uchar *)MEM_reallocN(data_, sizeof(uchar) * this->size_alloc_get());
134}
135
137{
138 if (vk_buffer_view_ != VK_NULL_HANDLE) {
140 vk_buffer_view_ = VK_NULL_HANDLE;
141 }
142
144}
145
146void VKVertexBuffer::upload_data_direct(const VKBuffer &host_buffer)
147{
148 host_buffer.update_immediately(data_);
149}
150
151void VKVertexBuffer::upload_data_via_staging_buffer(VKContext &context)
152{
153 VKStagingBuffer staging_buffer(
155 VKBuffer &buffer = staging_buffer.host_buffer_get();
156 if (buffer.is_allocated()) {
157 upload_data_direct(buffer);
158 staging_buffer.copy_to_device(context);
159 }
160 else {
162 "Unable to upload data to vertex buffer via a staging buffer as the staging buffer "
163 "could not be allocated. Vertex buffer will be filled with on zeros to reduce "
164 "drawing artifacts due to read from uninitialized memory.");
165 buffer_.clear(context, 0u);
166 }
167}
168
170{
171 if (!buffer_.is_allocated()) {
172 allocate();
173 /* If allocation fails, don't upload. */
174 if (!buffer_.is_allocated()) {
175 CLOG_ERROR(&LOG, "Unable to allocate vertex buffer. Most likely an out of memory issue.");
176 return;
177 }
178 }
179
181 return;
182 }
183
185 if (buffer_.is_mapped() && !data_uploaded_) {
186 upload_data_direct(buffer_);
187 }
188 else {
189 VKContext &context = *VKContext::get();
190 upload_data_via_staging_buffer(context);
191 }
192 if (usage_ == GPU_USAGE_STATIC) {
194 }
195 data_uploaded_ = true;
196
199 }
200}
201
202void VKVertexBuffer::allocate()
203{
204 VkBufferUsageFlags vk_buffer_usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
205 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
206 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
207 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
208 VK_BUFFER_USAGE_TRANSFER_DST_BIT;
209
210 buffer_.create(
211 size_alloc_get(), vk_buffer_usage, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlags(0), 0.8f);
212 debug::object_label(buffer_.vk_handle(), "VertexBuffer");
213}
214
215} // namespace blender::gpu
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
unsigned char uchar
unsigned int uint
#define ELEM(...)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
@ GPU_VERTBUF_DATA_DIRTY
@ GPU_VERTBUF_DATA_UPLOADED
@ GPU_USAGE_STATIC
@ GPU_USAGE_STREAM
@ GPU_USAGE_DYNAMIC
@ GPU_USAGE_DEVICE_ONLY
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
unsigned long long int uint64_t
static VKBackend & get()
Definition vk_backend.hh:91
void update_immediately(const void *data) const
Definition vk_buffer.cc:123
bool is_mapped() const
Definition vk_buffer.hh:140
void read(VKContext &context, void *data) const
Definition vk_buffer.cc:182
VkBuffer vk_handle() const
Definition vk_buffer.hh:101
void clear(VKContext &context, uint32_t clear_value)
Definition vk_buffer.cc:153
bool create(size_t size, VkBufferUsageFlags buffer_usage, VmaMemoryUsage vma_memory_usage, VmaAllocationCreateFlags vma_allocation_flags, float priority, bool export_memory=false)
Definition vk_buffer.cc:27
void * mapped_memory_get() const
Definition vk_buffer.hh:134
static VKContext * get()
VkDevice vk_handle() const
Definition vk_device.hh:311
void discard_buffer_view(VkBufferView vk_buffer_view)
static VKDiscardPool & discard_pool_get()
void copy_from_device(VKContext &context)
void copy_to_device(VKContext &context)
void texel_buffer_bind(VKVertexBuffer &vertex_buffer, int slot)
void storage_buffer_bind(BindSpaceStorageBuffers::Type resource_type, void *resource, int binding)
void update_sub(uint start, uint len, const void *data) override
void wrap_handle(uint64_t handle) override
void bind_as_ssbo(uint binding) override
void bind_as_texture(uint binding) override
void read(void *data) const override
MutableSpan< T > data()
#define LOG(level)
Definition log.h:97
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void object_label(GLenum type, GLuint object, const char *name)
Definition gl_debug.cc:329
static CLG_LogRef LOG
#define NOT_YET_IMPLEMENTED
Definition vk_common.hh:149