Skip to content

Commit

Permalink
Add multimesh_set_buffer_raw to RenderingServer
Browse files Browse the repository at this point in the history
  • Loading branch information
huwpascoe committed Sep 4, 2024
1 parent e2dd56b commit e048c03
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 0 deletions.
15 changes: 15 additions & 0 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2514,6 +2514,13 @@
[b]Note:[/b] If the buffer is in the engine's internal cache, it will have to be fetched from GPU memory and possibly decompressed. This means [method multimesh_get_buffer] is potentially a slow operation and should be avoided whenever possible.
</description>
</method>
<method name="multimesh_get_buffer_raw" qualifiers="const">
<return type="PackedByteArray" />
<param index="0" name="multimesh" type="RID" />
<description>
Returns the MultiMesh data without decompression.
</description>
</method>
<method name="multimesh_get_custom_aabb" qualifiers="const">
<return type="AABB" />
<param index="0" name="multimesh" type="RID" />
Expand Down Expand Up @@ -2640,6 +2647,14 @@
[/codeblock]
</description>
</method>
<method name="multimesh_set_buffer_raw">
<return type="void" />
<param index="0" name="multimesh" type="RID" />
<param index="1" name="buffer" type="PackedByteArray" />
<description>
Set the MultiMesh buffer from preprocessed data.
</description>
</method>
<method name="multimesh_set_buffer_interpolated">
<return type="void" />
<param index="0" name="multimesh" type="RID" />
Expand Down
61 changes: 61 additions & 0 deletions drivers/gles3/storage/mesh_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2046,6 +2046,67 @@ Vector<float> MeshStorage::_multimesh_get_buffer(RID p_multimesh) const {
}
}

void MeshStorage::_multimesh_set_buffer_raw(RID p_multimesh, const PackedByteArray &p_buffer) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache * (int)sizeof(float)));

// If we have a data cache, just update it.
if (multimesh->data_cache.size()) {
multimesh->data_cache.resize(p_buffer.size() / sizeof(float));
memcpy(multimesh->data_cache.ptrw(), p_buffer.ptr(), multimesh->data_cache.size());
}

const uint8_t *r = p_buffer.ptr();
glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
glBufferData(GL_ARRAY_BUFFER, p_buffer.size(), r, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

multimesh->buffer_set = true;

if (multimesh->data_cache.size() || multimesh->uses_colors || multimesh->uses_custom_data) {
// Clear dirty since nothing will be dirty anymore.
uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, MULTIMESH_DIRTY_REGION_SIZE);
for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
multimesh->data_cache_dirty_regions[i] = false;
}
multimesh->data_cache_used_dirty_regions = 0;

_multimesh_mark_all_dirty(multimesh, false, true); //update AABB
} else if (multimesh->mesh.is_valid()) {
//if we have a mesh set, we need to re-generate the AABB from the new data
const uint8_t *data = p_buffer.ptr();

if (multimesh->custom_aabb == AABB()) {
_multimesh_re_create_aabb(multimesh, reinterpret_cast<const float *>(data), multimesh->instances);
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
}
}

PackedByteArray MeshStorage::_multimesh_get_buffer_raw(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, PackedByteArray());
PackedByteArray ret;
if (multimesh->buffer == 0 || multimesh->instances == 0) {
return PackedByteArray();
} else if (multimesh->data_cache.size()) {
ret = multimesh->data_cache.to_byte_array();
} else {
// Buffer not cached, so fetch from GPU memory. This can be a stalling operation, avoid whenever possible.

Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float));
ret.resize(multimesh->instances * multimesh->stride_cache * sizeof(float));
{
uint8_t *w = ret.ptrw();
const uint8_t *r = buffer.ptr();
memcpy(w, r, buffer.size());
}
}

return ret;
}

void MeshStorage::_multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
Expand Down
2 changes: 2 additions & 0 deletions drivers/gles3/storage/mesh_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,8 @@ 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 Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
virtual void _multimesh_set_buffer_raw(RID p_multimesh, const PackedByteArray &p_buffer) override;
virtual PackedByteArray _multimesh_get_buffer_raw(RID p_multimesh) const override;

virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
virtual int _multimesh_get_visible_instances(RID p_multimesh) const override;
Expand Down
16 changes: 16 additions & 0 deletions servers/rendering/dummy/storage/mesh_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,19 @@ Vector<float> MeshStorage::_multimesh_get_buffer(RID p_multimesh) const {

return multimesh->buffer;
}

void MeshStorage::_multimesh_set_buffer_raw(RID p_multimesh, const PackedByteArray &p_buffer) {
DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
multimesh->buffer.resize(p_buffer.size() / (PackedByteArray::Size)sizeof(float));
ERR_FAIL_COND(p_buffer.size() != multimesh->buffer.size() * (PackedByteArray::Size)sizeof(float));
float *cache_data = multimesh->buffer.ptrw();
memcpy(cache_data, p_buffer.ptr(), p_buffer.size());
}

PackedByteArray MeshStorage::_multimesh_get_buffer_raw(RID p_multimesh) const {
DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, PackedByteArray());

return multimesh->buffer.to_byte_array();
}
2 changes: 2 additions & 0 deletions servers/rendering/dummy/storage/mesh_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ class MeshStorage : public RendererMeshStorage {
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 Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
virtual void _multimesh_set_buffer_raw(RID p_multimesh, const PackedByteArray &p_buffer) override;
virtual PackedByteArray _multimesh_get_buffer_raw(RID p_multimesh) const override;

virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {}
virtual int _multimesh_get_visible_instances(RID p_multimesh) const override { return 0; }
Expand Down
69 changes: 69 additions & 0 deletions servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2000,6 +2000,75 @@ Vector<float> MeshStorage::_multimesh_get_buffer(RID p_multimesh) const {
}
}

void MeshStorage::_multimesh_set_buffer_raw(RID p_multimesh, const PackedByteArray &p_buffer) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache * (int)sizeof(float)));

bool used_motion_vectors = multimesh->motion_vectors_enabled;
bool uses_motion_vectors = (RSG::viewport->get_num_viewports_with_motion_vectors() > 0) || (RendererCompositorStorage::get_singleton()->get_num_compositor_effects_with_motion_vectors() > 0);
if (uses_motion_vectors) {
_multimesh_enable_motion_vectors(multimesh);
}

if (multimesh->motion_vectors_enabled) {
uint32_t frame = RSG::rasterizer->get_frame_number();

if (multimesh->motion_vectors_last_change != frame) {
multimesh->motion_vectors_previous_offset = multimesh->motion_vectors_current_offset;
multimesh->motion_vectors_current_offset = multimesh->instances - multimesh->motion_vectors_current_offset;
multimesh->motion_vectors_last_change = frame;
}
}

{
const uint8_t *r = p_buffer.ptr();
RD::get_singleton()->buffer_update(multimesh->buffer, multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float), p_buffer.size() * sizeof(float), r);
if (multimesh->motion_vectors_enabled && !used_motion_vectors) {
// Motion vectors were just enabled, and the other half of the buffer will be empty.
// Need to ensure that both halves are filled for correct operation.
RD::get_singleton()->buffer_update(multimesh->buffer, multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float), p_buffer.size() * sizeof(float), r);
}
multimesh->buffer_set = true;
}

if (multimesh->data_cache.size()) {
float *cache_data = multimesh->data_cache.ptrw();
memcpy(cache_data + (multimesh->motion_vectors_current_offset * multimesh->stride_cache), p_buffer.ptr(), p_buffer.size());
_multimesh_mark_all_dirty(multimesh, true, true); //update AABB
} else if (multimesh->mesh.is_valid()) {
//if we have a mesh set, we need to re-generate the AABB from the new data
const uint8_t *data = p_buffer.ptr();

if (multimesh->custom_aabb == AABB()) {
_multimesh_re_create_aabb(multimesh, reinterpret_cast<const float *>(data), multimesh->instances);
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
}
}

PackedByteArray MeshStorage::_multimesh_get_buffer_raw(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, PackedByteArray());
if (multimesh->buffer.is_null()) {
return PackedByteArray();
} else {
PackedByteArray ret;
ret.resize(multimesh->instances * multimesh->stride_cache * sizeof(float));
uint8_t *w = ret.ptrw();

if (multimesh->data_cache.size()) {
const uint8_t *r = (uint8_t *)multimesh->data_cache.ptr() + multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float);
memcpy(w, r, ret.size());
} else {
Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
const uint8_t *r = buffer.ptr() + multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float);
memcpy(w, r, ret.size());
}
return ret;
}
}

void MeshStorage::_multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/renderer_rd/storage_rd/mesh_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,8 @@ class MeshStorage : public RendererMeshStorage {

virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
virtual void _multimesh_set_buffer_raw(RID p_multimesh, const PackedByteArray &p_buffer) override;
virtual PackedByteArray _multimesh_get_buffer_raw(RID p_multimesh) const override;

virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
virtual int _multimesh_get_visible_instances(RID p_multimesh) const override;
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/rendering_server_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,8 @@ class RenderingServerDefault : public RenderingServer {

FUNC2(multimesh_set_buffer, RID, const Vector<float> &)
FUNC1RC(Vector<float>, multimesh_get_buffer, RID)
FUNC2(multimesh_set_buffer_raw, RID, const PackedByteArray &)
FUNC1RC(PackedByteArray, multimesh_get_buffer_raw, RID)

FUNC3(multimesh_set_buffer_interpolated, RID, const Vector<float> &, const Vector<float> &)
FUNC2(multimesh_set_physics_interpolated, RID, bool)
Expand Down
25 changes: 25 additions & 0 deletions servers/rendering/storage/mesh_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,31 @@ Vector<float> RendererMeshStorage::multimesh_get_buffer(RID p_multimesh) const {
return _multimesh_get_buffer(p_multimesh);
}

void RendererMeshStorage::multimesh_set_buffer_raw(RID p_multimesh, const PackedByteArray &p_buffer) {
MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
if (mmi && mmi->interpolated) {
ERR_FAIL_COND_MSG(p_buffer.size() / (PackedFloat32Array::Size)sizeof(float) != mmi->_data_curr.size(), vformat("Buffer should have %d elements, got %d instead.", mmi->_data_curr.size(), p_buffer.size() / (PackedFloat32Array::Size)sizeof(float)));

mmi->_data_curr.resize(p_buffer.size() / (PackedFloat32Array::Size)sizeof(float));
memcpy(mmi->_data_curr.ptrw(), p_buffer.ptr(), p_buffer.size());
_multimesh_add_to_interpolation_lists(p_multimesh, *mmi);

#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
if (!Engine::get_singleton()->is_in_physics_frame()) {
PHYSICS_INTERPOLATION_WARNING("MultiMesh interpolation is being triggered from outside physics process, this might lead to issues");
}
#endif

return;
}

_multimesh_set_buffer_raw(p_multimesh, p_buffer);
}

PackedByteArray RendererMeshStorage::multimesh_get_buffer_raw(RID p_multimesh) const {
return _multimesh_get_buffer_raw(p_multimesh);
}

void RendererMeshStorage::multimesh_set_buffer_interpolated(RID p_multimesh, const Vector<float> &p_buffer, const Vector<float> &p_buffer_prev) {
MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
if (mmi) {
Expand Down
4 changes: 4 additions & 0 deletions servers/rendering/storage/mesh_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ class RendererMeshStorage {

virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer);
virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const;
virtual void multimesh_set_buffer_raw(RID p_multimesh, const PackedByteArray &p_buffer);
virtual PackedByteArray multimesh_get_buffer_raw(RID p_multimesh) const;

virtual void multimesh_set_buffer_interpolated(RID p_multimesh, const Vector<float> &p_buffer, const Vector<float> &p_buffer_prev);
virtual void multimesh_set_physics_interpolated(RID p_multimesh, bool p_interpolated);
Expand Down Expand Up @@ -179,6 +181,8 @@ class RendererMeshStorage {

virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const = 0;
virtual void _multimesh_set_buffer_raw(RID p_multimesh, const PackedByteArray &p_buffer) = 0;
virtual PackedByteArray _multimesh_get_buffer_raw(RID p_multimesh) const = 0;

virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0;
virtual int _multimesh_get_visible_instances(RID p_multimesh) const = 0;
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2438,6 +2438,8 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("multimesh_get_visible_instances", "multimesh"), &RenderingServer::multimesh_get_visible_instances);
ClassDB::bind_method(D_METHOD("multimesh_set_buffer", "multimesh", "buffer"), &RenderingServer::multimesh_set_buffer);
ClassDB::bind_method(D_METHOD("multimesh_get_buffer", "multimesh"), &RenderingServer::multimesh_get_buffer);
ClassDB::bind_method(D_METHOD("multimesh_set_buffer_raw", "multimesh", "buffer"), &RenderingServer::multimesh_set_buffer_raw);
ClassDB::bind_method(D_METHOD("multimesh_get_buffer_raw", "multimesh"), &RenderingServer::multimesh_get_buffer_raw);

ClassDB::bind_method(D_METHOD("multimesh_set_buffer_interpolated", "multimesh", "buffer", "buffer_previous"), &RenderingServer::multimesh_set_buffer_interpolated);
ClassDB::bind_method(D_METHOD("multimesh_set_physics_interpolated", "multimesh", "interpolated"), &RenderingServer::multimesh_set_physics_interpolated);
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,8 @@ class RenderingServer : public Object {

virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0;
virtual void multimesh_set_buffer_raw(RID p_multimesh, const PackedByteArray &p_buffer) = 0;
virtual PackedByteArray multimesh_get_buffer_raw(RID p_multimesh) const = 0;

// Interpolation.
virtual void multimesh_set_buffer_interpolated(RID p_multimesh, const Vector<float> &p_buffer_curr, const Vector<float> &p_buffer_prev) = 0;
Expand Down

0 comments on commit e048c03

Please sign in to comment.