From b6076e4d800d12bbc457ebecdf0e57d50f8109e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 24 Jul 2025 12:27:10 +0200 Subject: [PATCH] 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 --- source/blender/gpu/GPU_batch.hh | 5 ++++ source/blender/gpu/intern/gpu_batch.cc | 26 ++++++++++++++++++- source/blender/gpu/tests/framebuffer_test.cc | 19 ++++---------- source/blender/gpu/tests/shader_test.cc | 9 ++----- .../tests/specialization_constants_test.cc | 7 +---- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/source/blender/gpu/GPU_batch.hh b/source/blender/gpu/GPU_batch.hh index 6b4d89032fc..606cd5066ae 100644 --- a/source/blender/gpu/GPU_batch.hh +++ b/source/blender/gpu/GPU_batch.hh @@ -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. */ diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 43db4cba96d..53dd4cf30e3 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -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 { diff --git a/source/blender/gpu/tests/framebuffer_test.cc b/source/blender/gpu/tests/framebuffer_test.cc index ca07f501671..71d9afe3e47 100644 --- a/source/blender/gpu/tests/framebuffer_test.cc +++ b/source/blender/gpu/tests/framebuffer_test.cc @@ -289,17 +289,13 @@ static void test_framebuffer_multi_viewport() GPUShader *shader = GPU_shader_create_from_info( reinterpret_cast(&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(&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( diff --git a/source/blender/gpu/tests/shader_test.cc b/source/blender/gpu/tests/shader_test.cc index b31def4f923..41c349ba2f1 100644 --- a/source/blender/gpu/tests/shader_test.cc +++ b/source/blender/gpu/tests/shader_test.cc @@ -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); diff --git a/source/blender/gpu/tests/specialization_constants_test.cc b/source/blender/gpu/tests/specialization_constants_test.cc index 70f3c2ea11b..a8c7693224e 100644 --- a/source/blender/gpu/tests/specialization_constants_test.cc +++ b/source/blender/gpu/tests/specialization_constants_test.cc @@ -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);