Per docs/zh/plans/render-pipeline-threads.md §3.8: - oak-node/nodes/graphendpoints.rs: the GraphInput/GraphOutput virtual node pair — factory-registered but hidden from every create menu, duplicate refused, real value() semantics (the input forwards its feed_in row, the output publishes its tex_in as the frame). The input endpoint also declares a connectable feed_in port (documented deviation: footage/generator sources have no connectable inputs, so the walk needs a feeder anchor). - graph.rs: ensure_endpoints/endpoints/is_endpoint — idempotent, identified by type id, default input->output edge only while the output's tex_in is free; remove_node refuses endpoints. - project.rs + serializer.rs: every project graph carries the pair; a legacy file without endpoints migrates on load (roundtrip and legacy-migration tests, re-save is idempotent). - traverser.rs: eval_graph_bfs — the endpoint-to-endpoint Kahn sweep. Live set = (input's forward cone U its feeder cone) INTERSECT (output's backward cone); multi-input nodes dequeue at zero in-degree over the live subgraph; deterministic ascending-id ready order (Graph::edges is a BTreeSet, so insertion order is unrecoverable — documented); time-shifted upstreams pull through the shared DFS memo (walk_dfs, factored out of evaluate); un-orderable remainder reports a named cycle; missing endpoints / unreachable output are errors. Eight BFS tests cover the plan's acceptance bullets. - oak-render: bfs_endpoint_sweep_renders_footage_through_position — real clip through a real Position node via the sweep, shifted pixels asserted against a reference decode. - Endpoint names localized in all eight i18n packs; storage/structure tests updated for the two extra nodes.
146 lines
5.6 KiB
Rust
146 lines
5.6 KiB
Rust
// Oak Video Editor - Non-Linear Video Editor
|
|
// Copyright (C) 2026 Oak Team
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//! Built-in node registration smoke tests: `nodes::register_all()`
|
|
//! builds the factory entry table in C++ registration order
|
|
//! (`factory.cpp::create_from_factory_index` — the switch order, NOT
|
|
//! the `factory.h` InternalID enum order: `initialize()` iterates the
|
|
//! enum indices but the switch reorders log/white-balance after
|
|
//! linear, and tile/swirl/ripple after wave).
|
|
|
|
use oak_node::factory::Factory;
|
|
use oak_node::node::Category;
|
|
|
|
/// Expected `type_id` sequence, in C++ registration order
|
|
/// (`factory.cpp::create_from_factory_index`; the plugin nodes that
|
|
/// follow are registered at runtime by the oakplugin bridge and are not
|
|
/// part of this table).
|
|
const EXPECTED_ORDER: &[&str] = &[
|
|
"org.olivevideoeditor.Olive.polygon",
|
|
"org.olivevideoeditor.Olive.ortho",
|
|
"org.olivevideoeditor.Olive.transform",
|
|
"org.olivevideoeditor.Olive.volume",
|
|
"org.olivevideoeditor.Olive.pan",
|
|
"org.olivevideoeditor.Olive.math",
|
|
"org.olivevideoeditor.Olive.time",
|
|
"org.olivevideoeditor.Olive.trigonometry",
|
|
"org.olivevideoeditor.Olive.blur",
|
|
"org.olivevideoeditor.Olive.solidgenerator",
|
|
"org.olivevideoeditor.Olive.merge",
|
|
"org.olivevideoeditor.Olive.stroke",
|
|
"org.olivevideoeditor.Olive.textgenerator",
|
|
"org.olivevideoeditor.Olive.text2",
|
|
"org.olivevideoeditor.Olive.text3",
|
|
"org.olivevideoeditor.Olive.mosaicfilter",
|
|
"org.olivevideoeditor.Olive.crop",
|
|
"org.olivevideoeditor.Olive.value",
|
|
"org.olivevideoeditor.Olive.timeremap",
|
|
"org.olivevideoeditor.Olive.shape",
|
|
"org.olivevideoeditor.Olive.colordifferencekey",
|
|
"org.olivevideoeditor.Olive.despill",
|
|
"org.olivevideoeditor.Olive.group",
|
|
"org.olivevideoeditor.Olive.opacity",
|
|
"org.olivevideoeditor.Olive.flip",
|
|
"org.olivevideoeditor.Olive.noise",
|
|
"org.olivevideoeditor.Olive.timeoffset",
|
|
"org.olivevideoeditor.Olive.transition",
|
|
"org.olivevideoeditor.Olive.transitionfx",
|
|
"org.olivevideoeditor.Olive.cornerpin",
|
|
"org.olivevideoeditor.Olive.displaytransform",
|
|
"org.olivevideoeditor.Olive.ociogradingtransformlinear",
|
|
"org.olivevideoeditor.Olive.OCIO_NAMESPACEgradingtransformlog",
|
|
"org.olivevideoeditor.Olive.whitebalance",
|
|
"org.olivevideoeditor.Olive.ociolut",
|
|
"org.olivevideoeditor.Olive.threewaycolor",
|
|
"org.olivevideoeditor.Olive.chromakey",
|
|
"org.olivevideoeditor.Olive.mask",
|
|
"org.olivevideoeditor.Olive.dropshadow",
|
|
"org.olivevideoeditor.Olive.timeformat",
|
|
"org.olivevideoeditor.Olive.wave",
|
|
"org.olivevideoeditor.Olive.tile",
|
|
"org.olivevideoeditor.Olive.swirl",
|
|
"org.olivevideoeditor.Olive.ripple",
|
|
"org.olivevideoeditor.Olive.colormatrix",
|
|
"org.olivevideoeditor.Olive.dilate",
|
|
"org.olivevideoeditor.Olive.edgedetect",
|
|
"org.olivevideoeditor.Olive.erode",
|
|
// The OpenFX-Misc cleanroom GPU ports, registered between the C++
|
|
// menu order and multicam (see `nodes::register_all`).
|
|
"org.olivevideoeditor.Olive.colorcorrect",
|
|
"org.olivevideoeditor.Olive.gamma",
|
|
"org.olivevideoeditor.Olive.saturation",
|
|
"org.olivevideoeditor.Olive.invert",
|
|
"org.olivevideoeditor.Olive.clamp",
|
|
"org.olivevideoeditor.Olive.grade",
|
|
"org.olivevideoeditor.Olive.dirblur",
|
|
"org.olivevideoeditor.Olive.sharpen",
|
|
"org.olivevideoeditor.Olive.dissolve",
|
|
"org.olivevideoeditor.Olive.keymix",
|
|
"org.olivevideoeditor.Olive.premult",
|
|
"org.olivevideoeditor.Olive.unpremult",
|
|
"org.olivevideoeditor.Olive.position",
|
|
"org.olivevideoeditor.Olive.mirror",
|
|
"org.olivevideoeditor.Olive.checkerboard",
|
|
"org.olivevideoeditor.Olive.colorbars",
|
|
"org.olivevideoeditor.Olive.ramp",
|
|
"org.olivevideoeditor.Olive.multicam",
|
|
// Oak-only virtual graph endpoints (no C++ counterpart; appended
|
|
// after the C++ menu order by `nodes::register_all`, hidden from
|
|
// every create menu).
|
|
"org.olivevideoeditor.Olive.graphinput",
|
|
"org.olivevideoeditor.Olive.graphoutput",
|
|
];
|
|
|
|
/// `register_all()` installs every built-in node, exactly once, in C++
|
|
/// factory order.
|
|
#[test]
|
|
fn registered_entries_match_cpp_order() {
|
|
let entries = Factory::global().entries();
|
|
assert_eq!(entries.len(), EXPECTED_ORDER.len());
|
|
for (i, (entry, expected)) in entries.iter().zip(EXPECTED_ORDER.iter()).enumerate() {
|
|
assert_eq!(entry.type_id, *expected, "mismatch at entry {i}");
|
|
}
|
|
}
|
|
|
|
/// First entry is polygon; the last is the Oak-only graph-output endpoint
|
|
/// (multi-cam is the last C++ built-in in `factory.cpp` switch order, but
|
|
/// the endpoint pair is appended after it).
|
|
#[test]
|
|
fn first_and_last_entries() {
|
|
let entries = Factory::global().entries();
|
|
assert_eq!(
|
|
entries.first().unwrap().type_id,
|
|
"org.olivevideoeditor.Olive.polygon"
|
|
);
|
|
assert_eq!(entries.first().unwrap().name, "Polygon");
|
|
assert_eq!(
|
|
entries.last().unwrap().type_id,
|
|
"org.olivevideoeditor.Olive.graphoutput"
|
|
);
|
|
assert_eq!(entries.last().unwrap().name, "Graph Output");
|
|
}
|
|
|
|
/// `find()` resolves a type id to its metadata (pan, index 4 in the
|
|
/// table).
|
|
#[test]
|
|
fn find_pan_entry() {
|
|
let meta = Factory::global()
|
|
.find("org.olivevideoeditor.Olive.pan")
|
|
.expect("pan is a built-in node");
|
|
assert_eq!(meta.name, "Pan");
|
|
assert_eq!(meta.categories, &[Category::Filter]);
|
|
}
|