windows_gpu_recovery 0.1.0 copy "windows_gpu_recovery: ^0.1.0" to clipboard
windows_gpu_recovery: ^0.1.0 copied to clipboard

PlatformWindows

Flutter Windows plugin that recovers from EGL_CONTEXT_LOST / D3D11 device removed (DXGI_ERROR_DEVICE_REMOVED) after system sleep or GPU driver reset. Uses a sentinel D3D11 device for detection and a V [...]

example/lib/main.dart

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

/// Key used to persist the counter value across GPU recovery restarts.
/// The GPU recovery plugin destroys and recreates the Flutter engine
/// (Dart VM restarts), so in-memory state is lost. SharedPreferences
/// survives because it's stored on disk.
const _kCounterKey = 'gpu_recovery_counter';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'GPU Recovery Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
      ),
      home: const CounterPage(),
    );
  }
}

class CounterPage extends StatefulWidget {
  const CounterPage({super.key});

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _counter = 0;
  bool _recovered = false;
  bool _loading = true;

  @override
  void initState() {
    super.initState();
    _loadState();
  }

  /// On startup, check if we were restarted by GPU recovery.
  /// The C++ side writes a marker file next to the exe before recreation.
  /// If the marker exists, we know this is a recovery restart.
  Future<void> _loadState() async {
    final prefs = await SharedPreferences.getInstance();
    final savedCounter = prefs.getInt(_kCounterKey) ?? 0;

    // Check for recovery marker file written by flutter_window.cpp.
    final exePath = Platform.resolvedExecutable;
    final exeDir = File(exePath).parent.path;
    final markerFile = File('$exeDir/gpu_recovery.marker');
    final recovered = markerFile.existsSync();

    if (recovered) {
      // Delete marker so next normal launch doesn't show the banner.
      markerFile.deleteSync();
    }

    setState(() {
      _counter = savedCounter;
      _recovered = recovered;
      _loading = false;
    });
  }

  /// Increment counter and persist immediately.
  /// When GPU device loss happens, the engine is destroyed and recreated.
  /// The Dart VM restarts from scratch — only disk-persisted state survives.
  void _incrementCounter() {
    setState(() => _counter++);
    _persistCounter();
  }

  /// Save current counter to SharedPreferences.
  Future<void> _persistCounter() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setInt(_kCounterKey, _counter);
  }

  /// Dismiss the recovery banner.
  void _dismissBanner() {
    setState(() => _recovered = false);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('WITH GPU Recovery'),
      ),
      body: Column(
        children: [
          // --- Recovery banner ---
          // Shown after the engine was recreated by the GPU recovery plugin.
          // Proves that state was persisted and restored successfully.
          if (_recovered)
            MaterialBanner(
              content: Text(
                'GPU recovered. Counter restored to $_counter.',
                style: const TextStyle(fontWeight: FontWeight.bold),
              ),
              backgroundColor: Colors.green.shade100,
              actions: [
                TextButton(
                  onPressed: _dismissBanner,
                  child: const Text('DISMISS'),
                ),
              ],
            ),

          // --- Counter display ---
          Expanded(
            child: Center(
              child: _loading
                  ? const CircularProgressIndicator()
                  : Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        const Text('You have pushed the button this many times:'),
                        const SizedBox(height: 8),
                        Text(
                          '$_counter',
                          style: Theme.of(context).textTheme.displayMedium,
                        ),
                        const SizedBox(height: 32),
                        Text(
                          'Try putting the system to sleep.\n'
                          'The counter value will survive GPU recovery.',
                          textAlign: TextAlign.center,
                          style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                                color: Colors.grey,
                              ),
                        ),
                      ],
                    ),
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _loading ? null : _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
1
likes
150
points
9
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter Windows plugin that recovers from EGL_CONTEXT_LOST / D3D11 device removed (DXGI_ERROR_DEVICE_REMOVED) after system sleep or GPU driver reset. Uses a sentinel D3D11 device for detection and a Vectored Exception Handler to safely destroy the dead engine and create a fresh one.

Repository (GitHub)
View/report issues

Topics

#windows #gpu #d3d11 #recovery #plugin

License

MIT (license)

Dependencies

flutter

More

Packages that depend on windows_gpu_recovery

Packages that implement windows_gpu_recovery