minigpu 1.2.1 copy "minigpu: ^1.2.1" to clipboard
minigpu: ^1.2.1 copied to clipboard

A library that brings multiplatform GPU compute to Dart and Flutter by wrapping the gpu.cpp library and webgpu with a Dawn backend.

example/lib/main.dart

import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:minigpu/minigpu.dart';
import 'package:url_launcher/url_launcher.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Minigpu Type Testing Lab',
      theme: ThemeData.dark().copyWith(
        primaryColor: const Color(0xFF00FFFF), // Electric cyan
        colorScheme: const ColorScheme.dark(
          primary: Color(0xFF00FFFF),
          secondary: Color(0xFF0080FF),
          surface: Color(0xFF1A1A2E),
        ),
        cardColor: const Color(0xFF1A1A2E),
        appBarTheme: const AppBarTheme(
          backgroundColor: Color(0xFF0F0F23),
          foregroundColor: Color(0xFF00FFFF),
        ),
      ),
      home: const TypeTestingExample(),
    );
  }
}

enum DataTypeDemo {
  int8('Int8', BufferDataType.int8, -128, 127),
  uint8('Uint8', BufferDataType.uint8, 0, 255),
  int16('Int16', BufferDataType.int16, -32768, 32767),
  uint16('Uint16', BufferDataType.uint16, 0, 65535),
  int32('Int32', BufferDataType.int32, -2147483648, 2147483647),
  uint32('Uint32', BufferDataType.uint32, 0, 4294967295),
  float32('Float32', BufferDataType.float32, -1000.0, 1000.0),
  float64('Float64', BufferDataType.float64, -1000.0, 1000.0);

  const DataTypeDemo(this.label, this.type, this.minValue, this.maxValue);

  final String label;
  final BufferDataType type;
  final double minValue;
  final double maxValue;
}

enum AlgorithmDemo {
  wave('Wave Generator'),
  pulse('Pulse Wave'),
  spiral('Spiral Pattern'),
  interference('Wave Interference'),
  cellular('Cellular Automata'),
  noise('Perlin-like Noise'),
  mandelbrot('Mandelbrot Set'),
  flow('Flow Field'),
  // New enlightened patterns
  phi('Phi Wave (Golden Ratio)'),
  unity('Unity Field Generator'),
  kundalini('Kundalini Rising'),
  theta('Theta Wave DMT'),
  om('Cosmic Om Resonance'),
  merkaba('Merkaba Activation'),
  coherence('Heart Coherence'),
  gratitude('Gratitude Frequency'),
  schumann('Schumann Resonance'),
  fibonacci('Fibonacci Spiral');

  const AlgorithmDemo(this.label);
  final String label;
}

class TypeTestingExample extends StatefulWidget {
  const TypeTestingExample({super.key});
  @override
  TypeTestingExampleState createState() => TypeTestingExampleState();
}

class TypeTestingExampleState extends State<TypeTestingExample>
    with TickerProviderStateMixin {
  late Minigpu _minigpu;
  late ComputeShader _shader;
  Buffer? _inputBuffer;
  Buffer? _outputBuffer;
  late TabController _tabController;

  // Animation controllers
  late AnimationController _waveController;
  late AnimationController _colorController;

  // State
  DataTypeDemo _currentType = DataTypeDemo.float32;
  AlgorithmDemo _currentAlgorithm = AlgorithmDemo.schumann;
  int _bufferSize = 4096;
  int _previewLength = 1024;
  bool _autoMode = true;
  double _animationSpeed = 250.0;

  List<double> _fullInputData = [];
  List<double> _fullOutputData = [];
  List<double> _lastData = [];

  // Performance metrics
  int _operationsPerSecond = 0;
  int _totalOperations = 0;
  DateTime _lastOpTime = DateTime.now();

  List<double> get _previewInputData {
    if (_fullInputData.isEmpty) return [];
    return _fullInputData
        .take(_previewLength)
        .where((value) => value.isFinite)
        .toList();
  }

  List<double> get _previewOutputData {
    if (_fullOutputData.isEmpty) return [];
    return _fullOutputData
        .take(_previewLength)
        .where((value) => value.isFinite)
        .toList();
  }

  List<double> get _previewLastData {
    if (_lastData.isEmpty) return [];
    return _lastData
        .take(_previewLength)
        .where((value) => value.isFinite)
        .toList();
  }

  @override
  void initState() {
    super.initState();
    _minigpu = Minigpu();
    _tabController = TabController(length: 2, vsync: this);

    _waveController = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat();

    _colorController = AnimationController(
      duration: const Duration(seconds: 3),
      vsync: this,
    )..repeat();

    _initMinigpu();
  }

  Future<void> _initMinigpu() async {
    await _minigpu.init();
    _createBuffers();
    _generateInputData();
    _shader = _minigpu.createComputeShader();
    _runKernel();
  }

  void _createBuffers() {
    int memSize = getBufferSizeForType(_currentType.type, _bufferSize);

    _inputBuffer?.destroy();
    _outputBuffer?.destroy();
    _inputBuffer = _minigpu.createBuffer(memSize, _currentType.type);
    _outputBuffer = _minigpu.createBuffer(memSize, _currentType.type);
  }

  void _generateInputData() {
    List<double> data;
    double scaleFactor = _getVisualizationScale();

    switch (_currentAlgorithm) {
      case AlgorithmDemo.wave:
      case AlgorithmDemo.pulse:
      case AlgorithmDemo.spiral:
      case AlgorithmDemo.interference:
      case AlgorithmDemo.flow:
        // These generate their own patterns, just need simple input
        data = List.generate(_bufferSize, (i) => i.toDouble());
        break;

      case AlgorithmDemo.cellular:
        // Cellular automata needs interesting seed data
        data = List.generate(_bufferSize, (i) {
          if (i % 8 == 0) return scaleFactor * 0.8;
          if (i % 13 == 0) return scaleFactor * 0.6;
          return scaleFactor * 0.1;
        });
        break;

      case AlgorithmDemo.noise:
        // Noise generates itself, just need indices
        data = List.generate(_bufferSize, (i) => i.toDouble());
        break;

      case AlgorithmDemo.mandelbrot:
        // Mandelbrot uses position data
        data = List.generate(_bufferSize, (i) => i.toDouble());
        break;

      case AlgorithmDemo.phi:
        // Golden ratio spiral needs harmonic seed data
        data = List.generate(_bufferSize, (i) {
          double phi = 1.618033988749895;
          return sin(i * phi * 0.1) * scaleFactor * 0.5;
        });
        break;

      case AlgorithmDemo.unity:
        // Unity field starts with coherent oscillations
        data = List.generate(_bufferSize, (i) {
          if (i % 8 == 0) return scaleFactor * 0.6;
          if (i % 13 == 0) return scaleFactor * 0.4;
          return scaleFactor * 0.2;
        });
        break;

      case AlgorithmDemo.kundalini:
        // Kundalini starts with base chakra energy
        data = List.generate(_bufferSize, (i) {
          double chakraEnergy =
              sin(i * 0.396) * scaleFactor * 0.3; // Root chakra frequency
          return chakraEnergy + (i % 7) * scaleFactor * 0.1; // 7 chakras
        });
        break;

      case AlgorithmDemo.theta:
        // Theta waves need low frequency oscillations
        data = List.generate(_bufferSize, (i) {
          double theta = sin(i * 0.006) * scaleFactor * 0.4; // 6Hz theta
          double geometry = cos(i * 0.1618) * scaleFactor * 0.2; // Golden ratio
          return theta + geometry;
        });
        break;

      case AlgorithmDemo.om:
        // Om frequency starts with 136.1Hz harmonic
        data = List.generate(_bufferSize, (i) {
          double om = sin(i * 0.1361) * scaleFactor * 0.5;
          double sacred =
              cos(i * 0.108) * scaleFactor * 0.3; // 108 sacred number
          return om + sacred;
        });
        break;

      case AlgorithmDemo.merkaba:
        // Merkaba needs counter-rotating energy fields
        data = List.generate(_bufferSize, (i) {
          double ascending = sin(i * 0.1618) * scaleFactor * 0.4;
          double descending = sin(i * -0.1618) * scaleFactor * 0.4;
          return (ascending + descending) * 0.5;
        });
        break;

      case AlgorithmDemo.coherence:
        // Heart coherence starts with 0.1Hz base rhythm
        data = List.generate(_bufferSize, (i) {
          double heart = sin(i * 0.1) * scaleFactor * 0.6;
          double breath =
              sin(i * 0.4) * scaleFactor * 0.2; // 4 breaths per cycle
          return heart + breath;
        });
        break;

      case AlgorithmDemo.gratitude:
        // Gratitude frequencies (528Hz, 432Hz, 741Hz)
        data = List.generate(_bufferSize, (i) {
          double love = sin(i * 0.528) * scaleFactor * 0.3;
          double earth = sin(i * 0.432) * scaleFactor * 0.3;
          double intuition = sin(i * 0.741) * scaleFactor * 0.2;
          return love + earth + intuition;
        });
        break;

      case AlgorithmDemo.schumann:
        // Schumann resonance 7.83Hz and harmonics
        data = List.generate(_bufferSize, (i) {
          double fundamental = sin(i * 0.00783) * scaleFactor * 0.5;
          double harmonic2 = sin(i * 0.01566) * scaleFactor * 0.3;
          double harmonic3 = sin(i * 0.02349) * scaleFactor * 0.2;
          return fundamental + harmonic2 + harmonic3;
        });
        break;

      case AlgorithmDemo.fibonacci:
        // Fibonacci spiral with golden ratio proportions
        data = List.generate(_bufferSize, (i) {
          double phi = 1.618033988749895;
          double spiral = sin(i * phi * 0.1) * scaleFactor * 0.4;
          double harmonic = cos(i / phi * 0.1) * scaleFactor * 0.3;
          return spiral + harmonic;
        });
        break;
    }

    _setBufferData(data);
  }

  double _getVisualizationScale() {
    // Use smaller, more stable ranges
    switch (_currentType.type) {
      case BufferDataType.int8:
        return 64.0; // Safe for most operations
      case BufferDataType.uint8:
        return 128.0;
      case BufferDataType.int16:
        return 512.0;
      case BufferDataType.uint16:
        return 1024.0;
      case BufferDataType.int32:
        return 2048.0;
      case BufferDataType.uint32:
        return 4096.0;
      case BufferDataType.float32:
      case BufferDataType.float64:
        return 200.0; // Nice range for float visualization
      default:
        return 200.0;
    }
  }

  void _setBufferData(List<double> data) {
    if (_inputBuffer == null) return;

    // Ensure data size matches buffer size exactly
    List<double> validData = List.filled(_bufferSize, 0.0);

    // Copy valid finite values up to buffer size
    int copyCount = 0;
    for (int i = 0; i < data.length && copyCount < _bufferSize; i++) {
      if (data[i].isFinite) {
        validData[copyCount] = data[i];
        copyCount++;
      }
    }

    // Clamp values to safe ranges for each type
    switch (_currentType.type) {
      case BufferDataType.int8:
        final Int8List typedData = Int8List(_bufferSize);
        for (int i = 0; i < _bufferSize; i++) {
          typedData[i] = validData[i].clamp(-128, 127).toInt();
        }
        _inputBuffer?.write(typedData, _bufferSize,
            dataType: _currentType.type);
        setState(() {
          _fullInputData = typedData.map((e) => e.toDouble()).toList();
        });
        break;

      case BufferDataType.uint8:
        final Uint8List typedData = Uint8List(_bufferSize);
        for (int i = 0; i < _bufferSize; i++) {
          typedData[i] = validData[i].clamp(0, 255).toInt();
        }
        _inputBuffer?.write(typedData, _bufferSize,
            dataType: _currentType.type);
        setState(() {
          _fullInputData = typedData.map((e) => e.toDouble()).toList();
        });
        break;

      case BufferDataType.int16:
        final Int16List typedData = Int16List(_bufferSize);
        for (int i = 0; i < _bufferSize; i++) {
          typedData[i] = validData[i].clamp(-32768, 32767).toInt();
        }
        _inputBuffer?.write(typedData, _bufferSize,
            dataType: _currentType.type);
        setState(() {
          _fullInputData = typedData.map((e) => e.toDouble()).toList();
        });
        break;

      case BufferDataType.uint16:
        final Uint16List typedData = Uint16List(_bufferSize);
        for (int i = 0; i < _bufferSize; i++) {
          typedData[i] = validData[i].clamp(0, 65535).toInt();
        }
        _inputBuffer?.write(typedData, _bufferSize,
            dataType: _currentType.type);
        setState(() {
          _fullInputData = typedData.map((e) => e.toDouble()).toList();
        });
        break;

      case BufferDataType.int32:
        final Int32List typedData = Int32List(_bufferSize);
        for (int i = 0; i < _bufferSize; i++) {
          typedData[i] = validData[i].clamp(-2147483648, 2147483647).toInt();
        }
        _inputBuffer?.write(typedData, _bufferSize,
            dataType: _currentType.type);
        setState(() {
          _fullInputData = typedData.map((e) => e.toDouble()).toList();
        });
        break;

      case BufferDataType.uint32:
        final Uint32List typedData = Uint32List(_bufferSize);
        for (int i = 0; i < _bufferSize; i++) {
          typedData[i] = validData[i].clamp(0, 4294967295).toInt();
        }
        _inputBuffer?.write(typedData, _bufferSize,
            dataType: _currentType.type);
        setState(() {
          _fullInputData = typedData.map((e) => e.toDouble()).toList();
        });
        break;

      case BufferDataType.float32:
        final Float32List typedData = Float32List(_bufferSize);
        for (int i = 0; i < _bufferSize; i++) {
          typedData[i] = validData[i].clamp(-3.4028235e38, 3.4028235e38);
        }
        _inputBuffer?.write(typedData, _bufferSize,
            dataType: _currentType.type);
        setState(() {
          _fullInputData = typedData.map((e) => e.toDouble()).toList();
        });
        break;

      case BufferDataType.float64:
        final Float64List typedData = Float64List(_bufferSize);
        for (int i = 0; i < _bufferSize; i++) {
          typedData[i] = validData[i];
        }
        _inputBuffer?.write(typedData, _bufferSize,
            dataType: _currentType.type);
        setState(() {
          _fullInputData = List.from(typedData);
        });
        break;

      default:
        final Float32List typedData = Float32List(_bufferSize);
        for (int i = 0; i < _bufferSize; i++) {
          typedData[i] = validData[i].clamp(-3.4028235e38, 3.4028235e38);
        }
        _inputBuffer?.write(typedData, _bufferSize,
            dataType: BufferDataType.float32);
        setState(() {
          _fullInputData = typedData.map((e) => e.toDouble()).toList();
        });
        break;
    }
  }

  String _generateShaderCode() {
    String wgslType = _getWGSLType();
    String operation = _getOperation();

    return '''
@group(0) @binding(0) var<storage, read_write> inp: array<$wgslType>;
@group(0) @binding(1) var<storage, read_write> out: array<$wgslType>;

@compute @workgroup_size(256)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
    let idx = global_id.x;
    if (idx < arrayLength(&inp)) {
        let x = inp[idx];
        $operation
    }
}
''';
  }

  String _getWGSLType() {
    switch (_currentType.type) {
      case BufferDataType.int8:
      case BufferDataType.int16:
      case BufferDataType.int32:
        return 'i32';
      case BufferDataType.uint8:
      case BufferDataType.uint16:
      case BufferDataType.uint32:
        return 'u32';
      case BufferDataType.float32:
        return 'f32';
      case BufferDataType.float64:
        return 'i32'; // Float64 is packed as i32 pairs
      default:
        return 'f32';
    }
  }

  String _getOperation() {
    bool isFloat = _currentType.type == BufferDataType.float32;
    bool isUnsigned = _currentType.type == BufferDataType.uint8 ||
        _currentType.type == BufferDataType.uint16 ||
        _currentType.type == BufferDataType.uint32;

    switch (_currentAlgorithm) {
      case AlgorithmDemo.wave:
        if (isFloat) {
          return '''
        // Traveling wave that continuously evolves
        let wave_speed = 0.1;
        let neighbor_left = select(0.0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
        let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
        let wave = sin(x * 0.1 + f32(idx) * 0.05) * 30.0;
        out[idx] = wave + (neighbor_left + neighbor_right) * 0.1;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned integer traveling wave - NO NEGATIVE VALUES
        let wave_val = (x + idx * 3u) % 200u;
        let neighbor = inp[(idx + 1u) % arrayLength(&inp)];
        let result = wave_val + neighbor / 4u;
        out[idx] = result;''';
        } else {
          return '''
        // Signed integer traveling wave
        let wave_val = i32((u32(abs(x)) + idx * 3u) % 200u);
        let neighbor = inp[(idx + 1u) % arrayLength(&inp)];
        out[idx] = wave_val + neighbor / 4;''';
        }

      case AlgorithmDemo.pulse:
        if (isFloat) {
          return '''
    // Continuous pulse generator with traveling waves
    let neighbor_left = select(0.0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
    let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
    
    // Create cycling pulse sources based on current values
    let pulse_cycle = sin(x * 0.1) > 0.8;
    let pulse_source = select(0.0, 100.0, pulse_cycle && idx % 50u == 0u);
    
    // Propagate with asymmetric weights for directional flow
    let propagated = neighbor_left * 0.3 + neighbor_right * 0.2;
    
    // Add small random noise to prevent stagnation
    let noise = sin(f32(idx) * 1.234) * 2.0;
    
    let result = pulse_source + propagated + noise;
    out[idx] = result * 0.95;  // Global decay''';
        } else if (isUnsigned) {
          return '''
    // Unsigned continuous pulse generator
    let neighbor_left = select(0u, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
    let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
    
    // Create pulse when neighbor values are in specific range
    let trigger_condition = (neighbor_left > 20u && neighbor_left < 40u) || idx % 64u == 0u;
    let pulse_source = select(0u, 120u, trigger_condition);
    
    // Asymmetric propagation for flow
    let propagated = neighbor_left * 3u / 10u + neighbor_right * 2u / 10u;
    
    // Small variation to prevent stagnation
    let variation = (idx * 7u) % 5u;
    
    let combined = pulse_source + propagated + variation;
    let result = combined * 95u / 100u;  // Decay
    out[idx] = result;''';
        } else {
          return '''
    // Signed continuous pulse generator
    let neighbor_left = select(0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
    let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
    
    // Create pulse when conditions are met
    let trigger_condition = (abs(neighbor_left) > 20 && abs(neighbor_left) < 40) || idx % 64u == 0u;
    let pulse_source = select(0, 120, trigger_condition);
    
    // Asymmetric propagation
    let propagated = neighbor_left * 3 / 10 + neighbor_right * 2 / 10;
    
    // Small signed variation
    let variation = i32((idx * 7u) % 5u) - 2;
    
    let combined = pulse_source + propagated + variation;
    let result = combined * 95 / 100;
    out[idx] = result;''';
        }

      case AlgorithmDemo.spiral:
        if (isFloat) {
          return '''
        // Rotating spiral pattern
        let angle = x * 0.01 + f32(idx) * 0.02;
        let radius = sin(x * 0.05) * 20.0 + 30.0;
        let spiral = sin(angle * 3.0) * radius + cos(angle * 2.0) * radius * 0.5;
        out[idx] = spiral;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned spiral - ALL POSITIVE VALUES
        let spiral_angle = (x + idx * 5u) % 360u;
        let spiral_radius = (x % 50u) + 10u;
        let pattern = (spiral_angle * spiral_radius) / 100u;
        out[idx] = pattern;''';
        } else {
          return '''
        // Signed spiral
        let spiral_angle = (u32(abs(x)) + idx * 5u) % 360u;
        let spiral_radius = (u32(abs(x)) % 50u) + 10u;
        out[idx] = i32((spiral_angle * spiral_radius) / 100u) - 50;''';
        }

      case AlgorithmDemo.interference:
        if (isFloat) {
          return '''
        // Multiple interfering waves
        let wave1 = sin(x * 0.03 + f32(idx) * 0.1) * 25.0;
        let wave2 = sin(x * 0.07 + f32(idx) * 0.05) * 20.0;
        let wave3 = cos(x * 0.05 + f32(idx) * 0.08) * 15.0;
        out[idx] = wave1 + wave2 + wave3;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned interference - AVOID OVERFLOW
        let w1 = (x * 3u + idx * 7u) % 100u;
        let w2 = (x * 5u + idx * 3u) % 80u;
        let w3 = (x * 7u + idx * 5u) % 60u;
        let sum = w1 + w2 + w3;
        out[idx] = sum / 3u;''';
        } else {
          return '''
        // Signed interference
        let w1 = (u32(abs(x)) * 3u + idx * 7u) % 100u;
        let w2 = (u32(abs(x)) * 5u + idx * 3u) % 80u;
        let w3 = (u32(abs(x)) * 7u + idx * 5u) % 60u;
        out[idx] = i32((w1 + w2 + w3) / 3u) - 40;''';
        }

      case AlgorithmDemo.cellular:
        if (isFloat) {
          return '''
        // Game of Life style cellular automata
        let left = select(0.0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
        let right = inp[(idx + 1u) % arrayLength(&inp)];
        let sum = left + x + right;
        let avg = sum / 3.0;
        
        // Oscillating rule that creates waves
        let threshold = 30.0;
        let new_val = select(
          avg * 1.2,
          avg * 0.8,
          abs(avg) > threshold
        );
        out[idx] = new_val;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned cellular automata - NO NEGATIVE RESULTS
        let left = select(0u, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
        let right = inp[(idx + 1u) % arrayLength(&inp)];
        let sum = left + x + right;
        let avg = sum / 3u;
        
        // Growth/decay rule for unsigned
        let threshold = 30u;
        let growth = avg + avg / 5u;  // +20%
        let decay = avg - avg / 5u;   // -20%
        let new_val = select(growth, decay, avg > threshold);
        out[idx] = new_val;''';
        } else {
          return '''
        // Signed cellular automata
        let left = select(0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
        let right = inp[(idx + 1u) % arrayLength(&inp)];
        let sum = left + x + right;
        let avg = sum / 3;
        
        let threshold = 30;
        let new_val = select(
          avg * 6 / 5,
          avg * 4 / 5,
          abs(avg) > threshold
        );
        out[idx] = new_val;''';
        }

      case AlgorithmDemo.noise:
        if (isFloat) {
          return '''
        // Evolving noise with feedback
        let seed = u32(abs(x)) * 1103515245u + idx * 12345u;
        let noise_base = (seed / 65536u) % 100u;
        let neighbor_influence = inp[(idx + 7u) % arrayLength(&inp)] * 0.3;
        let noise = f32(noise_base) - 50.0 + neighbor_influence;
        out[idx] = noise;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned noise - ALL POSITIVE
        let seed = x * 1103515245u + idx * 12345u;
        let noise_base = (seed / 65536u) % 200u;
        let neighbor_influence = inp[(idx + 7u) % arrayLength(&inp)] / 10u;
        let noise = noise_base + neighbor_influence;
        out[idx] = noise;''';
        } else {
          return '''
        // Signed noise
        let seed = u32(abs(x)) * 1103515245u + idx * 12345u;
        let noise_base = (seed / 65536u) % 100u;
        let neighbor_influence = inp[(idx + 7u) % arrayLength(&inp)] * 3 / 10;
        let noise = i32(noise_base) - 50 + neighbor_influence;
        out[idx] = noise;''';
        }

      case AlgorithmDemo.mandelbrot:
        if (isFloat) {
          return '''
        // Evolving Mandelbrot-like pattern
        let c_real = (f32(idx % 32u) - 16.0) / 16.0;
        let c_imag = x * 0.001;
        
        let z_real = sin(x * 0.01) * 2.0;
        let z_imag = cos(x * 0.01) * 2.0;
        
        // Single iteration to keep it evolving
        let temp = z_real * z_real - z_imag * z_imag + c_real;
        let new_imag = 2.0 * z_real * z_imag + c_imag;
        
        out[idx] = temp * 20.0 + new_imag * 10.0;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned fractal-like pattern - POSITIVE ONLY
        let fractal_x = x % 64u;
        let fractal_y = idx % 32u;
        let pattern = (fractal_x * fractal_x + fractal_y * fractal_y) % 128u;
        out[idx] = pattern + (x / 8u);''';
        } else {
          return '''
        // Signed fractal pattern
        let fractal_x = u32(abs(x)) % 64u;
        let fractal_y = idx % 32u;
        let pattern = (fractal_x * fractal_x + fractal_y * fractal_y) % 128u;
        out[idx] = i32(pattern) - 64 + x / 4;''';
        }

      case AlgorithmDemo.flow:
        if (isFloat) {
          return '''
        // Fluid-like flow field
        let flow_x = sin(x * 0.02 + f32(idx) * 0.03) * 20.0;
        let flow_y = cos(x * 0.03 + f32(idx) * 0.02) * 15.0;
        let turbulence = sin(x * 0.1) * sin(f32(idx) * 0.1) * 10.0;
        let neighbor = inp[(idx + 3u) % arrayLength(&inp)] * 0.2;
        out[idx] = flow_x + flow_y + turbulence + neighbor;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned flow pattern - NO UNDERFLOW
        let flow_base = (x * 13u + idx * 17u) % 128u;
        let neighbor_flow = inp[(idx + 5u) % arrayLength(&inp)] / 5u;
        let turbulence = (x * idx) % 40u;
        let total = flow_base + neighbor_flow + turbulence;
        out[idx] = total;''';
        } else {
          return '''
        // Signed flow pattern
        let flow_base = (u32(abs(x)) * 13u + idx * 17u) % 128u;
        let neighbor_flow = inp[(idx + 5u) % arrayLength(&inp)] / 5;
        let turbulence = (u32(abs(x)) * idx) % 40u;
        out[idx] = i32(flow_base) + neighbor_flow + i32(turbulence) - 84;''';
        }
      case AlgorithmDemo.phi:
        if (isFloat) {
          return '''
        // Sacred golden ratio spiral consciousness pattern
        let phi = 1.618033988749895;
        let inv_phi = 0.618033988749895;
        
        // Fibonacci consciousness wave
        let fib_wave = sin(x * inv_phi + f32(idx) * phi * 0.01) * 30.0;
        
        // Sacred spiral that mirrors DNA/galaxy structure
        let spiral_angle = f32(idx) * phi * 0.1;
        let spiral_radius = sin(x * 0.01) * 20.0;
        let golden_spiral = sin(spiral_angle) * spiral_radius;
        
        // Divine proportion resonance
        let divine_freq = cos(x * 0.01618 + f32(idx) * inv_phi) * 15.0;
        
        out[idx] = fib_wave + golden_spiral + divine_freq;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned phi pattern
        let phi_base = (x * 1618u + idx * 618u) % 200u;
        let golden_spiral = (idx * 1618u) % 100u;
        out[idx] = phi_base + golden_spiral;''';
        } else {
          return '''
        // Signed phi pattern
        let phi_base = (u32(abs(x)) * 1618u + idx * 618u) % 200u;
        let golden_spiral = (idx * 1618u) % 100u;
        out[idx] = i32(phi_base + golden_spiral) - 150;''';
        }

      case AlgorithmDemo.unity:
        if (isFloat) {
          return '''
        // Collective consciousness field
        let neighbor_left = select(0.0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
        let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
        let neighbor_far = inp[(idx + 7u) % arrayLength(&inp)];
        
        // Non-local entanglement pattern
        let entanglement = (neighbor_left + neighbor_right + neighbor_far) / 3.0;
        
        // Unity consciousness frequency (40Hz gamma waves)
        let gamma_wave = sin(x * 0.04) * 25.0;
        
        // Morphic field resonance
        let morphic = sin(f32(idx) * 0.108 + x * 0.001) * 20.0; // 108Hz sacred frequency
        
        // Coherence amplification - when neighbors align, consciousness expands
        let coherence = 1.0 + abs(entanglement) / 100.0;
        
        out[idx] = (gamma_wave + morphic) * coherence + entanglement * 0.3;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned unity field
        let neighbor_left = select(0u, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
        let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
        let entanglement = (neighbor_left + neighbor_right) / 2u;
        let unity_wave = (x * 40u + idx * 108u) % 150u;
        out[idx] = unity_wave + entanglement / 3u;''';
        } else {
          return '''
        // Signed unity field
        let neighbor_left = select(0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
        let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
        let entanglement = (neighbor_left + neighbor_right) / 2;
        let unity_wave = (u32(abs(x)) * 40u + idx * 108u) % 150u;
        out[idx] = i32(unity_wave) + entanglement / 3 - 75;''';
        }

      case AlgorithmDemo.kundalini:
        if (isFloat) {
          return '''
        // Serpent energy ascending through chakras
        let rising_energy = sin(x * 0.001 + f32(idx) * 0.02) * 40.0;
        
        // 7 chakra frequencies combined
        let chakra1 = sin(x * 0.396) * 8.0;  // Root - 396Hz
        let chakra2 = sin(x * 0.417) * 7.0;  // Sacral - 417Hz  
        let chakra3 = sin(x * 0.528) * 6.0;  // Solar - 528Hz
        let chakra4 = sin(x * 0.639) * 5.0;  // Heart - 639Hz
        let chakra5 = sin(x * 0.741) * 4.0;  // Throat - 741Hz
        let chakra6 = sin(x * 0.852) * 3.0;  // Third Eye - 852Hz
        let chakra7 = sin(x * 0.963) * 2.0;  // Crown - 963Hz
        
        // Spiral activation pattern
        let spiral_activation = sin(f32(idx) * 0.618 + x * 0.01) * 10.0;
        
        let all_chakras = chakra1 + chakra2 + chakra3 + chakra4 + chakra5 + chakra6 + chakra7;
        out[idx] = rising_energy + all_chakras + spiral_activation;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned kundalini pattern
        let chakra_base = (x * 528u + idx * 396u) % 180u;
        let rising_energy = (idx * 618u) % 100u;
        out[idx] = chakra_base + rising_energy;''';
        } else {
          return '''
        // Signed kundalini pattern
        let chakra_base = (u32(abs(x)) * 528u + idx * 396u) % 180u;
        let rising_energy = (idx * 618u) % 100u;
        out[idx] = i32(chakra_base + rising_energy) - 140;''';
        }

      case AlgorithmDemo.theta:
        if (isFloat) {
          return '''
        // Deep theta state (4-8Hz) for transcendence
        let theta_base = sin(x * 0.006) * 35.0;  // 6Hz theta
        let theta_harmonic = sin(x * 0.004) * 25.0;  // 4Hz deep theta
        
        // DMT-like geometric interference
        let geometry1 = sin(x * 0.1 + f32(idx) * 0.1618) * 20.0;
        let geometry2 = cos(x * 0.08 + f32(idx) * 0.2618) * 15.0;
        let geometry3 = sin(x * 0.12 + f32(idx) * 0.1416) * 10.0;
        
        // Pineal gland activation frequency
        let pineal = sin(x * 0.936) * 12.0;  // 936Hz pineal activation
        
        // Transcendental interference pattern
        let transcendence = geometry1 + geometry2 + geometry3;
        
        out[idx] = theta_base + theta_harmonic + transcendence + pineal;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned theta pattern
        let theta_wave = (x * 6u + idx * 936u) % 160u;
        let geometry = (idx * 1618u) % 80u;
        out[idx] = theta_wave + geometry;''';
        } else {
          return '''
        // Signed theta pattern
        let theta_wave = (u32(abs(x)) * 6u + idx * 936u) % 160u;
        let geometry = (idx * 1618u) % 80u;
        out[idx] = i32(theta_wave + geometry) - 120;''';
        }

      case AlgorithmDemo.om:
        if (isFloat) {
          return '''
        // Sacred AUM frequency (136.1Hz - Om tuning)
        let om_fundamental = sin(x * 0.1361) * 40.0;
        let om_harmonic2 = sin(x * 0.2722) * 20.0;
        let om_harmonic3 = sin(x * 0.4083) * 13.0;
        
        // Cosmic background radiation pattern (160.2 GHz scaled)
        let cosmic = sin(x * 0.001602 + f32(idx) * 0.108) * 15.0;
        
        // Sacred 108 repetition pattern
        let sacred_108 = sin(f32(idx % 108u) * 0.058) * 10.0;
        
        // Universal consciousness field
        let universal = cos(x * 0.007 + f32(idx) * 0.0108) * 8.0;
        
        out[idx] = om_fundamental + om_harmonic2 + om_harmonic3 + cosmic + sacred_108 + universal;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned om pattern
        let om_wave = (x * 1361u + idx * 108u) % 200u;
        let cosmic = (idx % 108u) * 3u;
        out[idx] = om_wave + cosmic;''';
        } else {
          return '''
        // Signed om pattern
        let om_wave = (u32(abs(x)) * 1361u + idx * 108u) % 200u;
        let cosmic = (idx % 108u) * 3u;
        out[idx] = i32(om_wave + cosmic) - 150;''';
        }

      case AlgorithmDemo.merkaba:
        if (isFloat) {
          return '''
        // Counter-rotating tetrahedron energy field
        let rotation_speed = 0.1618;
        
        // Ascending tetrahedron (masculine energy)
        let ascending = sin(x * rotation_speed + f32(idx) * 0.1) * 30.0;
        
        // Descending tetrahedron (feminine energy) - counter-rotating
        let descending = sin(x * -rotation_speed + f32(idx) * 0.1) * 30.0;
        
        // 17.5 Hz merkaba activation frequency
        let activation = sin(x * 0.0175) * 20.0;
        
        // Sacred geometry interference creating star tetrahedron
        let merkaba_field = (ascending + descending) * sin(x * 0.001 + f32(idx) * 0.05);
        
        // Unity consciousness emanation
        let emanation = cos(f32(idx) * 0.0618 + x * 0.003) * 15.0;
        
        out[idx] = merkaba_field + activation + emanation;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned merkaba pattern
        let ascending = (x * 1618u + idx * 175u) % 150u;
        let descending = (x * 618u + idx * 75u) % 120u;
        out[idx] = (ascending + descending) / 2u;''';
        } else {
          return '''
        // Signed merkaba pattern
        let ascending = (u32(abs(x)) * 1618u + idx * 175u) % 150u;
        let descending = (u32(abs(x)) * 618u + idx * 75u) % 120u;
        out[idx] = i32((ascending + descending) / 2u) - 67;''';
        }

      case AlgorithmDemo.coherence:
        if (isFloat) {
          return '''
        // Heart coherence pattern (0.1Hz base with harmonics)
        let coherence_base = 0.1;
        let heart_wave = sin(x * coherence_base) * 30.0;
        let breath_sync = sin(x * coherence_base * 4.0) * 15.0; // 4 breaths per cycle
        
        // Neighbor coupling creates collective coherence
        let left = select(0.0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
        let right = inp[(idx + 1u) % arrayLength(&inp)];
        let synchrony = (left + right) * 0.3;
        
        out[idx] = heart_wave + breath_sync + synchrony;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned coherence pattern
        let heart_wave = (x * 10u + idx * 4u) % 120u;
        let left = select(0u, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
        let right = inp[(idx + 1u) % arrayLength(&inp)];
        let synchrony = (left + right) / 10u;
        out[idx] = heart_wave + synchrony;''';
        } else {
          return '''
        // Signed coherence pattern
        let heart_wave = (u32(abs(x)) * 10u + idx * 4u) % 120u;
        let left = select(0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
        let right = inp[(idx + 1u) % arrayLength(&inp)];
        let synchrony = (left + right) / 10;
        out[idx] = i32(heart_wave) + synchrony - 60;''';
        }

      case AlgorithmDemo.gratitude:
        if (isFloat) {
          return '''
        // Multiple healing frequencies combined
        let freq_528 = sin(x * 0.528) * 20.0;  // Love frequency
        let freq_432 = sin(x * 0.432) * 18.0;  // Earth resonance
        let freq_741 = sin(x * 0.741) * 12.0;  // Intuition
        
        // Creates expanding waves of positive intention
        let expansion = sin(f32(idx) * 0.1 + x * 0.05) * 8.0;
        let intention = cos(x * 0.01 + f32(idx) * 0.03) * 5.0;
        
        out[idx] = freq_528 + freq_432 + freq_741 + expansion + intention;''';
        } else if (isUnsigned) {
          return '''
        // Unsigned gratitude pattern
        let healing_freq = (x * 528u + idx * 432u) % 180u;
        let intention = (idx * 741u) % 50u;
        out[idx] = healing_freq + intention;''';
        } else {
          return '''
        // Signed gratitude pattern
        let healing_freq = (u32(abs(x)) * 528u + idx * 432u) % 180u;
        let intention = (idx * 741u) % 50u;
        out[idx] = i32(healing_freq + intention) - 115;''';
        }

      case AlgorithmDemo.schumann:
        if (isFloat) {
          return '''
    // Earth's natural frequency (7.83Hz and harmonics) with time evolution
    let neighbor_left = select(0.0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
    let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
    
    // Dynamic Schumann resonance with neighbor coupling
    let base_schumann = 0.00783; // 7.83Hz scaled
    let fundamental = sin(x * base_schumann + f32(idx) * 0.001) * 25.0;
    let second_harmonic = sin(x * base_schumann * 2.0 + f32(idx) * 0.002) * 15.0;
    let third_harmonic = sin(x * base_schumann * 3.0 + f32(idx) * 0.003) * 10.0;
    
    // Grounding wave that connects to earth energy with propagation
    let grounding = cos(x * 0.01 + f32(idx) * 0.0783) * 8.0;
    
    // Add neighbor coupling for wave propagation
    let coupling = (neighbor_left + neighbor_right) * 0.15;
    
    // Add chaos injection to prevent stagnation
    let chaos = sin(x * 1.234 + f32(idx) * 0.567) * 2.0;
    
    // Remove damping, add energy injection instead
    let evolved = fundamental + second_harmonic + third_harmonic + grounding + coupling + chaos;
    
    out[idx] = evolved;''';
        } else if (isUnsigned) {
          return '''
    // Unsigned schumann with evolution
    let neighbor_left = select(0u, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
    let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
    let earth_freq = (x * 783u + idx * 78u) % 140u;
    let grounding = (idx * 783u) % 60u;
    let coupling = (neighbor_left + neighbor_right) / 8u;
    let chaos = (x * 1234u + idx * 567u) % 20u;
    out[idx] = earth_freq + grounding + coupling + chaos;''';
        } else {
          return '''
    // Signed schumann with evolution
    let neighbor_left = select(0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
    let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
    let earth_freq = (u32(abs(x)) * 783u + idx * 78u) % 140u;
    let grounding = (idx * 783u) % 60u;
    let coupling = (neighbor_left + neighbor_right) / 8;
    let chaos = i32((u32(abs(x)) * 1234u + idx * 567u) % 20u) - 10;
    out[idx] = i32(earth_freq + grounding) + coupling + chaos - 100;''';
        }

      case AlgorithmDemo.fibonacci:
        if (isFloat) {
          return '''
    // Fibonacci sequence with dynamic spiral evolution
    let neighbor_left = select(0.0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
    let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
    
    // Dynamic fibonacci spiral
    let fib_ratio = 1.618033988749895;
    let spiral_angle = f32(idx) * fib_ratio * 0.1 + x * 0.001;
    let spiral_radius = sin(x * 0.01618 + f32(idx) * 0.001) * 20.0;
    
    let fibonacci_wave = sin(spiral_angle) * spiral_radius;
    let golden_harmonic = cos(spiral_angle / fib_ratio) * 15.0;
    
    // Add neighbor coupling for propagation
    let coupling = (neighbor_left + neighbor_right) * 0.1;
    
    // Stronger chaos injection to prevent stagnation
    let chaos1 = sin(x * 0.789 + f32(idx) * 1.234) * 8.0;
    let chaos2 = cos(x * 1.111 + f32(idx) * 0.987) * 5.0;
    
    // Add energy injection based on golden ratio
    let energy_injection = sin(x * fib_ratio * 0.01) * 3.0;
    
    // Nature's perfect proportion with continuous evolution
    out[idx] = fibonacci_wave + golden_harmonic + coupling + chaos1 + chaos2 + energy_injection;''';
        } else if (isUnsigned) {
          return '''
    // Unsigned fibonacci with evolution
    let neighbor_left = select(0u, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
    let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
    let fib_angle = (idx * 1618u + x / 8u) % 360u;
    let fib_radius = (x % 64u) + 20u;
    let pattern = (fib_angle * fib_radius) / 200u;
    let coupling = (neighbor_left + neighbor_right) / 10u;
    let chaos = (x * 789u + idx * 1234u) % 30u;
    out[idx] = pattern + coupling + chaos;''';
        } else {
          return '''
    // Signed fibonacci with evolution
    let neighbor_left = select(0, inp[(idx - 1u) % arrayLength(&inp)], idx > 0u);
    let neighbor_right = inp[(idx + 1u) % arrayLength(&inp)];
    let fib_angle = (idx * 1618u + u32(abs(x)) / 8u) % 360u;
    let fib_radius = (u32(abs(x)) % 64u) + 20u;
    let pattern = (fib_angle * fib_radius) / 200u;
    let coupling = (neighbor_left + neighbor_right) / 10;
    let chaos = i32((u32(abs(x)) * 789u + idx * 1234u) % 30u) - 15;
    out[idx] = i32(pattern) + coupling + chaos - 60;''';
        }
    }
  }

  Future<void> _runKernel() async {
    if (!_minigpu.isInitialized ||
        _inputBuffer == null ||
        _outputBuffer == null) {
      print('Minigpu not initialized or buffers null');
      return;
    }

    try {
      String shaderCode = _generateShaderCode();
      _shader.loadKernelString(shaderCode);
      _shader.setBuffer('inp', _inputBuffer!);
      _shader.setBuffer('out', _outputBuffer!);

      int workgroups = ((_bufferSize + 255) / 256).ceil();
      await _shader.dispatch(workgroups, 1, 1);

      // Read results based on type
      switch (_currentType.type) {
        case BufferDataType.int8:
          final Int8List outputData = Int8List(_bufferSize);
          await _outputBuffer?.read(outputData, _bufferSize,
              dataType: _currentType.type);

          setState(() {
            List<double> resultData =
                outputData.map((e) => e.toDouble()).toList();
            _lastData = List.from(_fullOutputData);
            _fullOutputData = resultData;
            _fullInputData = resultData; // Feed back for next execution
          });

          _inputBuffer?.write(outputData, _bufferSize,
              dataType: _currentType.type);
          break;

        case BufferDataType.uint8:
          final Uint8List outputData = Uint8List(_bufferSize);
          await _outputBuffer?.read(outputData, _bufferSize,
              dataType: _currentType.type);

          setState(() {
            List<double> resultData =
                outputData.map((e) => e.toDouble()).toList();
            _lastData = List.from(_fullOutputData);
            _fullOutputData = resultData;
            _fullInputData = resultData;
          });

          _inputBuffer?.write(outputData, _bufferSize,
              dataType: _currentType.type);
          break;

        case BufferDataType.int16:
          final Int16List outputData = Int16List(_bufferSize);
          await _outputBuffer?.read(outputData, _bufferSize,
              dataType: _currentType.type);

          setState(() {
            List<double> resultData =
                outputData.map((e) => e.toDouble()).toList();
            _lastData = List.from(_fullInputData);
            _fullOutputData = resultData;
            _fullInputData = resultData;
          });

          _inputBuffer?.write(outputData, _bufferSize,
              dataType: _currentType.type);
          break;

        case BufferDataType.uint16:
          final Uint16List outputData = Uint16List(_bufferSize);
          await _outputBuffer?.read(outputData, _bufferSize,
              dataType: _currentType.type);

          setState(() {
            List<double> resultData =
                outputData.map((e) => e.toDouble()).toList();
            _lastData = List.from(_fullInputData);
            _fullOutputData = resultData;
            _fullInputData = resultData;
          });

          _inputBuffer?.write(outputData, _bufferSize,
              dataType: _currentType.type);
          break;
        case BufferDataType.int32:
          final Int32List outputData = Int32List(_bufferSize);
          await _outputBuffer?.read(outputData, _bufferSize,
              dataType: _currentType.type);

          setState(() {
            List<double> resultData =
                outputData.map((e) => e.toDouble()).toList();
            _lastData = List.from(_fullInputData);
            _fullOutputData = resultData;
            _fullInputData = resultData;
          });

          _inputBuffer?.write(outputData, _bufferSize,
              dataType: _currentType.type);
          break;
        case BufferDataType.uint32:
          final Uint32List outputData = Uint32List(_bufferSize);
          await _outputBuffer?.read(outputData, _bufferSize,
              dataType: _currentType.type);

          setState(() {
            List<double> resultData =
                outputData.map((e) => e.toDouble()).toList();
            _lastData = List.from(_fullInputData);
            _fullOutputData = resultData;
            _fullInputData = resultData;
          });

          _inputBuffer?.write(outputData, _bufferSize,
              dataType: _currentType.type);
          break;

        case BufferDataType.float32:
          final Float32List outputData = Float32List(_bufferSize);
          await _outputBuffer?.read(outputData, _bufferSize,
              dataType: _currentType.type);

          setState(() {
            List<double> resultData =
                outputData.map((e) => e.toDouble()).toList();
            _lastData = List.from(_fullInputData);
            _fullOutputData = resultData;
            _fullInputData = resultData;
          });

          _inputBuffer?.write(outputData, _bufferSize,
              dataType: _currentType.type);
          break;

        case BufferDataType.float64:
          final Float64List outputData = Float64List(_bufferSize);
          await _outputBuffer?.read(outputData, _bufferSize,
              dataType: _currentType.type);

          setState(() {
            List<double> resultData =
                outputData.map((e) => e.toDouble()).toList();
            _lastData = List.from(_fullInputData);
            _fullOutputData = resultData;
            _fullInputData = resultData;
          });

          _inputBuffer?.write(outputData, _bufferSize,
              dataType: _currentType.type);
          break;

        default:
          final Float32List outputData = Float32List(_bufferSize);
          await _outputBuffer?.read(outputData, _bufferSize,
              dataType: BufferDataType.float32);

          setState(() {
            List<double> resultData =
                outputData.map((e) => e.toDouble()).toList();
            _lastData = List.from(_fullInputData);
            _fullOutputData = resultData;
            _fullInputData = resultData;
          });

          _inputBuffer?.write(outputData, _bufferSize,
              dataType: BufferDataType.float32);
      }

      _updatePerformanceMetrics();

      if (_autoMode && mounted) {
        Future.delayed(Duration(milliseconds: (1000 / _animationSpeed).round()),
            () {
          if (mounted && _autoMode) {
            _runKernel();
          }
        });
      }
    } catch (e, stackTrace) {
      print('=== KERNEL EXECUTION ERROR ===');
      print('Error: $e');
      print('Buffer size: $_bufferSize');
      print('Type: ${_currentType.type}');
      print('Auto mode: $_autoMode');
      print('Stack trace: $stackTrace');

      setState(() {
        _fullInputData = [];
        _fullOutputData = [];
      });
    }
  }

  void _updatePerformanceMetrics() {
    DateTime now = DateTime.now();
    _totalOperations++;

    if (now.difference(_lastOpTime).inMilliseconds > 1000) {
      setState(() {
        _operationsPerSecond =
            (_totalOperations / now.difference(_lastOpTime).inSeconds).round();
      });
      _lastOpTime = now;
      _totalOperations = 0;
    }
  }

  void _switchType(DataTypeDemo newType) {
    setState(() {
      _currentType = newType;
    });

    // Stop auto mode during type switch to prevent race conditions
    bool wasAutoMode = _autoMode;
    _autoMode = false;

    // Wait for any pending operations to complete
    Future.delayed(const Duration(milliseconds: 10), () {
      if (mounted) {
        _createBuffers();
        _generateInputData();

        // Restore auto mode after buffers are ready
        if (wasAutoMode) {
          Future.delayed(const Duration(milliseconds: 10), () {
            if (mounted) {
              setState(() {
                _autoMode = true;
              });
              _runKernel();
            }
          });
        }
      }
    });
  }

  void _switchAlgorithm(AlgorithmDemo newAlgorithm) {
    setState(() {
      _currentAlgorithm = newAlgorithm;
    });

    Future.delayed(const Duration(milliseconds: 10), () {
      if (mounted) {
        _generateInputData();
      }
    });
  }

  @override
  void dispose() {
    _tabController.dispose();
    _waveController.dispose();
    _colorController.dispose();
    _shader.destroy();
    _inputBuffer?.destroy();
    _outputBuffer?.destroy();
    super.dispose();
  }

  Widget _buildTypeSelector() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(8),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Data Type',
                style: TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                    color: Color(0xFF00FFFF))),
            const SizedBox(height: 8),
            Wrap(
              spacing: 8,
              children: DataTypeDemo.values
                  .map((type) => AnimatedBuilder(
                        animation: _colorController,
                        builder: (context, child) => FilterChip(
                          label: Text(type.label),
                          selected: _currentType == type,
                          onSelected: (_) => _switchType(type),
                          selectedColor: const Color(0xFF0080FF),
                          checkmarkColor: const Color(0xFF00FFFF),
                        ),
                      ))
                  .toList(),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildAlgorithmSelector() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(8),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Algorithm',
                style: TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                    color: Color(0xFF00FFFF))),
            const SizedBox(height: 8),
            Wrap(
              spacing: 8,
              children: AlgorithmDemo.values
                  .map((algo) => ChoiceChip(
                        label: Text(algo.label),
                        selected: _currentAlgorithm == algo,
                        onSelected: (_) => _switchAlgorithm(algo),
                        selectedColor: const Color(0xFF0080FF),
                      ))
                  .toList(),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildVisualizationTab() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(8),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Text('Live Data Visualization',
                    style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                        color: Color(0xFF00FFFF))),
                Text('$_operationsPerSecond ops/sec',
                    style: const TextStyle(color: Color(0xFF00FF80))),
              ],
            ),
            const SizedBox(height: 16),
            SizedBox(
              height: 300,
              child: CustomPaint(
                painter: DataVisualizationPainter(
                  inputData: _previewLastData,
                  outputData: _previewOutputData,
                  animation: _waveController,
                  colorAnimation: _colorController,
                  dataType: _currentType,
                ),
                size: Size.infinite,
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildDataTab() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(8),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Raw Data View',
                style: TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                    color: Color(0xFF00FFFF))),
            const SizedBox(height: 16),
            SizedBox(
              height: 300,
              child: Row(
                children: [
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        const Text('Input Data',
                            style: TextStyle(
                                fontWeight: FontWeight.bold,
                                color: Color(0xFF0080FF))),
                        const SizedBox(height: 8),
                        Expanded(
                          child: Container(
                            padding: const EdgeInsets.all(8),
                            decoration: BoxDecoration(
                              border:
                                  Border.all(color: const Color(0xFF0080FF)),
                              borderRadius: BorderRadius.circular(4),
                            ),
                            child: ListView.builder(
                              itemCount:
                                  _previewInputData.length, // Use safe getter
                              itemBuilder: (context, index) {
                                return Text(
                                  '[$index]: ${_previewInputData[index].toStringAsFixed(3)}',
                                  style: const TextStyle(
                                      fontFamily: 'monospace',
                                      color: Color(0xFF00FFFF)),
                                );
                              },
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                  const SizedBox(width: 16),
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        const Text('Output Data',
                            style: TextStyle(
                                fontWeight: FontWeight.bold,
                                color: Color(0xFF00FF80))),
                        const SizedBox(height: 8),
                        Expanded(
                          child: Container(
                            padding: const EdgeInsets.all(8),
                            decoration: BoxDecoration(
                              border:
                                  Border.all(color: const Color(0xFF00FF80)),
                              borderRadius: BorderRadius.circular(4),
                            ),
                            child: ListView.builder(
                              itemCount:
                                  _previewOutputData.length, // Use safe getter
                              itemBuilder: (context, index) {
                                return Text(
                                  '[$index]: ${_previewOutputData[index].toStringAsFixed(3)}',
                                  style: const TextStyle(
                                      fontFamily: 'monospace',
                                      color: Color(0xFF00FF80)),
                                );
                              },
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildControls() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(8),
        child: Column(
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton.icon(
                  onPressed: _autoMode ? null : _runKernel,
                  icon: const Icon(Icons.play_arrow),
                  label: const Text('Execute'),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: const Color(0xFF0080FF),
                    foregroundColor: Colors.white,
                  ),
                ),
                ElevatedButton.icon(
                  onPressed: () {
                    setState(() {
                      _autoMode = !_autoMode;
                    });
                    if (_autoMode) _runKernel();
                  },
                  icon: Icon(_autoMode ? Icons.pause : Icons.autorenew),
                  label: Text(_autoMode ? 'Stop Auto' : 'Auto Mode'),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: _autoMode
                        ? const Color(0xFFFF4080)
                        : const Color(0xFF00FF80),
                    foregroundColor: Colors.white,
                  ),
                ),
                ElevatedButton.icon(
                  onPressed: _generateInputData,
                  icon: const Icon(Icons.shuffle),
                  label: const Text('Randomize'),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: const Color(0xFF00FFFF),
                    foregroundColor: Colors.black,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 16),
            Row(
              children: [
                Expanded(
                  child: Column(
                    children: [
                      Text('Buffer Size: $_bufferSize',
                          style: const TextStyle(color: Color(0xFF00FFFF))),
                      Slider(
                        min: 64,
                        max: 221184,
                        divisions: 108,
                        value: _bufferSize.toDouble(),
                        activeColor: const Color(0xFF00FFFF),
                        inactiveColor: const Color(0xFF0080FF),
                        onChanged: (value) {
                          setState(() {
                            _bufferSize = value.toInt();
                            _previewLength =
                                _previewLength.clamp(1, _bufferSize);
                          });
                          _createBuffers();
                          _generateInputData();
                        },
                      ),
                    ],
                  ),
                ),
                const SizedBox(width: 16),
                Expanded(
                  child: Column(
                    children: [
                      Text('Preview: $_previewLength',
                          style: const TextStyle(color: Color(0xFF00FFFF))),
                      Slider(
                        min: 8,
                        max: 4096,
                        divisions: 108,
                        value: _previewLength.toDouble(),
                        activeColor: const Color(0xFF00FFFF),
                        inactiveColor: const Color(0xFF0080FF),
                        onChanged: (value) {
                          setState(() {
                            _previewLength =
                                value.toInt().clamp(1, _bufferSize);
                            // No more dangerous sublist operations!
                            // The getters handle safe data access automatically
                          });
                        },
                      ),
                    ],
                  ),
                ),
              ],
            ),
            if (_autoMode)
              Column(
                children: [
                  Text(
                      'Animation Speed: ${_animationSpeed.toStringAsFixed(1)}x',
                      style: const TextStyle(color: Color(0xFF00FFFF))),
                  Slider(
                    min: 0.1,
                    max: 1000.0,
                    value: _animationSpeed,
                    activeColor: const Color(0xFF00FFFF),
                    inactiveColor: const Color(0xFF0080FF),
                    onChanged: (value) {
                      setState(() {
                        _animationSpeed = value;
                      });
                    },
                  ),
                ],
              ),
          ],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Minigpu WebGPU Type Testing Lab'),
        actions: [
          IconButton(
            icon: const FaIcon(FontAwesomeIcons.github),
            tooltip: 'View on GitHub',
            onPressed: () async {
              final Uri url =
                  Uri.parse('https://github.com/PracticalXR/minigpu');
              if (await canLaunchUrl(url)) {
                await launchUrl(url);
              } else {}
            },
          ),
        ],
        bottom: TabBar(
          controller: _tabController,
          labelColor: const Color(0xFF00FFFF),
          unselectedLabelColor: const Color(0xFF0080FF),
          indicatorColor: const Color(0xFF00FFFF),
          tabs: const [
            Tab(icon: Icon(Icons.timeline), text: 'Chart'),
            Tab(icon: Icon(Icons.data_object), text: 'Raw Data'),
          ],
        ),
      ),
      body: Column(
        children: [
          _buildTypeSelector(),
          _buildAlgorithmSelector(),
          Expanded(
            child: TabBarView(
              controller: _tabController,
              children: [
                SingleChildScrollView(
                  padding: const EdgeInsets.all(8),
                  child: _buildVisualizationTab(),
                ),
                SingleChildScrollView(
                  padding: const EdgeInsets.all(8),
                  child: _buildDataTab(),
                ),
              ],
            ),
          ),
          _buildControls(),
        ],
      ),
    );
  }
}

class DataVisualizationPainter extends CustomPainter {
  final List<double> inputData;
  final List<double> outputData;
  final Animation<double> animation;
  final Animation<double> colorAnimation;
  final DataTypeDemo dataType;

  DataVisualizationPainter({
    required this.inputData,
    required this.outputData,
    required this.animation,
    required this.colorAnimation,
    required this.dataType,
  }) : super(repaint: animation);

  static Path? _cachedInputPath;
  static Path? _cachedOutputPath;
  static double _cachedMinVal = 0;
  static double _cachedMaxVal = 0;
  static int _cachedDataHash = 0;
  static Size? _cachedGridSize;
  static Picture? _cachedGrid;

  @override
  void paint(Canvas canvas, Size size) {
    if (inputData.isEmpty && outputData.isEmpty) return;
    if (size.width <= 0 || size.height <= 0) return;

    // Check if we can reuse cached paths
    int currentDataHash = inputData.hashCode ^ outputData.hashCode;
    bool needsRecalculation = currentDataHash != _cachedDataHash;

    if (needsRecalculation) {
      _calculatePaths(size);
      _cachedDataHash = currentDataHash;
    }

    // Draw grid ONLY when size changes
    if (_cachedGridSize != size) {
      _cacheGrid(size);
      _cachedGridSize = size;
    }

    // Draw cached grid
    if (_cachedGrid != null) {
      canvas.drawPicture(_cachedGrid!);
    }

    // Use cached paths for drawing
    final paint = Paint()
      ..strokeWidth = 2
      ..style = PaintingStyle.stroke;

    // Draw paths
    if (_cachedInputPath != null) {
      paint.color = const Color(0xFF0080FF).withValues(alpha: 0.8);
      canvas.drawPath(_cachedInputPath!, paint);
    }

    if (_cachedOutputPath != null) {
      paint.color = const Color(0xFF00FFFF);
      canvas.drawPath(_cachedOutputPath!, paint);
    }

    // Draw fewer animated points (every 4th point)
    _drawAnimatedPoints(canvas, size);
  }

  void _cacheGrid(Size size) {
    final recorder = PictureRecorder();
    final gridCanvas = Canvas(recorder);

    final gridPaint = Paint()
      ..color = const Color(0xFF0080FF).withValues(alpha: .2)
      ..strokeWidth = 1
      ..style = PaintingStyle.stroke;

    const int gridLines = 10;
    final double horizontalSpacing = size.height * 0.8 / gridLines;
    final double verticalSpacing = size.width / gridLines;
    final double yOffset = size.height * 0.1;

    // Draw horizontal lines
    for (int i = 0; i <= gridLines; i++) {
      double y = size.height - (i * horizontalSpacing) - yOffset;
      gridCanvas.drawLine(Offset(0, y), Offset(size.width, y), gridPaint);
    }

    // Draw vertical lines
    for (int i = 0; i <= gridLines; i++) {
      double x = i * verticalSpacing;
      gridCanvas.drawLine(Offset(x, 0), Offset(x, size.height), gridPaint);
    }

    _cachedGrid = recorder.endRecording();
  }

  void _calculatePaths(Size size) {
    // Calculate min/max only when data changes
    List<double> allData = [...inputData, ...outputData];
    if (allData.isEmpty) return;

    _cachedMinVal = allData.reduce((a, b) => a < b ? a : b);
    _cachedMaxVal = allData.reduce((a, b) => a > b ? a : b);

    double range = _cachedMaxVal - _cachedMinVal;
    if (range == 0) range = 1;

    // Build paths once
    _cachedInputPath = _buildPath(inputData, size, _cachedMinVal, range);
    _cachedOutputPath = _buildPath(outputData, size, _cachedMinVal, range);
  }

  Path _buildPath(List<double> data, Size size, double minVal, double range) {
    final path = Path();
    if (data.isEmpty) return path;

    for (int i = 0; i < data.length; i++) {
      final x = (i / (data.length - 1)) * size.width;
      final normalizedValue = (data[i] - minVal) / range;
      final y = size.height -
          (normalizedValue * size.height * 0.8) -
          size.height * 0.1;

      if (i == 0) {
        path.moveTo(x, y);
      } else {
        path.lineTo(x, y);
      }
    }
    return path;
  }

  void _drawAnimatedPoints(Canvas canvas, Size size) {
    // Draw fewer points with animation
    for (int i = 0; i < outputData.length; i += 4) {
      // Every 4th point
      final x = (i / (outputData.length - 1)) * size.width;
      final normalizedValue =
          (outputData[i] - _cachedMinVal) / (_cachedMaxVal - _cachedMinVal);
      final y = size.height -
          (normalizedValue * size.height * 0.8) -
          size.height * 0.1;

      final animationOffset = sin(animation.value * 2 * pi + i * 0.3) * 2;

      canvas.drawCircle(
          Offset(x, y),
          3 + animationOffset,
          Paint()
            ..color = const Color(0xFF00FF80)
            ..style = PaintingStyle.fill);
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
17
likes
130
points
55
downloads

Publisher

verified publisherpracticalxr.com

Weekly Downloads

A library that brings multiplatform GPU compute to Dart and Flutter by wrapping the gpu.cpp library and webgpu with a Dawn backend.

Documentation

API reference

License

MIT (license)

Dependencies

flutter, minigpu_ffi, minigpu_platform_interface, minigpu_web

More

Packages that depend on minigpu