Skip to content

Commit

Permalink
scene: Extrace dependency resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
pragmatrix committed Jul 2, 2024
1 parent c53c4f6 commit 9a65c83
Showing 1 changed file with 3 additions and 85 deletions.
88 changes: 3 additions & 85 deletions renderer/src/scene/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use std::{cell::RefCell, collections::HashMap};

use euclid::num::Zero;

use dependency_resolver::{resolve, DependencyResolver};
use id_table::IdTable;
use massive_geometry::Matrix4;
use massive_scene::{Change, Id, PositionRenderObj, PositionedRenderShape, SceneChange, Shape};
use versioning::{Computed, Version, Versioned};

mod dependency_resolver;
mod id_table;
mod versioning;

Expand Down Expand Up @@ -81,91 +84,6 @@ impl Scene {
}
}

/// Resolve a computed value.
///
/// Invoking this function ensures that the computed value `id` is up to date with its dependencies
/// at `head_version`.
///
/// We don't return a reference to the result here, because the borrow checker would make this
/// recursive function invocation unnecessarily more complex.
///
/// TODO: Unrecurse this. There might be degenerate cases of large dependency chains.
fn resolve<Resolver: DependencyResolver>(
head_version: Version,
shared_storage: &Resolver::SharedStorage,
caches: &mut Resolver::ComputedStorage,
id: Id,
) where
Computed<Resolver::Computed>: Default,
{
// Already validated at the latest version? Done.
//
// `get_or_default` must be used here. This is the only situation in which the cache may
// need to be resized.
let computed = Resolver::computed_mut(caches, id);
if computed.validated_at == head_version {
return;
}
// Save the current max dependencies version for later.
//
// In theory this could be overwritten if there are cycles in the dependency graph, but in
// practice they are not (and everything may blow up anyway).
let computed_max_deps = computed.max_deps_version;

let source = Resolver::source(shared_storage, id);
let max_deps_version =
Resolver::resolve_dependencies(head_version, source, shared_storage, caches);

// If the max_deps_version is smaller or equal to the current one, the value is ok and can
// be marked as validated at `head_version`.
if max_deps_version <= computed_max_deps {
Resolver::computed_mut(caches, id).validated_at = head_version;
return;
}

// Compute a new value and store it.
let new_value = Resolver::compute(shared_storage, caches, source);
*Resolver::computed_mut(caches, id) = Computed {
validated_at: head_version,
max_deps_version,
value: new_value,
};
}

trait DependencyResolver {
/// Type of the shared table storage.
type SharedStorage;
/// Type of the computed table storage.
type ComputedStorage;

/// The symmetric _versioned_ source value type. There must be a source value for every computed
/// value with the same id.
type Source;
/// The computed value type (must implement Default for now, use Option<> otherwise)
type Computed;

/// Retrieve a reference to the versioned source value.
fn source(scene: &Self::SharedStorage, id: Id) -> &Versioned<Self::Source>;

/// Make sure that all dependencies are up to date and return their maximum version.
fn resolve_dependencies(
head_version: Version,
source: &Versioned<Self::Source>,
shared: &Self::SharedStorage,
computed: &mut Self::ComputedStorage,
) -> Version;

fn compute(
shared: &Self::SharedStorage,
computed: &Self::ComputedStorage,
source: &Self::Source,
) -> Self::Computed;

fn computed_mut(computed: &mut Self::ComputedStorage, id: Id) -> &mut Computed<Self::Computed>
where
Computed<Self::Computed>: Default;
}

/// The dependency resolver for finally positioned matrix.
struct PositionedMatrix;

Expand Down

0 comments on commit 9a65c83

Please sign in to comment.