package video import ( "errors" "fmt" "log" "mxl-pattern-generator/internal/generator" ) type generatorFactory func() (generator.FrameGenerator, error) func newFrameGenerator(cfg Config, pattern pattern) (generator.FrameGenerator, Backend, error) { newGPU := func() (generator.FrameGenerator, error) { return generator.NewWGPUGenerator(cfg.Width(), cfg.Height(), pattern.kernelSource) } newCPU := func() (generator.FrameGenerator, error) { return generator.NewCPUPatternGenerator(cfg.Width(), cfg.Height(), cfg.Pattern) } fill, backend, err := selectFrameGenerator(cfg.Backend, newGPU, newCPU) if err != nil { return nil, "", err } gen, err := wrapAlphaGenerator(cfg, fill, pattern.dynamic) if err != nil { return nil, "", err } return gen, backend, nil } func wrapAlphaGenerator( cfg Config, fill generator.FrameGenerator, fillDynamic bool, ) (generator.FrameGenerator, error) { if !cfg.HasAlpha() { return fill, nil } gen, err := generator.NewV210AGenerator(fill, cfg.Width(), cfg.Height(), fillDynamic) if err != nil { closeErr := fill.Close() return nil, errors.Join( fmt.Errorf("initialize v210a generator: %w", err), closeErr, ) } return gen, nil } func selectFrameGenerator( backend Backend, newGPU, newCPU generatorFactory, ) (generator.FrameGenerator, Backend, error) { switch backend { case BackendGPU: gen, err := newGPU() if err != nil { return nil, "", fmt.Errorf("initialize GPU video generator: %w", err) } return gen, BackendGPU, nil case BackendCPU: gen, err := newCPU() if err != nil { return nil, "", fmt.Errorf("initialize CPU video generator: %w", err) } return gen, BackendCPU, nil case "", BackendAuto: gpuGen, gpuErr := newGPU() if gpuErr == nil { return gpuGen, BackendGPU, nil } log.Printf("GPU video generator unavailable, falling back to CPU: %v", gpuErr) cpuGen, cpuErr := newCPU() if cpuErr == nil { return cpuGen, BackendCPU, nil } return nil, "", errors.Join( fmt.Errorf("initialize GPU video generator: %w", gpuErr), fmt.Errorf("initialize CPU video generator: %w", cpuErr), ) default: return nil, "", fmt.Errorf("unsupported video backend %q", backend) } }