Blender V4.5
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_INST_VBO_MAX_LEN; v++) {
96 VKVertexBuffer *vbo = batch.instance_buffer_get(v);
97 if (vbo) {
99 vbo->format, vbo, nullptr, vbo->vertex_len, interface, occupied_attributes, true);
100 }
101 }
102 for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
103 VKVertexBuffer *vbo = batch.vertex_buffer_get(v);
104 if (vbo) {
106 vbo->format, vbo, nullptr, vbo->vertex_len, interface, occupied_attributes, false);
107 }
108 }
109
110 if (occupied_attributes != interface.enabled_attr_mask_) {
111 fill_unused_bindings(interface, occupied_attributes);
112 }
113 is_valid = true;
114}
115
116/* Determine the number of binding location the given attribute uses. */
117static uint32_t to_binding_location_len(const GPUVertAttr &attribute)
118{
119 return ceil_division(attribute.comp_len, 4u);
120}
121
122/* Determine the number of binding location the given type uses. */
165
166void VKVertexAttributeObject::fill_unused_bindings(const VKShaderInterface &interface,
167 const AttributeMask occupied_attributes)
168{
169 for (int location : IndexRange(16)) {
170 AttributeMask location_mask = 1 << location;
171 /* Skip occupied slots */
172 if (occupied_attributes & location_mask) {
173 continue;
174 }
175 /* Skip slots that are not used by the vertex shader. */
176 if ((interface.enabled_attr_mask_ & location_mask) == 0) {
177 continue;
178 }
179
180 /* Use dummy binding. */
181 shader::Type attribute_type = interface.get_attribute_type(location);
182 const uint32_t num_locations = to_binding_location_len(attribute_type);
183 for (const uint32_t location_offset : IndexRange(num_locations)) {
184 const uint32_t binding = bindings.size();
185 VkVertexInputAttributeDescription attribute_description = {};
186 attribute_description.binding = binding;
187 attribute_description.location = location + location_offset;
188 attribute_description.offset = 0;
189 attribute_description.format = to_vk_format(attribute_type);
190 attributes.append(attribute_description);
191
192 VkVertexInputBindingDescription vk_binding_descriptor = {};
193 vk_binding_descriptor.binding = binding;
194 vk_binding_descriptor.stride = 0;
195 vk_binding_descriptor.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
196 bindings.append(vk_binding_descriptor);
197 }
198 }
199}
200
202{
203 clear();
204 const VKShaderInterface &interface = unwrap(unwrap(immediate.shader))->interface_get();
205 AttributeMask occupied_attributes = 0;
206
207 VKBufferWithOffset immediate_buffer = immediate.active_buffer();
209 nullptr,
210 &immediate_buffer,
211 immediate.vertex_len,
212 interface,
213 occupied_attributes,
214 false);
215 is_valid = true;
216 BLI_assert(interface.enabled_attr_mask_ == occupied_attributes);
217}
218
220 VKVertexBuffer *vertex_buffer,
221 VKBufferWithOffset *immediate_vertex_buffer,
222 const int64_t vertex_len,
224 AttributeMask &r_occupied_attributes,
225 const bool use_instancing)
226{
227 BLI_assert(vertex_buffer || immediate_vertex_buffer);
228 BLI_assert(!(vertex_buffer && immediate_vertex_buffer));
229
230 if (vertex_format.attr_len <= 0) {
231 return;
232 }
233
234 /* Interleaved offset is added to the buffer binding. Attribute offsets are hardware
235 * restricted (ref: VUID-VkVertexInputAttributeDescription-offset-00622). */
236 uint32_t buffer_offset = 0;
237 uint32_t attribute_offset = 0;
238 uint32_t stride = vertex_format.stride;
239
240 bool add_vbo = false;
241
242 for (uint32_t attribute_index = 0; attribute_index < vertex_format.attr_len; attribute_index++) {
243 const GPUVertAttr &attribute = vertex_format.attrs[attribute_index];
244 if (vertex_format.deinterleaved) {
245 buffer_offset += ((attribute_index == 0) ? 0 :
246 vertex_format.attrs[attribute_index - 1].size) *
247 vertex_len;
248 stride = attribute.size;
249 }
250 else {
251 attribute_offset = attribute.offset;
252 }
253
254 for (uint32_t name_index = 0; name_index < attribute.name_len; name_index++) {
255 const char *name = GPU_vertformat_attr_name_get(&vertex_format, &attribute, name_index);
256 const ShaderInput *shader_input = interface.attr_get(name);
257 if (shader_input == nullptr || shader_input->location == -1) {
258 continue;
259 }
260
261 /* Don't overwrite attributes that are already occupied. */
262 AttributeMask attribute_mask = 1 << shader_input->location;
263 if (r_occupied_attributes & attribute_mask) {
264 continue;
265 }
266 r_occupied_attributes |= attribute_mask;
267 const uint32_t num_locations = to_binding_location_len(attribute);
268 for (const uint32_t location_offset : IndexRange(num_locations)) {
269 const uint32_t binding = bindings.size();
270 VkVertexInputAttributeDescription attribute_description = {};
271 attribute_description.binding = binding;
272 attribute_description.location = shader_input->location + location_offset;
273 attribute_description.offset = attribute_offset + location_offset * sizeof(float4);
274 attribute_description.format = to_vk_format(
275 static_cast<GPUVertCompType>(attribute.comp_type),
276 attribute.size,
277 static_cast<GPUVertFetchMode>(attribute.fetch_mode));
278 attributes.append(attribute_description);
279
280 VkVertexInputBindingDescription vk_binding_descriptor = {};
281 vk_binding_descriptor.binding = binding;
282 vk_binding_descriptor.stride = stride;
283 vk_binding_descriptor.inputRate = use_instancing ? VK_VERTEX_INPUT_RATE_INSTANCE :
284 VK_VERTEX_INPUT_RATE_VERTEX;
285 bindings.append(vk_binding_descriptor);
286 if (vertex_buffer) {
287 add_vbo = true;
288 vertex_buffer->upload();
289 buffers.append({vertex_buffer->vk_handle(), buffer_offset});
290 }
291 if (immediate_vertex_buffer) {
292 buffers.append(*immediate_vertex_buffer);
293 }
294 }
295 }
296 }
297
298 if (add_vbo) {
299 BLI_assert(vertex_buffer != nullptr);
300 vbos.append(vertex_buffer);
301 }
302}
303
305
306/* -------------------------------------------------------------------- */
309
311{
312 std::cout << __FILE__ << "::" << __func__ << "\n";
313 BitVector visited_bindings(bindings.size());
314
315 for (VkVertexInputAttributeDescription attribute : attributes) {
316 std::cout << " - attribute(binding=" << attribute.binding
317 << ", location=" << attribute.location << ")";
318
319 if (visited_bindings[attribute.binding]) {
320 std::cout << " WARNING: Already bound\n";
321 continue;
322 }
323 visited_bindings[attribute.binding].set(true);
324
325 if (attribute.binding < vbos.size()) {
326 std::cout << " Attach to Buffer\n";
327 }
328 else {
329 std::cout << " WARNING: Attach to dummy\n";
330 }
331 }
332}
333
335
336} // 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:31
static constexpr int GPU_BATCH_INST_VBO_MAX_LEN
Definition GPU_batch.hh:32
BLI_INLINE const char * GPU_vertformat_attr_name_get(const GPUVertFormat *format, const GPUVertAttr *attr, uint n_idx)
GPUVertFetchMode
GPUVertCompType
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:102
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 @064345207361167251075330302113175271221317160336::@113254110077376341056327177062323111323010325277 batch
#define interface
static Context * unwrap(GPUContext *ctx)
VkFormat to_vk_format(const eGPUTextureFormat format)
Definition vk_common.cc:131
static uint32_t to_binding_location_len(const GPUVertAttr &attribute)
VecBase< float, 4 > float4
constexpr IntT ceil_division(const IntT x, const IntT y)
GPUVertAttr attrs[GPU_VERT_ATTR_MAX_LEN]