Added indirect drawing functionality to MultiMesh

Update doc/classes/RenderingServer.xml

Co-Authored-By: Micky <66727710+Mickeon@users.noreply.github.com>
This commit is contained in:
David House 2024-11-19 08:34:01 -06:00
parent d19147e09a
commit e6daec9cf8
17 changed files with 143 additions and 15 deletions

View file

@ -1485,7 +1485,7 @@ void MeshStorage::_multimesh_free(RID p_rid) {
multimesh_owner.free(p_rid);
}
void MeshStorage::_multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
void MeshStorage::_multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data, bool p_use_indirect) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
@ -1521,6 +1521,9 @@ void MeshStorage::_multimesh_allocate_data(RID p_multimesh, int p_instances, RS:
multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 4 : 0);
multimesh->buffer_set = false;
multimesh->indirect = p_use_indirect;
multimesh->command_buffer = RID();
//print_line("allocate, elements: " + itos(p_instances) + " 2D: " + itos(p_transform_format == RS::MULTIMESH_TRANSFORM_2D) + " colors " + itos(multimesh->uses_colors) + " data " + itos(multimesh->uses_custom_data) + " stride " + itos(multimesh->stride_cache) + " total size " + itos(multimesh->stride_cache * multimesh->instances));
multimesh->data_cache = Vector<float>();
multimesh->aabb = AABB();
@ -1609,6 +1612,30 @@ void MeshStorage::_multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
}
multimesh->mesh = p_mesh;
if (multimesh->indirect) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_NULL(mesh);
if (mesh->surface_count > 0) {
if (multimesh->command_buffer.is_valid()) {
RD::get_singleton()->free(multimesh->command_buffer);
}
Vector<uint8_t> newVector;
newVector.resize_zeroed(sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE * mesh->surface_count);
for (uint32_t i = 0; i < mesh->surface_count; i++) {
uint32_t count = mesh_surface_get_vertices_drawn_count(mesh->surfaces[i]);
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE, static_cast<uint8_t>(count));
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE + 1, static_cast<uint8_t>(count >> 8));
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE + 2, static_cast<uint8_t>(count >> 16));
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE + 3, static_cast<uint8_t>(count >> 24));
}
RID newBuffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE * mesh->surface_count, newVector, RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
multimesh->command_buffer = newBuffer;
}
}
if (multimesh->instances == 0) {
return;
}
@ -2064,6 +2091,12 @@ void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_
}
}
RID MeshStorage::_multimesh_get_command_buffer_rd_rid(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, RID());
return multimesh->command_buffer;
}
RID MeshStorage::_multimesh_get_buffer_rd_rid(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, RID());
@ -2111,6 +2144,15 @@ void MeshStorage::_multimesh_set_visible_instances(RID p_multimesh, int p_visibl
multimesh->visible_instances = p_visible;
if (multimesh->indirect) { //we have to update the command buffer for the instance counts, in each stride this will be the second integer.
Mesh *mesh = mesh_owner.get_or_null(multimesh->mesh);
if (mesh != nullptr) {
for (uint32_t i = 0; i < mesh->surface_count; i++) {
RD::get_singleton()->buffer_update(multimesh->command_buffer, (i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE) + sizeof(uint32_t), sizeof(uint32_t), &p_visible);
}
}
}
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES);
}

View file

@ -59,6 +59,10 @@ public:
DEFAULT_RD_BUFFER_MAX,
};
enum IndirectMultiMesh : uint32_t {
INDIRECT_MULTIMESH_COMMAND_STRIDE = 5
};
private:
static MeshStorage *singleton;
@ -226,6 +230,7 @@ private:
AABB custom_aabb;
bool aabb_dirty = false;
bool buffer_set = false;
bool indirect = false;
bool motion_vectors_enabled = false;
uint32_t motion_vectors_current_offset = 0;
uint32_t motion_vectors_previous_offset = 0;
@ -243,6 +248,7 @@ private:
RID buffer; //storage buffer
RID uniform_set_3d;
RID uniform_set_2d;
RID command_buffer; //used if indirect setting is used
bool dirty = false;
MultiMesh *dirty_list = nullptr;
@ -637,7 +643,7 @@ public:
virtual void _multimesh_initialize(RID p_multimesh) override;
virtual void _multimesh_free(RID p_rid) override;
virtual void _multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override;
virtual void _multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false, bool p_use_indirect = false) override;
virtual int _multimesh_get_instance_count(RID p_multimesh) const override;
virtual void _multimesh_set_mesh(RID p_multimesh, RID p_mesh) override;
@ -654,6 +660,7 @@ public:
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
virtual RID _multimesh_get_command_buffer_rd_rid(RID p_multimesh) const override;
virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const override;
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
@ -672,6 +679,11 @@ public:
bool _multimesh_uses_motion_vectors_offsets(RID p_multimesh);
bool _multimesh_uses_motion_vectors(RID p_multimesh);
_FORCE_INLINE_ bool multimesh_uses_indirect(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
return multimesh->indirect;
}
_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
return multimesh->xform_format;