import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import '../../../common/widgets/floating_menu_button.dart'; class VsyncBenchmarkScreen extends StatelessWidget { const VsyncBenchmarkScreen({super.key}); @override Widget build(BuildContext context) { return const Scaffold( body: Stack( children: [ SizedBox( width: double.infinity, height: double.infinity, child: ShaderHomePage(), ), FloatingMenuButton(), ], ), ); } } class ShaderHomePage extends StatefulWidget { const ShaderHomePage({super.key}); @override State createState() => _ShaderHomePageState(); } class _ShaderHomePageState extends State with SingleTickerProviderStateMixin { double delta = 0; FragmentShader? shader; late final Ticker _ticker; void loadMyShader() async { var program = await FragmentProgram.fromAsset('shaders/vsync.frag'); shader = program.fragmentShader(); } @override void initState() { super.initState(); loadMyShader(); _ticker = createTicker((elapsed) { setState(() { delta += 1 / 60; }); }); _ticker.start(); } @override void dispose() { _ticker.dispose(); super.dispose(); } @override Widget build(BuildContext context) { if (shader == null) { return const Center(child: CircularProgressIndicator()); } else { return Container( color: Colors.white, child: CustomPaint(painter: ShaderPainter(shader!, delta))); } } } class ShaderPainter extends CustomPainter { final FragmentShader shader; final double time; ShaderPainter(FragmentShader fragmentShader, this.time) : shader = fragmentShader; @override void paint(Canvas canvas, Size size) { final paint = Paint(); shader.setFloat(0, size.width); shader.setFloat(1, size.height); shader.setFloat(2, time); paint.shader = shader; canvas.drawRect(Offset.zero & size, paint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => true; }