Blender V5.0
vk_vertex_attribute_object.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include "vk_batch.hh"
8#include "vk_context.hh"
9#include "vk_immediate.hh"
10#include "vk_shader.hh"
12#include "vk_vertex_buffer.hh"
13
14#include "BLI_bit_vector.hh"
16
17namespace blender::gpu {
22
24{
25 is_valid = false;
26 info.pNext = nullptr;
27 bindings.clear();
28 attributes.clear();
29 vbos.clear();
30 buffers.clear();
31}
32
34{
35 if (this == &other) {
36 return *this;
37 }
38
39 is_valid = other.is_valid;
40 info = other.info;
41 bindings.clear();
42 bindings.extend(other.bindings);
43 attributes.clear();
44 attributes.extend(other.attributes);
45 vbos.clear();
46 vbos.extend(other.vbos);
47 buffers.clear();
48 buffers.extend(other.buffers);
49 return *this;
50}
51
52/* -------------------------------------------------------------------- */
55
57 render_graph::VKVertexBufferBindings &r_vertex_buffer_bindings) const
58{
59 BitVector visited_bindings(bindings.size());
60
62 for (VkVertexInputAttributeDescription attribute : attributes) {
63 if (visited_bindings[attribute.binding]) {
64 continue;
65 }
66 visited_bindings[attribute.binding].set(true);
67
68 VkBuffer buffer = dummy.vk_handle();
69 VkDeviceSize offset = 0;
70
71 if (attribute.binding < buffers.size()) {
72 buffer = buffers[attribute.binding].buffer;
73 offset = buffers[attribute.binding].offset;
74 }
75
76 r_vertex_buffer_bindings.buffer[attribute.binding] = buffer;
77 r_vertex_buffer_bindings.offset[attribute.binding] = offset;
78 r_vertex_buffer_bindings.buffer_count = max_ii(r_vertex_buffer_bindings.buffer_count,
79 attribute.binding + 1);
80 }
81}
82
84
85/* -------------------------------------------------------------------- */
88
90{
91 clear();
92 const VKShaderInterface &interface = unwrap(context.shader)->interface_get();
93 AttributeMask occupied_attributes = 0;
94
95 for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
96 VKVertexBuffer *vbo = batch.vertex_buffer_get(v);
97 if (vbo) {
98 update_bindings(vbo->format, vbo, nullptr, vbo->vertex_len, interface, occupied_attributes);
99 }
100 }
101
102 if (occupied_attributes != interface.enabled_attr_mask_) {
103 fill_unused_bindings(interface, occupied_attributes);
104 }
105 is_valid = true;
106}
107
108/* Determine the number of binding location the given attribute uses. */
109static uint32_t to_binding_location_len(const GPUVertAttr &attribute)
110{
111 return ceil_division(attribute.type.comp_len(), 4);
112}
113
114/* Determine the number of binding location the given type uses. */
157
158void VKVertexAttributeObject::fill_unused_bindings(const VKShaderInterface &interface,
159 const AttributeMask occupied_attributes)
160{
161 for (int location : IndexRange(16)) {
162 AttributeMask location_mask = 1 << location;
163 /* Skip occupied slots */
164 if (occupied_attributes & location_mask) {
165 continue;
166 }
167 /* Skip slots that are not used by the vertex shader. */
168 if ((interface.enabled_attr_mask_ & location_mask) == 0) {
169 continue;
170 }
171
172 /* Use dummy binding. */
173 shader::Type attribute_type = interface.get_attribute_type(location);
174 const uint32_t num_locations = to_binding_location_len(attribute_type);
175 for (const uint32_t location_offset : IndexRange(num_locations)) {
176 const uint32_t binding = bindings.size();
177 VkVertexInputAttributeDescription attribute_description = {};
178 attribute_description.binding = binding;
179 attribute_description.location = location + location_offset;
180 attribute_description.offset = 0;
181 attribute_description.format = to_vk_format(attribute_type);
182 attributes.append(attribute_description);
183
184 VkVertexInputBindingDescription vk_binding_descriptor = {};
185 vk_binding_descriptor.binding = binding;
186 vk_binding_descriptor.stride = 0;
187 vk_binding_descriptor.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
188 bindings.append(vk_binding_descriptor);
189 }
190 }
191}
192
194{
195 clear();
196 const VKShaderInterface &interface = unwrap(unwrap(immediate.shader))->interface_get();
197 AttributeMask occupied_attributes = 0;
198
199 VKBufferWithOffset immediate_buffer = immediate.active_buffer();
201 nullptr,
202 &immediate_buffer,
203 immediate.vertex_len,
204 interface,
205 occupied_attributes);
206 is_valid = true;
207 BLI_assert(interface.enabled_attr_mask_ == occupied_attributes);
208}
209
211 VKVertexBuffer *vertex_buffer,
212 VKBufferWithOffset *immediate_vertex_buffer,
213 const int64_t vertex_len,
215 AttributeMask &r_occupied_attributes)
216{
217 BLI_assert(vertex_buffer || immediate_vertex_buffer);
218 BLI_assert(!(vertex_buffer && immediate_vertex_buffer));
219
220 if (vertex_format.attr_len <= 0) {
221 return;
222 }
223
224 /* Interleaved offset is added to the buffer binding. Attribute offsets are hardware
225 * restricted (ref: VUID-VkVertexInputAttributeDescription-offset-00622). */
226 uint32_t buffer_offset = 0;
227 uint32_t attribute_offset = 0;
228 uint32_t stride = vertex_format.stride;
229
230 bool add_vbo = false;
231
232 for (uint32_t attribute_index = 0; attribute_index < vertex_format.attr_len; attribute_index++) {
233 const GPUVertAttr &attribute = vertex_format.attrs[attribute_index];
234 if (vertex_format.deinterleaved) {
235 buffer_offset += ((attribute_index == 0) ?
236 0 :
237 vertex_format.attrs[attribute_index - 1].type.size()) *
238 vertex_len;
239 stride = attribute.type.size();
240 }
241 else {
242 attribute_offset = attribute.offset;
243 }
244
245 for (uint32_t name_index = 0; name_index < attribute.name_len; name_index++) {
246 const char *name = GPU_vertformat_attr_name_get(&vertex_format, &attribute, name_index);
247 const ShaderInput *shader_input = interface.attr_get(name);
248 if (shader_input == nullptr || shader_input->location == -1) {
249 continue;
250 }
251
252 /* Don't overwrite attributes that are already occupied. */
253 AttributeMask attribute_mask = 1 << shader_input->location;
254 if (r_occupied_attributes & attribute_mask) {
255 continue;
256 }
257 r_occupied_attributes |= attribute_mask;
258 const uint32_t num_locations = to_binding_location_len(attribute);
259 for (const uint32_t location_offset : IndexRange(num_locations)) {
260 const uint32_t binding = bindings.size();
261 VkVertexInputAttributeDescription attribute_description = {};
262 attribute_description.binding = binding;
263 attribute_description.location = shader_input->location + location_offset;
264 attribute_description.offset = attribute_offset + location_offset * sizeof(float4);
265 attribute_description.format = to_vk_format(
266 attribute.type.comp_type(), attribute.type.size(), attribute.type.fetch_mode());
267 attributes.append(attribute_description);
268
269 VkVertexInputBindingDescription vk_binding_descriptor = {};
270 vk_binding_descriptor.binding = binding;
271 vk_binding_descriptor.stride = stride;
272 vk_binding_descriptor.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
273 bindings.append(vk_binding_descriptor);
274 if (vertex_buffer) {
275 add_vbo = true;
276 vertex_buffer->upload();
277 buffers.append({vertex_buffer->vk_handle(), buffer_offset});
278 }
279 if (immediate_vertex_buffer) {
280 buffers.append(*immediate_vertex_buffer);
281 }
282 }
283 }
284 }
285
286 if (add_vbo) {
287 BLI_assert(vertex_buffer != nullptr);
288 vbos.append(vertex_buffer);
289 }
290}
291
293
294/* -------------------------------------------------------------------- */
297
299{
300 std::cout << __FILE__ << "::" << __func__ << "\n";
301 BitVector visited_bindings(bindings.size());
302
303 for (VkVertexInputAttributeDescription attribute : attributes) {
304 std::cout << " - attribute(binding=" << attribute.binding
305 << ", location=" << attribute.location << ")";
306
307 if (visited_bindings[attribute.binding]) {
308 std::cout << " WARNING: Already bound\n";
309 continue;
310 }
311 visited_bindings[attribute.binding].set(true);
312
313 if (attribute.binding < vbos.size()) {
314 std::cout << " Attach to Buffer\n";
315 }
316 else {
317 std::cout << " WARNING: Attach to dummy\n";
318 }
319 }
320}
321
323
324} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE int max_ii(int a, int b)
static constexpr int GPU_BATCH_VBO_MAX_LEN
Definition GPU_batch.hh:33
BLI_INLINE const char * GPU_vertformat_attr_name_get(const GPUVertFormat *format, const GPUVertAttr *attr, uint n_idx)
ATTR_WARN_UNUSED_RESULT const BMVert * v
long long int int64_t
static VKBackend & get()
Definition vk_backend.hh:91
VkBuffer vk_handle() const
Definition vk_buffer.hh:101
VKVertexAttributeObject & operator=(const VKVertexAttributeObject &other)
Vector< VkVertexInputAttributeDescription > attributes
void update_bindings(const VKContext &context, VKBatch &batch)
VkPipelineVertexInputStateCreateInfo info
Vector< VkVertexInputBindingDescription > bindings
void bind(render_graph::VKVertexBufferBindings &r_vertex_buffer_bindings) const
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
#define interface
#define interface_get(create_info, _res)
static Context * unwrap(GPUContext *ctx)
VkFormat to_vk_format(const TextureFormat format)
Definition vk_common.cc:136
static uint32_t to_binding_location_len(const GPUVertAttr &attribute)
VecBase< float, 4 > float4
constexpr IntT ceil_division(const IntT x, const IntT y)
const char * name
GPUVertFetchMode fetch_mode() const
GPUVertCompType comp_type() const
struct GPUVertAttr::Type type
GPUVertAttr attrs[GPU_VERT_ATTR_MAX_LEN]