diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-16 08:26:45 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-16 08:26:45 +0100 |
| commit | 9d1d4df877f96f1970dce2ab30cfae49d3d796e1 (patch) | |
| tree | 681298bc46a58890f2b5581c16a05a4272ef4ed3 /src/tests | |
| parent | 7947a1230e526eb17ca0252f81d19c18811bd355 (diff) | |
feat(sequence): Phase 1 - Sequence v2 foundation
- Add Node system with typed buffers (u8x4_norm, f32x4, f16x8, depth24)
- Add NodeRegistry with aliasing support for ping-pong optimization
- Add SequenceV2 base class with DAG execution
- Add EffectV2 base class with multi-input/multi-output
- Add comprehensive tests (5 test cases, all passing)
- Corrected FATAL_CHECK usage (checks ERROR conditions, not success)
Phase 1 complete: Core v2 architecture functional.
Next: Phase 2 compiler (seq_compiler_v2.py)
handoff(Claude): Phase 1 foundation complete, all tests passing (35/35)
Diffstat (limited to 'src/tests')
| -rw-r--r-- | src/tests/gpu/test_sequence_v2.cc | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/tests/gpu/test_sequence_v2.cc b/src/tests/gpu/test_sequence_v2.cc new file mode 100644 index 0000000..54b544e --- /dev/null +++ b/src/tests/gpu/test_sequence_v2.cc @@ -0,0 +1,184 @@ +// Test file for Sequence v2 system +// Phase 1: Foundation tests (NodeRegistry, SequenceV2 base class) + +#include "gpu/sequence_v2.h" +#include "gpu/effect_v2.h" +#include "tests/common/webgpu_test_fixture.h" +#include <cassert> +#include <cstdio> + +// Simple test effect for DAG execution +class TestEffectV2 : public EffectV2 { + public: + TestEffectV2(const GpuContext& ctx, const std::vector<std::string>& inputs, + const std::vector<std::string>& outputs) + : EffectV2(ctx, inputs, outputs), render_called_(false) { + } + + void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, + NodeRegistry& nodes) override { + (void)encoder; + (void)params; + (void)nodes; + render_called_ = true; + } + + bool was_render_called() const { + return render_called_; + } + + private: + bool render_called_; +}; + +// Test: NodeRegistry basic allocation +void test_node_registry_basic() { + WebGPUTestFixture fixture; + if (!fixture.init()) { + fprintf(stderr, "Skipping test_node_registry_basic (no GPU)\n"); + return; + } + + NodeRegistry registry(fixture.ctx().device, 1280, 720); + + // Declare node + registry.declare_node("test_node", NodeType::U8X4_NORM, 1280, 720); + + // Verify node exists + assert(registry.has_node("test_node")); + + // Get view (should not crash) + WGPUTextureView view = registry.get_view("test_node"); + assert(view != nullptr); + + printf("PASS: NodeRegistry basic allocation\n"); +} + +// Test: NodeRegistry aliased nodes (ping-pong optimization) +void test_node_registry_aliased() { + WebGPUTestFixture fixture; + if (!fixture.init()) { + fprintf(stderr, "Skipping test_node_registry_aliased (no GPU)\n"); + return; + } + + NodeRegistry registry(fixture.ctx().device, 1280, 720); + + // Declare backing node + registry.declare_node("frame_a", NodeType::U8X4_NORM, 1280, 720); + + // Declare aliased node + registry.declare_aliased_node("frame_b", "frame_a"); + + // Both should resolve to same view + WGPUTextureView view_a = registry.get_view("frame_a"); + WGPUTextureView view_b = registry.get_view("frame_b"); + assert(view_a == view_b); + + printf("PASS: NodeRegistry aliased nodes\n"); +} + +// Test: NodeRegistry multi-output views +void test_node_registry_multi_output() { + WebGPUTestFixture fixture; + if (!fixture.init()) { + fprintf(stderr, "Skipping test_node_registry_multi_output (no GPU)\n"); + return; + } + + NodeRegistry registry(fixture.ctx().device, 1280, 720); + + // Declare multiple nodes + registry.declare_node("output1", NodeType::U8X4_NORM, 1280, 720); + registry.declare_node("output2", NodeType::F32X4, 1280, 720); + + // Get multiple views + std::vector<std::string> names = {"output1", "output2"}; + std::vector<WGPUTextureView> views = registry.get_output_views(names); + + assert(views.size() == 2); + assert(views[0] != nullptr); + assert(views[1] != nullptr); + + printf("PASS: NodeRegistry multi-output views\n"); +} + +// Test: SequenceV2 default preprocess +void test_sequence_v2_preprocess() { + WebGPUTestFixture fixture; + if (!fixture.init()) { + fprintf(stderr, "Skipping test_sequence_v2_preprocess (no GPU)\n"); + return; + } + + SequenceV2 seq(fixture.ctx(), 1280, 720); + + // Call preprocess with test values + seq.preprocess(1.0f, 4.0f, 0.5f, 0.8f); + + // No crash = success (params updated internally) + printf("PASS: SequenceV2 preprocess\n"); +} + +// Test: SequenceV2 DAG execution +void test_sequence_v2_dag_execution() { + WebGPUTestFixture fixture; + if (!fixture.init()) { + fprintf(stderr, "Skipping test_sequence_v2_dag_execution (no GPU)\n"); + return; + } + + // Create sequence + class TestSequence : public SequenceV2 { + public: + TestSequence(const GpuContext& ctx) + : SequenceV2(ctx, 1280, 720), + effect1_(std::make_shared<TestEffectV2>(ctx, std::vector<std::string>{"source"}, + std::vector<std::string>{"temp"})), + effect2_(std::make_shared<TestEffectV2>(ctx, std::vector<std::string>{"temp"}, + std::vector<std::string>{"sink"})) { + // Build DAG (2 effects in sequence) + effect_dag_.push_back( + {effect1_, {"source"}, {"temp"}, 0}); + effect_dag_.push_back( + {effect2_, {"temp"}, {"sink"}, 1}); + } + + std::shared_ptr<TestEffectV2> effect1_; + std::shared_ptr<TestEffectV2> effect2_; + }; + + TestSequence seq(fixture.ctx()); + + // Create command encoder + WGPUCommandEncoderDescriptor enc_desc = {}; + WGPUCommandEncoder encoder = + wgpuDeviceCreateCommandEncoder(fixture.ctx().device, &enc_desc); + + // Execute DAG + seq.render_effects(encoder); + + // Verify both effects called + assert(seq.effect1_->was_render_called()); + assert(seq.effect2_->was_render_called()); + + // Cleanup + WGPUCommandBuffer cmd = wgpuCommandEncoderFinish(encoder, nullptr); + wgpuCommandBufferRelease(cmd); + wgpuCommandEncoderRelease(encoder); + + printf("PASS: SequenceV2 DAG execution\n"); +} + +int main() { + printf("Running Sequence v2 tests...\n"); + + test_node_registry_basic(); + test_node_registry_aliased(); + test_node_registry_multi_output(); + test_sequence_v2_preprocess(); + test_sequence_v2_dag_execution(); + + printf("All Sequence v2 tests passed!\n"); + return 0; +} |
