Blender V4.3
vk_immediate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include "vk_immediate.hh"
12#include "vk_backend.hh"
13#include "vk_context.hh"
14#include "vk_data_conversion.hh"
15#include "vk_framebuffer.hh"
16#include "vk_state_manager.hh"
17
18#include "CLG_log.h"
19
20namespace blender::gpu {
21
22static CLG_LogRef LOG = {"gpu.vulkan"};
23
26{
27 BLI_assert_msg(recycling_buffers_.is_empty(),
28 "VKImmediate::deinit must be called before destruction.");
29 BLI_assert_msg(active_buffers_.is_empty(),
30 "VKImmediate::deinit must be called before destruction");
31}
32
34{
35 while (!recycling_buffers_.is_empty()) {
36 std::unique_ptr<VKBuffer> buffer = recycling_buffers_.pop_last();
37 buffer->free_immediately(device);
38 buffer.release();
39 }
40 while (!active_buffers_.is_empty()) {
41 std::unique_ptr<VKBuffer> buffer = active_buffers_.pop_last();
42 buffer->free_immediately(device);
43 buffer.release();
44 }
45}
46
48{
49 const VKWorkarounds &workarounds = VKBackend::get().device.workarounds_get();
50 vertex_format_converter.init(&vertex_format, workarounds);
51 const size_t bytes_needed = vertex_buffer_size(&vertex_format_converter.device_format_get(),
53 VKBuffer &buffer = ensure_space(bytes_needed);
54 current_subbuffer_len_ = bytes_needed;
55
56 uchar *data = static_cast<uchar *>(buffer.mapped_memory_get());
57 return data + buffer_offset_;
58}
59
61{
62 BLI_assert_msg(prim_type != GPU_PRIM_NONE, "Illegal state: not between an immBegin/End pair.");
63 if (vertex_idx == 0) {
64 return;
65 }
66
67 if (vertex_format_converter.needs_conversion()) {
68 /* Determine the start of the subbuffer. The `vertex_data` attribute changes when new vertices
69 * are loaded.
70 */
71 uchar *data = static_cast<uchar *>(active_buffers_.last()->mapped_memory_get()) +
72 buffer_offset_;
73 vertex_format_converter.convert(data, data, vertex_idx);
74 }
75
76 VKContext &context = *VKContext::get();
77 BLI_assert(context.shader == unwrap(shader));
78 render_graph::VKResourceAccessInfo &resource_access_info = context.reset_and_get_access_info();
79 vertex_attributes_.update_bindings(*this);
80 context.active_framebuffer_get()->rendering_ensure(context);
81
82 render_graph::VKDrawNode::CreateInfo draw(resource_access_info);
85 draw.node_data.first_vertex = 0;
87 vertex_attributes_.bind(draw.node_data.vertex_buffers);
88 context.update_pipeline_data(prim_type, vertex_attributes_, draw.node_data.pipeline_data);
89
90 context.render_graph.add_node(draw);
91
92 buffer_offset_ += current_subbuffer_len_;
93 current_subbuffer_len_ = 0;
94 vertex_format_converter.reset();
95}
96
97VKBufferWithOffset VKImmediate::active_buffer() const
98{
99 VKBufferWithOffset result = {active_buffers_.last()->vk_handle(), buffer_offset_};
100 return result;
101}
102
103VkDeviceSize VKImmediate::buffer_bytes_free()
104{
105 return active_buffers_.last()->size_in_bytes() - buffer_offset_;
106}
107
108static VkDeviceSize new_buffer_size(size_t sub_buffer_size)
109{
110 return max_ulul(sub_buffer_size, DEFAULT_INTERNAL_BUFFER_SIZE);
111}
112
113VKBuffer &VKImmediate::ensure_space(size_t bytes_needed)
114{
115 /* Last used buffer still has space. */
116 if (!active_buffers_.is_empty() && buffer_bytes_free() >= bytes_needed) {
117 return *active_buffers_.last();
118 }
119
120 /* Recycle a previous buffer. */
121 if (!recycling_buffers_.is_empty() && recycling_buffers_.last()->size_in_bytes() >= bytes_needed)
122 {
123 CLOG_INFO(&LOG, 2, "Activating recycled buffer");
124 buffer_offset_ = 0;
125 active_buffers_.append(recycling_buffers_.pop_last());
126 return *active_buffers_.last();
127 }
128
129 size_t alloc_size = new_buffer_size(bytes_needed);
130 CLOG_INFO(&LOG, 2, "Allocate buffer (size=%d)", int(alloc_size));
131 buffer_offset_ = 0;
132 active_buffers_.append(std::make_unique<VKBuffer>());
133 VKBuffer &result = *active_buffers_.last();
134 result.create(new_buffer_size(bytes_needed),
136 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
137 debug::object_label(result.vk_handle(), "Immediate");
138
139 return result;
140}
141
143{
144 if (!recycling_buffers_.is_empty()) {
145 CLOG_INFO(&LOG, 2, "Discarding %d unused buffers", int(recycling_buffers_.size()));
146 }
147 recycling_buffers_.clear();
148 recycling_buffers_ = std::move(active_buffers_);
149}
150
151} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
unsigned char uchar
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
@ GPU_PRIM_NONE
@ GPU_USAGE_DYNAMIC
int64_t size() const
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
static VKBackend & get()
Definition vk_backend.hh:92
void * mapped_memory_get() const
Definition vk_buffer.cc:151
static VKContext * get()
Definition vk_context.hh:97
const VKWorkarounds & workarounds_get() const
Definition vk_device.hh:286
uchar * begin() override
void deinit(VKDevice &device)
void update_bindings(const VKContext &context, VKBatch &batch)
void bind(render_graph::VKVertexBufferBindings &r_vertex_buffer_bindings) const
uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len)
MINLINE unsigned long long max_ulul(unsigned long long a, unsigned long long b)
void object_label(GLenum type, GLuint object, const char *name)
Definition gl_debug.cc:344
static Context * unwrap(GPUContext *ctx)
static VkDeviceSize new_buffer_size(size_t sub_buffer_size)
constexpr size_t DEFAULT_INTERNAL_BUFFER_SIZE
static CLG_LogRef LOG
void init(const GPUVertFormat *vertex_format, const VKWorkarounds &workarounds)
void convert(void *device_data, const void *src_data, const uint vertex_len) const
const GPUVertFormat & device_format_get() const
VKVertexBufferBindings vertex_buffers