Skip to content

Commit

Permalink
Merge pull request #99455 from Bonkahe/IndirectMultimeshImplementation
Browse files Browse the repository at this point in the history
Add indirect draw functionality to `MultiMesh`
  • Loading branch information
akien-mga committed Jan 14, 2025
2 parents 1ca03ad + e6daec9 commit 85b066a
Show file tree
Hide file tree
Showing 17 changed files with 143 additions and 15 deletions.
24 changes: 24 additions & 0 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2559,6 +2559,7 @@
<param index="2" name="transform_format" type="int" enum="RenderingServer.MultimeshTransformFormat" />
<param index="3" name="color_format" type="bool" default="false" />
<param index="4" name="custom_data_format" type="bool" default="false" />
<param index="5" name="use_indirect" type="bool" default="false" />
<description>
</description>
</method>
Expand Down Expand Up @@ -2593,6 +2594,29 @@
Returns the [RenderingDevice] [RID] handle of the [MultiMesh], which can be used as any other buffer on the Rendering Device.
</description>
</method>
<method name="multimesh_get_command_buffer_rd_rid" qualifiers="const">
<return type="RID" />
<param index="0" name="multimesh" type="RID" />
<description>
Returns the [RenderingDevice] [RID] handle of the [MultiMesh] command buffer. This [RID] is only valid if [code]use_indirect[/code] is set to [code]true[/code] when allocating data through [method multimesh_allocate_data]. It can be used to directly modify the instance count via buffer.
The data structure is dependent on both how many surfaces the mesh contains and whether it is indexed or not, the buffer has 5 integers in it, with the last unused if the mesh is not indexed.
Each of the values in the buffer correspond to these options:
[codeblock lang=text]
Indexed:
0 - indexCount;
1 - instanceCount;
2 - firstIndex;
3 - vertexOffset;
4 - firstInstance;
Non Indexed:
0 - vertexCount;
1 - instanceCount;
2 - firstVertex;
3 - firstInstance;
4 - unused;
[/codeblock]
</description>
</method>
<method name="multimesh_get_custom_aabb" qualifiers="const">
<return type="AABB" />
<param index="0" name="multimesh" type="RID" />
Expand Down
6 changes: 5 additions & 1 deletion drivers/gles3/storage/mesh_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1518,7 +1518,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);

Expand Down Expand Up @@ -2041,6 +2041,10 @@ void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_
}
}

RID MeshStorage::_multimesh_get_command_buffer_rd_rid(RID p_multimesh) const {
ERR_FAIL_V_MSG(RID(), "GLES3 does not implement indirect multimeshes.");
}

RID MeshStorage::_multimesh_get_buffer_rd_rid(RID p_multimesh) const {
ERR_FAIL_V_MSG(RID(), "GLES3 does not contain a Rid for the multimesh buffer.");
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/gles3/storage/mesh_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ class MeshStorage : public RendererMeshStorage {
virtual RID _multimesh_allocate() override;
virtual void _multimesh_initialize(RID p_rid) 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;
Expand All @@ -521,6 +521,7 @@ class MeshStorage : public RendererMeshStorage {
virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
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;

Expand Down
7 changes: 7 additions & 0 deletions misc/extension_api_validation/4.3-stable.expected
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ Validate extension JSON: Error: Field 'classes/Control/properties/offset_top': t
Property type changed to float to match the actual internal API and documentation.


GH-99455
--------
Validate extension JSON: Error: Field 'classes/RenderingServer/methods/multimesh_allocate_data/arguments': size changed value in new API, from 5 to 6.

Optional argument added to allow setting indirect draw mode on Multimesh. Compatibility method registered.


GH-100129
---------
Validate extension JSON: Error: Field 'classes/NavigationServer2D/methods/query_path': is_const changed value in new API, from true to false.
Expand Down
3 changes: 2 additions & 1 deletion servers/rendering/dummy/storage/mesh_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class MeshStorage : public RendererMeshStorage {
virtual void _multimesh_initialize(RID p_rid) 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 { return 0; }

virtual void _multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {}
Expand All @@ -171,6 +171,7 @@ class MeshStorage : public RendererMeshStorage {
virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
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 { return RID(); }
virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const override { return RID(); }
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,11 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
instance_count /= surf->owner->trail_steps;
}

RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
if (bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT)) {
RD::get_singleton()->draw_list_draw_indirect(draw_list, index_array_rd.is_valid(), mesh_storage->_multimesh_get_command_buffer_rd_rid(surf->owner->data->base), surf->surface_index * sizeof(uint32_t) * mesh_storage->INDIRECT_MULTIMESH_COMMAND_STRIDE, 1, 0);
} else {
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
}
}

i += element_info.repeat - 1; //skip equal elements
Expand Down Expand Up @@ -1083,6 +1087,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
} else {
surf->sort.lod_index = 0;
if (p_render_data->render_info) {
// This does not include primitives rendered via indirect draw calls.
uint32_t to_draw = mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
to_draw = _indices_to_primitives(surf->primitive, to_draw);
to_draw *= inst->instance_count;
Expand Down Expand Up @@ -4205,9 +4210,9 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p
ginstance->base_flags = 0;

bool store_transform = true;

if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;

if (mesh_storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
}
Expand All @@ -4217,6 +4222,9 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p
if (mesh_storage->multimesh_uses_custom_data(ginstance->data->base)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
}
if (mesh_storage->multimesh_uses_indirect(ginstance->data->base)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT;
}

ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {

// When changing any of these enums, remember to change the corresponding enums in the shader files as well.
enum {
INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT = 1 << 2,
INSTANCE_DATA_FLAGS_DYNAMIC = 1 << 3,
INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2380,7 +2380,11 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
instance_count /= surf->owner->trail_steps;
}

RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
if (bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT)) {
RD::get_singleton()->draw_list_draw_indirect(draw_list, index_array_rd.is_valid(), mesh_storage->_multimesh_get_command_buffer_rd_rid(surf->owner->data->base), surf->surface_index * sizeof(uint32_t) * mesh_storage->INDIRECT_MULTIMESH_COMMAND_STRIDE, 1, 0);
} else {
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
}
}
}

Expand Down Expand Up @@ -2801,6 +2805,7 @@ void RenderForwardMobile::_geometry_instance_update(RenderGeometryInstance *p_ge

if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;

if (mesh_storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
}
Expand All @@ -2810,6 +2815,9 @@ void RenderForwardMobile::_geometry_instance_update(RenderGeometryInstance *p_ge
if (mesh_storage->multimesh_uses_custom_data(ginstance->data->base)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
}
if (mesh_storage->multimesh_uses_indirect(ginstance->data->base)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT;
}

ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ class RenderForwardMobile : public RendererSceneRenderRD {

// When changing any of these enums, remember to change the corresponding enums in the shader files as well.
enum {
INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT = 1 << 2,
INSTANCE_DATA_FLAGS_DYNAMIC = 1 << 3,
INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
Expand Down
44 changes: 43 additions & 1 deletion servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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);
}

Expand Down
14 changes: 13 additions & 1 deletion servers/rendering/renderer_rd/storage_rd/mesh_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ class MeshStorage : public RendererMeshStorage {
DEFAULT_RD_BUFFER_MAX,
};

enum IndirectMultiMesh : uint32_t {
INDIRECT_MULTIMESH_COMMAND_STRIDE = 5
};

private:
static MeshStorage *singleton;

Expand Down Expand Up @@ -226,6 +230,7 @@ class MeshStorage : public RendererMeshStorage {
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;
Expand All @@ -243,6 +248,7 @@ class MeshStorage : public RendererMeshStorage {
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;
Expand Down Expand Up @@ -637,7 +643,7 @@ class MeshStorage : public RendererMeshStorage {
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;
Expand All @@ -654,6 +660,7 @@ class MeshStorage : public RendererMeshStorage {
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;

Expand All @@ -672,6 +679,11 @@ class MeshStorage : public RendererMeshStorage {
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;
Expand Down
3 changes: 2 additions & 1 deletion servers/rendering/rendering_server_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ class RenderingServerDefault : public RenderingServer {

FUNCRIDSPLIT(multimesh)

FUNC5(multimesh_allocate_data, RID, int, MultimeshTransformFormat, bool, bool)
FUNC6(multimesh_allocate_data, RID, int, MultimeshTransformFormat, bool, bool, bool)
FUNC1RC(int, multimesh_get_instance_count, RID)

FUNC2(multimesh_set_mesh, RID, RID)
Expand All @@ -403,6 +403,7 @@ class RenderingServerDefault : public RenderingServer {
FUNC2RC(Color, multimesh_instance_get_custom_data, RID, int)

FUNC2(multimesh_set_buffer, RID, const Vector<float> &)
FUNC1RC(RID, multimesh_get_command_buffer_rd_rid, RID)
FUNC1RC(RID, multimesh_get_buffer_rd_rid, RID)
FUNC1RC(Vector<float>, multimesh_get_buffer, RID)

Expand Down
8 changes: 6 additions & 2 deletions servers/rendering/storage/mesh_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void RendererMeshStorage::multimesh_free(RID p_rid) {
_multimesh_free(p_rid);
}

void RendererMeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
void RendererMeshStorage::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) {
MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
if (mmi) {
mmi->_transform_format = p_transform_format;
Expand All @@ -68,7 +68,7 @@ void RendererMeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instanc
mmi->_data_interpolated.resize_zeroed(size_in_floats);
}

_multimesh_allocate_data(p_multimesh, p_instances, p_transform_format, p_use_colors, p_use_custom_data);
_multimesh_allocate_data(p_multimesh, p_instances, p_transform_format, p_use_colors, p_use_custom_data, p_use_indirect);
}

int RendererMeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
Expand Down Expand Up @@ -223,6 +223,10 @@ void RendererMeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<flo
_multimesh_set_buffer(p_multimesh, p_buffer);
}

RID RendererMeshStorage::multimesh_get_command_buffer_rd_rid(RID p_multimesh) const {
return _multimesh_get_command_buffer_rd_rid(p_multimesh);
}

RID RendererMeshStorage::multimesh_get_buffer_rd_rid(RID p_multimesh) const {
return _multimesh_get_buffer_rd_rid(p_multimesh);
}
Expand Down
Loading

0 comments on commit 85b066a

Please sign in to comment.