diff options
Diffstat (limited to 'src/tests/gpu/test_sequence.cc')
| -rw-r--r-- | src/tests/gpu/test_sequence.cc | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/tests/gpu/test_sequence.cc b/src/tests/gpu/test_sequence.cc new file mode 100644 index 0000000..337381a --- /dev/null +++ b/src/tests/gpu/test_sequence.cc @@ -0,0 +1,184 @@ +// Test file for Sequence v2 system +// Phase 1: Foundation tests (NodeRegistry, Sequence base class) + +#include "gpu/sequence.h" +#include "gpu/effect.h" +#include "tests/common/webgpu_test_fixture.h" +#include <cassert> +#include <cstdio> + +// Simple test effect for DAG execution +class TestEffect : public Effect { + public: + TestEffect(const GpuContext& ctx, const std::vector<std::string>& inputs, + const std::vector<std::string>& outputs) + : Effect(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: Sequence default preprocess +void test_sequence_v2_preprocess() { + WebGPUTestFixture fixture; + if (!fixture.init()) { + fprintf(stderr, "Skipping test_sequence_v2_preprocess (no GPU)\n"); + return; + } + + Sequence 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: Sequence preprocess\n"); +} + +// Test: Sequence 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 Sequence { + public: + TestSequence(const GpuContext& ctx) + : Sequence(ctx, 1280, 720), + effect1_(std::make_shared<TestEffect>(ctx, std::vector<std::string>{"source"}, + std::vector<std::string>{"temp"})), + effect2_(std::make_shared<TestEffect>(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<TestEffect> effect1_; + std::shared_ptr<TestEffect> 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: Sequence 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; +} |
