Blender V4.3
gpu_batch.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2016 by Mike Erwin. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12#include "MEM_guardedalloc.h"
13
14#include "BLI_math_base.h"
15#include "BLI_utildefines.h"
16
17#include "GPU_batch.hh"
18#include "GPU_batch_presets.hh"
19#include "GPU_platform.hh"
20#include "GPU_shader.hh"
21
22#include "GPU_index_buffer.hh"
23#include "GPU_vertex_buffer.hh"
24#include "gpu_backend.hh"
26#include "gpu_shader_private.hh"
27
28#include "GPU_batch.hh"
29
30#include <cstring>
31
32using namespace blender::gpu;
33
34/* -------------------------------------------------------------------- */
39{
40 std::fill_n(batch->verts, ARRAY_SIZE(batch->verts), nullptr);
41 std::fill_n(batch->inst, ARRAY_SIZE(batch->inst), nullptr);
42 batch->elem = nullptr;
43 batch->resource_id_buf = nullptr;
44 batch->flag = eGPUBatchFlag(0);
45 batch->prim_type = GPUPrimType(0);
46 batch->shader = nullptr;
47}
48
50{
51 Batch *batch = GPUBackend::get()->batch_alloc();
53 return batch;
54}
55
56Batch *GPU_batch_create_ex(GPUPrimType primitive_type,
57 VertBuf *vertex_buf,
58 IndexBuf *index_buf,
59 eGPUBatchFlag owns_flag)
60{
61 Batch *batch = GPU_batch_calloc();
62 GPU_batch_init_ex(batch, primitive_type, vertex_buf, index_buf, owns_flag);
63 return batch;
64}
65
67 GPUPrimType primitive_type,
68 VertBuf *vertex_buf,
69 IndexBuf *index_buf,
70 eGPUBatchFlag owns_flag)
71{
72 /* Do not pass any other flag */
73 BLI_assert((owns_flag & ~(GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX)) == 0);
74 /* Batch needs to be in cleared state. */
75 BLI_assert((batch->flag & GPU_BATCH_INIT) == 0);
76
77 batch->verts[0] = vertex_buf;
78 for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) {
79 batch->verts[v] = nullptr;
80 }
81 for (auto &v : batch->inst) {
82 v = nullptr;
83 }
84 batch->elem = index_buf;
85 batch->prim_type = primitive_type;
86 batch->flag = owns_flag | GPU_BATCH_INIT | GPU_BATCH_DIRTY;
87 batch->shader = nullptr;
88}
89
90void GPU_batch_copy(Batch *batch_dst, Batch *batch_src)
91{
92 GPU_batch_clear(batch_dst);
94 batch_dst, GPU_PRIM_POINTS, batch_src->verts[0], batch_src->elem, GPU_BATCH_INVALID);
95
96 batch_dst->prim_type = batch_src->prim_type;
97 for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) {
98 batch_dst->verts[v] = batch_src->verts[v];
99 }
100}
101
103{
104 if (batch->flag & GPU_BATCH_OWNS_INDEX) {
106 }
107 if (batch->flag & GPU_BATCH_OWNS_VBO_ANY) {
108 for (int v = 0; (v < GPU_BATCH_VBO_MAX_LEN) && batch->verts[v]; v++) {
109 if (batch->flag & (GPU_BATCH_OWNS_VBO << v)) {
111 }
112 }
113 }
115 for (int v = 0; (v < GPU_BATCH_INST_VBO_MAX_LEN) && batch->inst[v]; v++) {
116 if (batch->flag & (GPU_BATCH_OWNS_INST_VBO << v)) {
118 }
119 }
120 }
121 batch->flag = GPU_BATCH_INVALID;
122}
123
125{
127 delete batch;
128}
129
132/* -------------------------------------------------------------------- */
136void GPU_batch_instbuf_set(Batch *batch, VertBuf *vertex_buf, bool own_vbo)
137{
138 BLI_assert(vertex_buf);
139 batch->flag |= GPU_BATCH_DIRTY;
140
141 if (batch->inst[0] && (batch->flag & GPU_BATCH_OWNS_INST_VBO)) {
142 GPU_vertbuf_discard(batch->inst[0]);
143 }
144 batch->inst[0] = vertex_buf;
145
147}
148
149void GPU_batch_elembuf_set(Batch *batch, blender::gpu::IndexBuf *index_buf, bool own_ibo)
150{
151 BLI_assert(index_buf);
152 batch->flag |= GPU_BATCH_DIRTY;
153
154 if (batch->elem && (batch->flag & GPU_BATCH_OWNS_INDEX)) {
156 }
157 batch->elem = index_buf;
158
160}
161
162int GPU_batch_instbuf_add(Batch *batch, VertBuf *vertex_buf, bool own_vbo)
163{
164 BLI_assert(vertex_buf);
165 batch->flag |= GPU_BATCH_DIRTY;
166
167 for (uint v = 0; v < GPU_BATCH_INST_VBO_MAX_LEN; v++) {
168 if (batch->inst[v] == nullptr) {
169 /* for now all VertexBuffers must have same vertex_len */
170 if (batch->inst[0]) {
171 /* Allow for different size of vertex buffer (will choose the smallest number of verts). */
172 // BLI_assert(insts->vertex_len == batch->inst[0]->vertex_len);
173 }
174
175 batch->inst[v] = vertex_buf;
177 return v;
178 }
179 }
180 /* we only make it this far if there is no room for another VertBuf */
181 BLI_assert_msg(0, "Not enough Instance VBO slot in batch");
182 return -1;
183}
184
185int GPU_batch_vertbuf_add(Batch *batch, VertBuf *vertex_buf, bool own_vbo)
186{
187 BLI_assert(vertex_buf);
188 batch->flag |= GPU_BATCH_DIRTY;
189
190 for (uint v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
191 if (batch->verts[v] == nullptr) {
192 /* for now all VertexBuffers must have same vertex_len */
193 if (batch->verts[0] != nullptr) {
194 /* This is an issue for the HACK inside DRW_vbo_request(). */
195 // BLI_assert(verts->vertex_len == batch->verts[0]->vertex_len);
196 }
197 batch->verts[v] = vertex_buf;
199 return v;
200 }
201 }
202 /* we only make it this far if there is no room for another VertBuf */
203 BLI_assert_msg(0, "Not enough VBO slot in batch");
204 return -1;
205}
206
207bool GPU_batch_vertbuf_has(const Batch *batch, const VertBuf *vertex_buf)
208{
209 for (uint v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
210 if (batch->verts[v] == vertex_buf) {
211 return true;
212 }
213 }
214 return false;
215}
216
217void GPU_batch_resource_id_buf_set(Batch *batch, GPUStorageBuf *resource_id_buf)
218{
219 BLI_assert(resource_id_buf);
220 batch->flag |= GPU_BATCH_DIRTY;
221 batch->resource_id_buf = resource_id_buf;
222}
223
226/* -------------------------------------------------------------------- */
232{
233 batch->shader = shader;
234 GPU_shader_bind(batch->shader);
235}
236
238 GPUShader *shader,
239 VertBuf *vbo)
240{
241 const GPUVertFormat *format = &vbo->format;
242
243 /* We need to support GPU OpenSubdiv meshes. This assert can be enabled back after we refactor
244 * our OpenSubdiv implementation to output the same layout as the regular mesh extraction. */
245 // BLI_assert_msg(format->attr_len == 1, "Multi attribute buffers are not supported for now");
246
247 char uniform_name[] = "gpu_attr_0";
248 uint stride = format->stride;
249 uint offset = 0;
250 uint16_t bound_attr = 0u;
251 for (uint a_idx = 0; a_idx < format->attr_len; a_idx++) {
252 const GPUVertAttr *a = &format->attrs[a_idx];
253 for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
254 const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
255 const ShaderInput *input = interface->ssbo_get(name);
256 if (input == nullptr || input->location == -1) {
257 continue;
258 }
259 GPU_vertbuf_bind_as_ssbo(vbo, input->location);
260 bound_attr |= (1 << input->location);
261
262 /* WORKAROUND: This is to support complex format. But ideally this should not be supported.
263 */
264 uniform_name[9] = '0' + input->location;
265
266 if (format->deinterleaved) {
267 offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].size) * vbo->vertex_len;
268 stride = a->size;
269 }
270 else {
271 offset = a->offset;
272 }
273
274 /* Only support 4byte aligned attributes. */
275 BLI_assert((stride % 4) == 0);
276 BLI_assert((offset % 4) == 0);
277 int descriptor[2] = {int(stride) / 4, int(offset) / 4};
278 GPU_shader_uniform_2iv(shader, uniform_name, descriptor);
279 }
280 }
281 return bound_attr;
282}
283
285{
286 const ShaderInterface *interface = unwrap(shader)->interface;
287 if (interface->ssbo_attr_mask_ == 0) {
288 return;
289 }
290
291 uint16_t ssbo_attributes = interface->ssbo_attr_mask_;
292
293 if (ssbo_attributes & (1 << GPU_SSBO_INDEX_BUF_SLOT)) {
294 /* Ensure binding for setting uniforms. This is required by the OpenGL backend. */
295 GPU_shader_bind(shader);
296 if (batch->elem) {
298 GPU_shader_uniform_1b(shader, "gpu_index_no_buffer", false);
299 GPU_shader_uniform_1b(shader, "gpu_index_16bit", !batch->elem->is_32bit());
300 GPU_shader_uniform_1i(shader, "gpu_index_base_index", batch->elem->index_base_get());
301 }
302 else {
303 /* Still fulfill the binding requirements even if the buffer will not be read. */
305 GPU_shader_uniform_1b(shader, "gpu_index_no_buffer", true);
306 }
307 ssbo_attributes &= ~(1 << GPU_SSBO_INDEX_BUF_SLOT);
308 }
309
310 /* Reverse order so first VBO'S have more prevalence (in term of attribute override). */
311 for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) {
312 VertBuf *vbo = batch->verts_(v);
313 if (vbo) {
314 ssbo_attributes &= ~bind_attribute_as_ssbo(interface, shader, vbo);
315 }
316 }
317
318 BLI_assert_msg(ssbo_attributes == 0, "Not all attribute storage buffer fulfilled");
319 UNUSED_VARS_NDEBUG(ssbo_attributes);
320}
321
324/* -------------------------------------------------------------------- */
328void GPU_batch_draw_parameter_get(Batch *gpu_batch,
329 int *r_vertex_count,
330 int *r_vertex_first,
331 int *r_base_index,
332 int *r_instance_count)
333{
334 Batch *batch = static_cast<Batch *>(gpu_batch);
335
336 if (batch->elem) {
337 *r_vertex_count = batch->elem_()->index_len_get();
338 *r_vertex_first = batch->elem_()->index_start_get();
339 *r_base_index = batch->elem_()->index_base_get();
340 }
341 else {
342 *r_vertex_count = batch->verts_(0)->vertex_len;
343 *r_vertex_first = 0;
344 *r_base_index = -1;
345 }
346
347 int i_count = (batch->inst[0]) ? batch->inst_(0)->vertex_len : 1;
348 /* Meh. This is to be able to use different numbers of verts in instance VBO's. */
349 if (batch->inst[1] != nullptr) {
350 i_count = min_ii(i_count, batch->inst_(1)->vertex_len);
351 }
352 *r_instance_count = i_count;
353}
354
356 GPUPrimType expanded_prim_type,
357 int vertex_count,
358 int vertex_first)
359{
360 int vert_per_original_primitive = indices_per_primitive(batch->prim_type);
361 int vert_per_expanded_primitive = indices_per_primitive(expanded_prim_type);
362
363 BLI_assert_msg(vert_per_original_primitive != -1,
364 "Primitive expansion only works for primitives with known amount of vertices");
365
366 int prim_first = vertex_first / vert_per_original_primitive;
367 int prim_len = vertex_count / vert_per_original_primitive;
368
369 int out_vertex_first = prim_first * vert_per_expanded_primitive;
370 int out_vertex_count = prim_len * vert_per_expanded_primitive;
371
372 return blender::IndexRange(out_vertex_first, out_vertex_count);
373}
374
376{
377 GPU_shader_bind(batch->shader);
378 GPU_batch_draw_advanced(batch, 0, 0, 0, 0);
379}
380
381void GPU_batch_draw_range(Batch *batch, int vertex_first, int vertex_count)
382{
383 GPU_shader_bind(batch->shader);
384 GPU_batch_draw_advanced(batch, vertex_first, vertex_count, 0, 0);
385}
386
387void GPU_batch_draw_instance_range(Batch *batch, int instance_first, int instance_count)
388{
389 BLI_assert(batch->inst[0] == nullptr);
390
391 GPU_shader_bind(batch->shader);
392 GPU_batch_draw_advanced(batch, 0, 0, instance_first, instance_count);
393}
394
396 Batch *gpu_batch, int vertex_first, int vertex_count, int instance_first, int instance_count)
397{
398 BLI_assert(Context::get()->shader != nullptr);
399 Batch *batch = static_cast<Batch *>(gpu_batch);
400
401 if (vertex_count == 0) {
402 if (batch->elem) {
403 vertex_count = batch->elem_()->index_len_get();
404 }
405 else {
406 vertex_count = batch->verts_(0)->vertex_len;
407 }
408 }
409 if (instance_count == 0) {
410 instance_count = (batch->inst[0]) ? batch->inst_(0)->vertex_len : 1;
411 /* Meh. This is to be able to use different numbers of verts in instance VBO's. */
412 if (batch->inst[1] != nullptr) {
413 instance_count = min_ii(instance_count, batch->inst_(1)->vertex_len);
414 }
415 }
416
417 if (vertex_count == 0 || instance_count == 0) {
418 /* Nothing to draw. */
419 return;
420 }
421
422 batch->draw(vertex_first, vertex_count, instance_first, instance_count);
423}
424
425void GPU_batch_draw_indirect(Batch *gpu_batch, GPUStorageBuf *indirect_buf, intptr_t offset)
426{
427 BLI_assert(Context::get()->shader != nullptr);
428 BLI_assert(indirect_buf != nullptr);
429 Batch *batch = static_cast<Batch *>(gpu_batch);
430
431 batch->draw_indirect(indirect_buf, offset);
432}
433
435 Batch *gpu_batch, GPUStorageBuf *indirect_buf, int count, intptr_t offset, intptr_t stride)
436{
437 BLI_assert(Context::get()->shader != nullptr);
438 BLI_assert(indirect_buf != nullptr);
439 Batch *batch = static_cast<Batch *>(gpu_batch);
440
441 batch->multi_draw_indirect(indirect_buf, count, offset, stride);
442}
443
446/* -------------------------------------------------------------------- */
451 eGPUBuiltinShader shader_id,
452 eGPUShaderConfig sh_cfg)
453{
454 GPUShader *shader = GPU_shader_get_builtin_shader_with_config(shader_id, sh_cfg);
456}
457
462
467
470/* -------------------------------------------------------------------- */
478
483
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
MINLINE int min_ii(int a, int b)
unsigned int uint
#define ARRAY_SIZE(arr)
#define UNUSED_VARS_NDEBUG(...)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define GPU_BATCH_INST_VBO_MAX_LEN
Definition GPU_batch.hh:33
#define GPU_BATCH_VBO_MAX_LEN
Definition GPU_batch.hh:32
eGPUBatchFlag
Definition GPU_batch.hh:37
@ GPU_BATCH_INVALID
Definition GPU_batch.hh:39
@ GPU_BATCH_DIRTY
Definition GPU_batch.hh:58
@ GPU_BATCH_INIT
Definition GPU_batch.hh:54
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:51
@ GPU_BATCH_OWNS_INST_VBO
Definition GPU_batch.hh:46
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
@ GPU_BATCH_OWNS_VBO_ANY
Definition GPU_batch.hh:44
@ GPU_BATCH_OWNS_INST_VBO_ANY
Definition GPU_batch.hh:48
void gpu_batch_presets_init()
void gpu_batch_presets_exit()
void GPU_indexbuf_discard(blender::gpu::IndexBuf *elem)
void GPU_indexbuf_bind_as_ssbo(blender::gpu::IndexBuf *elem, int binding)
GPUPrimType
@ GPU_PRIM_POINTS
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2])
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value)
@ GPU_SHADER_CFG_DEFAULT
GPUShader * GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, eGPUShaderConfig sh_cfg)
eGPUBuiltinShader
#define GPU_VERTBUF_DISCARD_SAFE(verts)
void GPU_vertbuf_bind_as_ssbo(blender::gpu::VertBuf *verts, int binding)
void GPU_vertbuf_discard(blender::gpu::VertBuf *)
BLI_INLINE const char * GPU_vertformat_attr_name_get(const GPUVertFormat *format, const GPUVertAttr *attr, uint n_idx)
Read Guarded memory(de)allocation.
struct GPUShader GPUShader
ATTR_WARN_UNUSED_RESULT const BMVert * v
static Context * get()
static GPUBackend * get()
virtual Batch * batch_alloc()=0
const ShaderInput * ssbo_get(const char *name) const
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void GPU_batch_resource_id_buf_set(Batch *batch, GPUStorageBuf *resource_id_buf)
Definition gpu_batch.cc:217
void GPU_batch_draw_indirect(Batch *gpu_batch, GPUStorageBuf *indirect_buf, intptr_t offset)
Definition gpu_batch.cc:425
void GPU_batch_discard(Batch *batch)
Definition gpu_batch.cc:124
int GPU_batch_instbuf_add(Batch *batch, VertBuf *vertex_buf, bool own_vbo)
Definition gpu_batch.cc:162
Batch * GPU_batch_create_ex(GPUPrimType primitive_type, VertBuf *vertex_buf, IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:56
bool GPU_batch_vertbuf_has(const Batch *batch, const VertBuf *vertex_buf)
Definition gpu_batch.cc:207
void GPU_batch_program_set_imm_shader(Batch *batch)
Definition gpu_batch.cc:463
void GPU_batch_draw(Batch *batch)
Definition gpu_batch.cc:375
void GPU_batch_draw_instance_range(Batch *batch, int instance_first, int instance_count)
Definition gpu_batch.cc:387
static uint16_t bind_attribute_as_ssbo(const ShaderInterface *interface, GPUShader *shader, VertBuf *vbo)
Definition gpu_batch.cc:237
void GPU_batch_draw_parameter_get(Batch *gpu_batch, int *r_vertex_count, int *r_vertex_first, int *r_base_index, int *r_instance_count)
Definition gpu_batch.cc:328
Batch * GPU_batch_calloc()
Definition gpu_batch.cc:49
blender::IndexRange GPU_batch_draw_expanded_parameter_get(const blender::gpu::Batch *batch, GPUPrimType expanded_prim_type, int vertex_count, int vertex_first)
Definition gpu_batch.cc:355
void GPU_batch_draw_range(Batch *batch, int vertex_first, int vertex_count)
Definition gpu_batch.cc:381
int GPU_batch_vertbuf_add(Batch *batch, VertBuf *vertex_buf, bool own_vbo)
Definition gpu_batch.cc:185
void GPU_batch_program_set_builtin(Batch *batch, eGPUBuiltinShader shader_id)
Definition gpu_batch.cc:458
void GPU_batch_init_ex(Batch *batch, GPUPrimType primitive_type, VertBuf *vertex_buf, IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:66
void GPU_batch_set_shader(Batch *batch, GPUShader *shader)
Definition gpu_batch.cc:231
void GPU_batch_bind_as_resources(Batch *batch, GPUShader *shader)
Definition gpu_batch.cc:284
void GPU_batch_instbuf_set(Batch *batch, VertBuf *vertex_buf, bool own_vbo)
Definition gpu_batch.cc:136
void GPU_batch_zero(Batch *batch)
Definition gpu_batch.cc:38
void gpu_batch_init()
Definition gpu_batch.cc:474
void GPU_batch_draw_advanced(Batch *gpu_batch, int vertex_first, int vertex_count, int instance_first, int instance_count)
Definition gpu_batch.cc:395
void GPU_batch_copy(Batch *batch_dst, Batch *batch_src)
Definition gpu_batch.cc:90
void GPU_batch_program_set_builtin_with_config(Batch *batch, eGPUBuiltinShader shader_id, eGPUShaderConfig sh_cfg)
Definition gpu_batch.cc:450
void GPU_batch_clear(Batch *batch)
Definition gpu_batch.cc:102
void GPU_batch_elembuf_set(Batch *batch, blender::gpu::IndexBuf *index_buf, bool own_ibo)
Definition gpu_batch.cc:149
void gpu_batch_exit()
Definition gpu_batch.cc:479
void GPU_batch_multi_draw_indirect(Batch *gpu_batch, GPUStorageBuf *indirect_buf, int count, intptr_t offset, intptr_t stride)
Definition gpu_batch.cc:434
struct @620::@622 batch
GPUShader * immGetShader()
#define GPU_SSBO_INDEX_BUF_SLOT
int count
format
descriptor
int indices_per_primitive(GPUPrimType prim_type)
unsigned short uint16_t
Definition stdint.h:79
_W64 int intptr_t
Definition stdint.h:118