Skip to content

Commit

Permalink
feat: implement deeper throttling for Transform, MeshRenderer and…
Browse files Browse the repository at this point in the history
… `GltfContainer` (#177)

* feat: implement deeper throttling for `Transform`, `MeshRenderer` and `GltfContainer`

* set times that make senses
  • Loading branch information
leanmendoza committed Jan 24, 2024
1 parent e54ff92 commit c249172
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 119 deletions.
36 changes: 9 additions & 27 deletions godot/src/decentraland_components/gltf_container.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ enum GltfContainerLoadingState {
FINISHED = 4,
}

var file_hash: String = ""
var gltf_node = null


func _ready():
self.async_load_gltf.call_deferred()
Expand All @@ -20,9 +17,7 @@ func async_load_gltf():
var content_mapping := Global.scene_runner.get_scene_content_mapping(dcl_scene_id)

self.dcl_gltf_src = dcl_gltf_src.to_lower()
self.file_hash = content_mapping.get_hash(dcl_gltf_src)

if self.file_hash.is_empty():
if content_mapping.get_hash(dcl_gltf_src).is_empty():
dcl_gltf_loading_state = GltfContainerLoadingState.NOT_FOUND
return

Expand Down Expand Up @@ -50,26 +45,13 @@ func async_load_gltf():
printerr("Error on fetch gltf: ", res_instance.get_error())
return

self.async_deferred_add_child.call_deferred(res_instance)


func _async_on_gltf_loaded():
var node = Global.content_provider.get_gltf_from_hash(file_hash)
if node == null:
dcl_gltf_loading_state = GltfContainerLoadingState.FINISHED_WITH_ERROR
return

var promise: Promise = Global.content_provider.instance_gltf_colliders(
node, dcl_visible_cmask, dcl_invisible_cmask, dcl_scene_id, dcl_entity_id
)

await PromiseUtils.async_awaiter(promise)
dcl_pending_node = res_instance

gltf_node = promise.get_data()
self.async_deferred_add_child.call_deferred(gltf_node)

func async_deferred_add_child():
var new_gltf_node = dcl_pending_node
dcl_pending_node = null

func async_deferred_add_child(new_gltf_node):
# Corner case, when the scene is unloaded before the gltf is loaded
if not is_inside_tree():
dcl_gltf_loading_state = GltfContainerLoadingState.FINISHED_WITH_ERROR
Expand Down Expand Up @@ -127,10 +109,10 @@ func change_gltf(new_gltf, visible_meshes_collision_mask, invisible_meshes_colli
dcl_visible_cmask = visible_meshes_collision_mask
dcl_invisible_cmask = invisible_meshes_collision_mask

if gltf_node != null:
if get_child_count() > 0:
var gltf_node = get_child(0)
remove_child(gltf_node)
gltf_node.queue_free()
gltf_node = null

self.async_load_gltf.call_deferred()
else:
Expand All @@ -139,8 +121,8 @@ func change_gltf(new_gltf, visible_meshes_collision_mask, invisible_meshes_colli
visible_meshes_collision_mask != dcl_visible_cmask
or invisible_meshes_collision_mask != dcl_invisible_cmask
)
and gltf_node != null
and get_child_count() > 0
):
dcl_visible_cmask = visible_meshes_collision_mask
dcl_invisible_cmask = invisible_meshes_collision_mask
update_mask_colliders(gltf_node)
update_mask_colliders(get_child(0))
19 changes: 17 additions & 2 deletions rust/decentraland-godot-lib/src/dcl/crdt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,22 @@ pub struct SceneCrdtState {
pub entities: SceneEntityContainer,
}

pub type DirtyLwwComponents = HashMap<SceneComponentId, HashSet<SceneEntityId>>;
pub trait InsertIfNotExists<T> {
fn insert_if_not_exists(&mut self, value: T) -> bool;
}

impl<T: PartialEq> InsertIfNotExists<T> for Vec<T> {
fn insert_if_not_exists(&mut self, value: T) -> bool {
if !self.contains(&value) {
self.push(value);
true
} else {
false
}
}
}

pub type DirtyLwwComponents = HashMap<SceneComponentId, Vec<SceneEntityId>>;
pub type DirtyGosComponents = HashMap<SceneComponentId, HashMap<SceneEntityId, usize>>;

// message from scene-thread describing new and deleted entities
Expand Down Expand Up @@ -221,7 +236,7 @@ impl SceneCrdtState {
}

if !dirty.is_empty() {
dirty_lww_components.insert(*component_id, dirty);
dirty_lww_components.insert(*component_id, dirty.into_iter().collect());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ pub struct DclGltfContainer {
#[export(enum = (Unknown, Loading, NotFound, FinishedWithError, Finished))]
dcl_gltf_loading_state: GltfContainerLoadingState,

#[export]
dcl_pending_node: Option<Gd<Node>>,

#[base]
base: Base<Node3D>,
}
Expand Down Expand Up @@ -151,6 +154,7 @@ impl INode for DclGltfContainer {
dcl_invisible_cmask: 3,
dcl_entity_id: SceneEntityId::INVALID.as_i32(),
dcl_gltf_loading_state: GltfContainerLoadingState::Unknown,
dcl_pending_node: None,
base,
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::time::Instant;

use crate::{
dcl::{
components::SceneComponentId,
Expand All @@ -11,15 +13,25 @@ use crate::{
};
use godot::prelude::*;

pub fn update_gltf_container(scene: &mut Scene, crdt_state: &mut SceneCrdtState) {
pub fn update_gltf_container(
scene: &mut Scene,
crdt_state: &mut SceneCrdtState,
ref_time: &Instant,
end_time_us: i64,
) -> bool {
let mut updated_count = 0;
let mut current_time_us;

let godot_dcl_scene = &mut scene.godot_dcl_scene;
let dirty_lww_components = &scene.current_dirty.lww_components;
let gltf_container_dirty = scene
.current_dirty
.lww_components
.remove(&SceneComponentId::GLTF_CONTAINER);
let scene_id = scene.scene_id.0;
let gltf_container_component = SceneCrdtStateProtoComponents::get_gltf_container(crdt_state);

if let Some(gltf_container_dirty) = dirty_lww_components.get(&SceneComponentId::GLTF_CONTAINER)
{
for entity in gltf_container_dirty {
if let Some(mut gltf_container_dirty) = gltf_container_dirty {
for entity in gltf_container_dirty.iter() {
let new_value = gltf_container_component.get(entity);
if new_value.is_none() {
continue;
Expand All @@ -43,46 +55,66 @@ pub fn update_gltf_container(scene: &mut Scene, crdt_state: &mut SceneCrdtState)
new_value.invisible_meshes_collision_mask.unwrap_or(3) as i32;

if let Some(mut gltf_node) = existing {
gltf_node.call_deferred(
StringName::from(GString::from("change_gltf")),
gltf_node.call(
"change_gltf".into(),
&[
Variant::from(GString::from(new_value.src)),
Variant::from(visible_meshes_collision_mask),
Variant::from(invisible_meshes_collision_mask),
new_value.src.to_variant(),
visible_meshes_collision_mask.to_variant(),
invisible_meshes_collision_mask.to_variant(),
],
);
scene.gltf_loading.insert(*entity);
} else {
// TODO: preload this resource
let mut new_gltf = godot::engine::load::<PackedScene>(
"res://src/decentraland_components/gltf_container.tscn",
)
.instantiate()
.unwrap()
.cast::<DclGltfContainer>();

new_gltf
.bind_mut()
.set_dcl_gltf_src(GString::from(new_value.src));
new_gltf.bind_mut().set_dcl_scene_id(scene_id);
new_gltf.bind_mut().set_dcl_entity_id(entity.as_i32());
new_gltf
.bind_mut()
.set_dcl_visible_cmask(visible_meshes_collision_mask);
new_gltf
.bind_mut()
.set_dcl_invisible_cmask(invisible_meshes_collision_mask);
let mut new_gltf_ref = new_gltf.bind_mut();
new_gltf_ref.set_dcl_gltf_src(GString::from(new_value.src));
new_gltf_ref.set_dcl_scene_id(scene_id);
new_gltf_ref.set_dcl_entity_id(entity.as_i32());
new_gltf_ref.set_dcl_visible_cmask(visible_meshes_collision_mask);
new_gltf_ref.set_dcl_invisible_cmask(invisible_meshes_collision_mask);
drop(new_gltf_ref);

new_gltf.set_name(GString::from("GltfContainer"));
node_3d.add_child(new_gltf.clone().upcast());

scene.gltf_loading.insert(*entity);
}
}

updated_count += 1;
current_time_us = (std::time::Instant::now() - *ref_time).as_micros() as i64;
if current_time_us > end_time_us {
break;
}
}

if updated_count < gltf_container_dirty.len() {
gltf_container_dirty.drain(0..updated_count);
scene
.current_dirty
.lww_components
.insert(SceneComponentId::GLTF_CONTAINER, gltf_container_dirty);
return false;
}
}

true
}

pub fn sync_gltf_loading_state(scene: &mut Scene, crdt_state: &mut SceneCrdtState) {
pub fn sync_gltf_loading_state(
scene: &mut Scene,
crdt_state: &mut SceneCrdtState,
ref_time: &Instant,
end_time_us: i64,
) -> bool {
let mut current_time_us;
let godot_dcl_scene = &mut scene.godot_dcl_scene;
let gltf_container_loading_state_component =
SceneCrdtStateProtoComponents::get_gltf_container_loading_state_mut(crdt_state);
Expand All @@ -93,6 +125,12 @@ pub fn sync_gltf_loading_state(scene: &mut Scene, crdt_state: &mut SceneCrdtStat
.1
.try_get_node_as::<DclGltfContainer>(NodePath::from("GltfContainer"));

if let Some(mut gltf_node) = gltf_node.clone() {
if gltf_node.bind().get_dcl_pending_node().is_some() {
gltf_node.call("async_deferred_add_child".into(), &[]);
}
}

let current_state = match gltf_container_loading_state_component.get(entity) {
Some(state) => match state.value.as_ref() {
Some(value) => GltfContainerLoadingState::from_proto(value.current_state()),
Expand All @@ -118,5 +156,12 @@ pub fn sync_gltf_loading_state(scene: &mut Scene, crdt_state: &mut SceneCrdtStat
{
scene.gltf_loading.remove(entity);
}

current_time_us = (std::time::Instant::now() - *ref_time).as_micros() as i64;
if current_time_us > end_time_us {
return false;
}
}

true
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::time::Instant;

use crate::{
dcl::{
components::{
Expand Down Expand Up @@ -63,13 +65,24 @@ pub fn create_or_update_mesh(mesh_instance: &mut Gd<MeshInstance3D>, mesh: &PbMe
}
}

pub fn update_mesh_renderer(scene: &mut Scene, crdt_state: &mut SceneCrdtState) {
pub fn update_mesh_renderer(
scene: &mut Scene,
crdt_state: &mut SceneCrdtState,
ref_time: &Instant,
end_time_us: i64,
) -> bool {
let mut updated_count = 0;
let mut current_time_us;
let godot_dcl_scene = &mut scene.godot_dcl_scene;
let dirty_lww_components = &scene.current_dirty.lww_components;
if let Some(mesh_renderer_dirty) = dirty_lww_components.get(&SceneComponentId::MESH_RENDERER) {
let mesh_renderer_dirty = scene
.current_dirty
.lww_components
.remove(&SceneComponentId::MESH_RENDERER);

if let Some(mut mesh_renderer_dirty) = mesh_renderer_dirty {
let mesh_renderer_component = SceneCrdtStateProtoComponents::get_mesh_renderer(crdt_state);

for entity in mesh_renderer_dirty {
for entity in mesh_renderer_dirty.iter() {
let new_value = mesh_renderer_component.get(entity);
if new_value.is_none() {
continue;
Expand Down Expand Up @@ -107,6 +120,22 @@ pub fn update_mesh_renderer(scene: &mut Scene, crdt_state: &mut SceneCrdtState)
node_3d.add_child(mesh_instance_3d.upcast());
}
}
updated_count += 1;
current_time_us = (std::time::Instant::now() - *ref_time).as_micros() as i64;
if current_time_us > end_time_us {
break;
}
}

if updated_count < mesh_renderer_dirty.len() {
mesh_renderer_dirty.drain(0..updated_count);
scene
.current_dirty
.lww_components
.insert(SceneComponentId::MESH_RENDERER, mesh_renderer_dirty);
return false;
}
}

true
}
Loading

0 comments on commit c249172

Please sign in to comment.