Blender V4.3
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;
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;
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/* -------------------------------------------------------------------- */
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
85/* -------------------------------------------------------------------- */
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) {
100 vbo,
101 nullptr,
102 vbo->vertex_len,
103 interface,
104 occupied_attributes,
105 true);
106 }
107 }
108 for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
109 VKVertexBuffer *vbo = batch.vertex_buffer_get(v);
110 if (vbo) {
113 vbo,
114 nullptr,
115 vbo->vertex_len,
116 interface,
117 occupied_attributes,
118 false);
119 }
120 }
121
122 if (occupied_attributes != interface.enabled_attr_mask_) {
123 fill_unused_bindings(interface, occupied_attributes);
124 }
125 is_valid = true;
126}
127
128/* Determine the number of binding location the given attribute uses. */
130{
131 return ceil_division(attribute.comp_len, 4u);
132}
133
134/* Determine the number of binding location the given type uses. */
136{
137 switch (type) {
168 return 1;
170 return 3;
172 return 4;
173 }
174
175 return 1;
176}
177
178void VKVertexAttributeObject::fill_unused_bindings(const VKShaderInterface &interface,
179 const AttributeMask occupied_attributes)
180{
181 for (int location : IndexRange(16)) {
182 AttributeMask location_mask = 1 << location;
183 /* Skip occupied slots */
184 if (occupied_attributes & location_mask) {
185 continue;
186 }
187 /* Skip slots that are not used by the vertex shader. */
188 if ((interface.enabled_attr_mask_ & location_mask) == 0) {
189 continue;
190 }
191
192 /* Use dummy binding. */
193 shader::Type attribute_type = interface.get_attribute_type(location);
194 const uint32_t num_locations = to_binding_location_len(attribute_type);
195 for (const uint32_t location_offset : IndexRange(num_locations)) {
196 const uint32_t binding = bindings.size();
197 VkVertexInputAttributeDescription attribute_description = {};
198 attribute_description.binding = binding;
199 attribute_description.location = location + location_offset;
200 attribute_description.offset = 0;
201 attribute_description.format = to_vk_format(attribute_type);
202 attributes.append(attribute_description);
203
204 VkVertexInputBindingDescription vk_binding_descriptor = {};
205 vk_binding_descriptor.binding = binding;
206 vk_binding_descriptor.stride = 0;
207 vk_binding_descriptor.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
208 bindings.append(vk_binding_descriptor);
209 }
210 }
211}
212
214{
215 clear();
216 const VKShaderInterface &interface = unwrap(unwrap(immediate.shader))->interface_get();
217 AttributeMask occupied_attributes = 0;
218
219 VKBufferWithOffset immediate_buffer = immediate.active_buffer();
220 update_bindings(immediate.vertex_format_converter.device_format_get(),
221 nullptr,
222 &immediate_buffer,
223 immediate.vertex_len,
224 interface,
225 occupied_attributes,
226 false);
227 is_valid = true;
228 BLI_assert(interface.enabled_attr_mask_ == occupied_attributes);
229}
230
232 VKVertexBuffer *vertex_buffer,
233 VKBufferWithOffset *immediate_vertex_buffer,
234 const int64_t vertex_len,
235 const VKShaderInterface &interface,
236 AttributeMask &r_occupied_attributes,
237 const bool use_instancing)
238{
239 BLI_assert(vertex_buffer || immediate_vertex_buffer);
240 BLI_assert(!(vertex_buffer && immediate_vertex_buffer));
241
242 if (vertex_format.attr_len <= 0) {
243 return;
244 }
245
246 /* Interleaved offset is added to the buffer binding. Attribute offsets are hardware
247 * restricted (ref: VUID-VkVertexInputAttributeDescription-offset-00622). */
248 uint32_t buffer_offset = 0;
249 uint32_t attribute_offset = 0;
250 uint32_t stride = vertex_format.stride;
251
252 bool add_vbo = false;
253
254 for (uint32_t attribute_index = 0; attribute_index < vertex_format.attr_len; attribute_index++) {
255 const GPUVertAttr &attribute = vertex_format.attrs[attribute_index];
256 if (vertex_format.deinterleaved) {
257 buffer_offset += ((attribute_index == 0) ? 0 :
258 vertex_format.attrs[attribute_index - 1].size) *
259 vertex_len;
260 stride = attribute.size;
261 }
262 else {
263 attribute_offset = attribute.offset;
264 }
265
266 for (uint32_t name_index = 0; name_index < attribute.name_len; name_index++) {
267 const char *name = GPU_vertformat_attr_name_get(&vertex_format, &attribute, name_index);
268 const ShaderInput *shader_input = interface.attr_get(name);
269 if (shader_input == nullptr || shader_input->location == -1) {
270 continue;
271 }
272
273 /* Don't overwrite attributes that are already occupied. */
274 AttributeMask attribute_mask = 1 << shader_input->location;
275 if (r_occupied_attributes & attribute_mask) {
276 continue;
277 }
278 r_occupied_attributes |= attribute_mask;
279 const uint32_t num_locations = to_binding_location_len(attribute);
280 for (const uint32_t location_offset : IndexRange(num_locations)) {
281 const uint32_t binding = bindings.size();
282 VkVertexInputAttributeDescription attribute_description = {};
283 attribute_description.binding = binding;
284 attribute_description.location = shader_input->location + location_offset;
285 attribute_description.offset = attribute_offset + location_offset * sizeof(float4);
286 attribute_description.format = to_vk_format(
287 static_cast<GPUVertCompType>(attribute.comp_type),
288 attribute.size,
289 static_cast<GPUVertFetchMode>(attribute.fetch_mode));
290 attributes.append(attribute_description);
291
292 VkVertexInputBindingDescription vk_binding_descriptor = {};
293 vk_binding_descriptor.binding = binding;
294 vk_binding_descriptor.stride = stride;
295 vk_binding_descriptor.inputRate = use_instancing ? VK_VERTEX_INPUT_RATE_INSTANCE :
296 VK_VERTEX_INPUT_RATE_VERTEX;
297 bindings.append(vk_binding_descriptor);
298 if (vertex_buffer) {
299 add_vbo = true;
300 vertex_buffer->upload();
301 buffers.append({vertex_buffer->vk_handle(), buffer_offset});
302 }
303 if (immediate_vertex_buffer) {
304 buffers.append(*immediate_vertex_buffer);
305 }
306 }
307 }
308 }
309
310 if (add_vbo) {
311 BLI_assert(vertex_buffer != nullptr);
312 vbos.append(vertex_buffer);
313 }
314}
315
318/* -------------------------------------------------------------------- */
323{
324 std::cout << __FILE__ << "::" << __func__ << "\n";
325 BitVector visited_bindings(bindings.size());
326
327 for (VkVertexInputAttributeDescription attribute : attributes) {
328 std::cout << " - attribute(binding=" << attribute.binding
329 << ", location=" << attribute.location << ")";
330
331 if (visited_bindings[attribute.binding]) {
332 std::cout << " WARNING: Already bound\n";
333 continue;
334 }
335 visited_bindings[attribute.binding].set(true);
336
337 if (attribute.binding < vbos.size()) {
338 std::cout << " Attach to Buffer\n";
339 }
340 else {
341 std::cout << " WARNING: Attach to dummy\n";
342 }
343 }
344}
345
348} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE int max_ii(int a, int b)
#define GPU_BATCH_INST_VBO_MAX_LEN
Definition GPU_batch.hh:33
#define GPU_BATCH_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
int64_t size() const
void append(const T &value)
void extend(Span< T > array)
const ShaderInput * attr_get(const char *name) const
static VKBackend & get()
Definition vk_backend.hh:92
VkBuffer vk_handle() const
Definition vk_buffer.hh:69
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
const GPUVertFormat & device_format_get() const
struct @620::@622 batch
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)
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
GPUVertAttr attrs[GPU_VERT_ATTR_MAX_LEN]
const GPUVertFormat & device_format_get() const