summaryrefslogtreecommitdiffstats
path: root/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
diff options
context:
space:
mode:
authorDario <dariosamo@gmail.com>2023-08-08 09:46:06 -0300
committerDario <dariosamo@gmail.com>2023-08-09 08:17:07 -0300
commit5155870d644b1598cd4c8dd675583c3fa1b79d60 (patch)
treea93c16c18bfe6c0a65b552467ad12a543e30f41b /servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
parentf7bc653cbe81018fe362472a0143b7153a52f929 (diff)
downloadredot-engine-5155870d644b1598cd4c8dd675583c3fa1b79d60.tar.gz
Improve handling of motion vectors for multimesh instances.
Fixes #67287. There was a subtle error where due to how enabling motion vectors for multi-meshes was handled, only the first instance would have a valid transforms buffer and the rest would point to an invalid buffer. This change moves over the responsibility of enabling motion vectors only when changes happen to the individual 3D transforms or the entire buffer itself. It also fixes an unnecessary download of the existing buffer that'd get overwritten by the current cache if it exists. Another fix is handling the case where the buffer was not set, and enabling motion vectors would not cause the buffer to be recreated correctly.
Diffstat (limited to 'servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp')
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp48
1 files changed, 32 insertions, 16 deletions
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 67b5cdd291..4bfec8ae8d 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -1289,12 +1289,9 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH);
}
-bool MeshStorage::_multimesh_enable_motion_vectors(RID p_multimesh) {
- MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, false);
-
+void MeshStorage::_multimesh_enable_motion_vectors(MultiMesh *multimesh) {
if (multimesh->motion_vectors_enabled) {
- return false;
+ return;
}
multimesh->motion_vectors_enabled = true;
@@ -1307,22 +1304,30 @@ bool MeshStorage::_multimesh_enable_motion_vectors(RID p_multimesh) {
multimesh->data_cache.append_array(multimesh->data_cache);
}
- if (multimesh->buffer_set) {
+ uint32_t buffer_size = multimesh->instances * multimesh->stride_cache * sizeof(float);
+ uint32_t new_buffer_size = buffer_size * 2;
+ RID new_buffer = RD::get_singleton()->storage_buffer_create(new_buffer_size);
+
+ if (multimesh->buffer_set && multimesh->data_cache.is_empty()) {
+ // If the buffer was set but there's no data cached in the CPU, we must download it from the GPU and
+ // upload it because RD does not provide a way to copy the buffer directly yet.
RD::get_singleton()->barrier();
Vector<uint8_t> buffer_data = RD::get_singleton()->buffer_get_data(multimesh->buffer);
- if (!multimesh->data_cache.is_empty()) {
- memcpy(buffer_data.ptrw(), multimesh->data_cache.ptr(), buffer_data.size());
- }
+ ERR_FAIL_COND(buffer_data.size() != int(buffer_size));
+ RD::get_singleton()->buffer_update(new_buffer, 0, buffer_size, buffer_data.ptr(), RD::BARRIER_MASK_NO_BARRIER);
+ RD::get_singleton()->buffer_update(new_buffer, buffer_size, buffer_size, buffer_data.ptr());
+ } else if (!multimesh->data_cache.is_empty()) {
+ // Simply upload the data cached in the CPU, which should already be doubled in size.
+ ERR_FAIL_COND(multimesh->data_cache.size() != int(new_buffer_size));
+ RD::get_singleton()->buffer_update(new_buffer, 0, new_buffer_size, multimesh->data_cache.ptr());
+ }
+ if (multimesh->buffer.is_valid()) {
RD::get_singleton()->free(multimesh->buffer);
- uint32_t buffer_size = multimesh->instances * multimesh->stride_cache * sizeof(float) * 2;
- multimesh->buffer = RD::get_singleton()->storage_buffer_create(buffer_size);
- RD::get_singleton()->buffer_update(multimesh->buffer, 0, buffer_data.size(), buffer_data.ptr(), RD::BARRIER_MASK_NO_BARRIER);
- RD::get_singleton()->buffer_update(multimesh->buffer, buffer_data.size(), buffer_data.size(), buffer_data.ptr());
- multimesh->uniform_set_3d = RID(); // Cleared by dependency
- return true;
}
- return false; // Update the transforms uniform set cache
+
+ multimesh->buffer = new_buffer;
+ multimesh->uniform_set_3d = RID(); // Cleared by dependency.
}
void MeshStorage::_multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset) {
@@ -1531,6 +1536,12 @@ void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index,
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D);
_multimesh_make_local(multimesh);
+
+ bool uses_motion_vectors = (RSG::viewport->get_num_viewports_with_motion_vectors() > 0);
+ if (uses_motion_vectors) {
+ _multimesh_enable_motion_vectors(multimesh);
+ }
+
_multimesh_update_motion_vectors_data_cache(multimesh);
{
@@ -1749,6 +1760,11 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
ERR_FAIL_COND(!multimesh);
ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
+ bool uses_motion_vectors = (RSG::viewport->get_num_viewports_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();