summaryrefslogtreecommitdiff
path: root/src/tests/gpu/test_sequence_v2.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/gpu/test_sequence_v2.cc')
-rw-r--r--src/tests/gpu/test_sequence_v2.cc184
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;
+}