GPU: Add procedural drawcall in gpu::Batch

This allows to store a number of vertex to draw
per batch without specifying any attribute.

This allows to create batches that are empty but
still holds the amount of geometry to produce.

Needed for new curve drawing #142969.

Pull Request: https://projects.blender.org/blender/blender/pulls/143052
This commit is contained in:
Clément Foucault
2025-07-24 12:27:10 +02:00
committed by Clément Foucault
parent 614b6508d4
commit b6076e4d80
5 changed files with 38 additions and 28 deletions

View File

@@ -84,6 +84,8 @@ class Batch {
blender::gpu::IndexBuf *elem;
/** Resource ID attribute workaround. */
GPUStorageBuf *resource_id_buf;
/** Number of vertices to draw for procedural drawcalls. */
int32_t procedural_vertices;
/** Bookkeeping. */
eGPUBatchFlag flag;
/** Type of geometry to draw. */
@@ -142,6 +144,9 @@ blender::gpu::Batch *GPU_batch_create_ex(GPUPrimType primitive_type,
blender::gpu::VertBuf *vertex_buf,
blender::gpu::IndexBuf *index_buf,
eGPUBatchFlag owns_flag);
blender::gpu::Batch *GPU_batch_create_procedural(GPUPrimType primitive_type, int32_t vertex_count);
/**
* Creates a #blender::gpu::Batch without buffer ownership.
*/

View File

@@ -39,6 +39,7 @@ void GPU_batch_zero(Batch *batch)
batch->flag = eGPUBatchFlag(0);
batch->prim_type = GPUPrimType(0);
batch->shader = nullptr;
batch->procedural_vertices = 0;
}
Batch *GPU_batch_calloc()
@@ -80,6 +81,24 @@ void GPU_batch_init_ex(Batch *batch,
batch->prim_type = primitive_type;
batch->flag = owns_flag | GPU_BATCH_INIT | GPU_BATCH_DIRTY;
batch->shader = nullptr;
batch->procedural_vertices = 0;
}
Batch *GPU_batch_create_procedural(GPUPrimType primitive_type, int32_t vertex_count)
{
Batch *batch = GPU_batch_calloc();
for (auto &v : batch->verts) {
v = nullptr;
}
for (auto &v : batch->inst) {
v = nullptr;
}
batch->elem = nullptr;
batch->prim_type = primitive_type;
batch->flag = GPU_BATCH_INIT | GPU_BATCH_DIRTY;
batch->shader = nullptr;
batch->procedural_vertices = vertex_count;
return batch;
}
void GPU_batch_copy(Batch *batch_dst, Batch *batch_src)
@@ -92,6 +111,7 @@ void GPU_batch_copy(Batch *batch_dst, Batch *batch_src)
for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) {
batch_dst->verts[v] = batch_src->verts[v];
}
batch_dst->procedural_vertices = batch_src->procedural_vertices;
}
void GPU_batch_clear(Batch *batch)
@@ -114,6 +134,7 @@ void GPU_batch_clear(Batch *batch)
}
}
batch->flag = GPU_BATCH_INVALID;
batch->procedural_vertices = 0;
}
void GPU_batch_discard(Batch *batch)
@@ -461,7 +482,10 @@ void GPU_batch_draw_advanced(
Context::get()->assert_framebuffer_shader_compatibility(Context::get()->shader);
if (vertex_count == 0) {
if (batch->elem) {
if (batch->procedural_vertices > 0) {
vertex_count = batch->procedural_vertices;
}
else if (batch->elem) {
vertex_count = batch->elem_()->index_len_get();
}
else {

View File

@@ -289,17 +289,13 @@ static void test_framebuffer_multi_viewport()
GPUShader *shader = GPU_shader_create_from_info(
reinterpret_cast<GPUShaderCreateInfo *>(&create_info));
/* TODO(fclem): remove this boilerplate. */
GPUVertFormat format{};
GPU_vertformat_attr_add(&format, "dummy", VertAttrType::UINT_32);
VertBuf *verts = GPU_vertbuf_create_with_format(format);
GPU_vertbuf_data_alloc(*verts, 3);
Batch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, verts, nullptr, GPU_BATCH_OWNS_VBO);
int tri_count = size.x * size.y * layers;
Batch *batch = GPU_batch_create_procedural(GPU_PRIM_TRIS, tri_count * 3);
GPU_batch_set_shader(batch, shader);
int tri_count = size.x * size.y * layers;
GPU_batch_draw_advanced(batch, 0, tri_count * 3, 0, 1);
GPU_batch_draw(batch);
GPU_batch_discard(batch);
@@ -370,12 +366,7 @@ static void test_framebuffer_subpass_input()
GPUShader *shader_read = GPU_shader_create_from_info(
reinterpret_cast<GPUShaderCreateInfo *>(&create_info_read));
/* TODO(fclem): remove this boilerplate. */
GPUVertFormat format{};
GPU_vertformat_attr_add(&format, "dummy", VertAttrType::UINT_32);
VertBuf *verts = GPU_vertbuf_create_with_format(format);
GPU_vertbuf_data_alloc(*verts, 3);
Batch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, verts, nullptr, GPU_BATCH_OWNS_VBO);
Batch *batch = GPU_batch_create_procedural(GPU_PRIM_TRIS, 3);
/* Metal Raster Order Group does not need that. */
GPU_framebuffer_subpass_transition(

View File

@@ -374,15 +374,10 @@ static void gpu_shader_lib_test(const char *test_src_name, const char *additiona
GPU_framebuffer_ensure_config(&fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(tex)});
GPU_framebuffer_bind(fb);
/* TODO(fclem): remove this boilerplate. */
GPUVertFormat format{};
GPU_vertformat_attr_add(&format, "dummy", VertAttrType::UINT_32);
VertBuf *verts = GPU_vertbuf_create_with_format(format);
GPU_vertbuf_data_alloc(*verts, 3);
Batch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, verts, nullptr, GPU_BATCH_OWNS_VBO);
Batch *batch = GPU_batch_create_procedural(GPU_PRIM_TRIS, 3);
GPU_batch_set_shader(batch, shader);
GPU_batch_draw_advanced(batch, 0, 3, 0, 1);
GPU_batch_draw(batch);
GPU_batch_discard(batch);

View File

@@ -97,13 +97,8 @@ struct ShaderSpecializationConst {
GPU_framebuffer_default_size(fb, 1, 1);
GPU_framebuffer_bind(fb);
/* TODO(fclem): remove this boilerplate. */
GPUVertFormat format{};
GPU_vertformat_attr_add(&format, "dummy", VertAttrType::UINT_32);
VertBuf *verts = GPU_vertbuf_create_with_format(format);
Batch *batch = GPU_batch_create_procedural(GPU_PRIM_POINTS, 1);
GPU_vertbuf_data_alloc(*verts, 1);
Batch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, verts, nullptr, GPU_BATCH_OWNS_VBO);
GPU_batch_set_shader(batch, shader, &constants);
GPU_batch_draw_advanced(batch, 0, 1, 0, 1);
GPU_batch_discard(batch);