From 700fe3d2b0ca92b70f2b6fcdc8064e8610ad8224 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 10 Jan 2023 01:51:40 -0800 Subject: [PATCH] [Impeller Scene] Add SceneC asset importing (#118157) --- packages/flutter_tools/lib/src/artifacts.dart | 7 + packages/flutter_tools/lib/src/asset.dart | 15 ++ .../lib/src/build_system/targets/assets.dart | 13 ++ .../build_system/targets/scene_importer.dart | 156 ++++++++++++++++++ .../flutter_tools/lib/src/bundle_builder.dart | 14 ++ packages/flutter_tools/lib/src/devfs.dart | 63 ++++--- .../lib/src/flutter_manifest.dart | 36 ++-- .../lib/src/isolated/devfs_web.dart | 5 + .../lib/src/resident_runner.dart | 15 ++ packages/flutter_tools/lib/src/run_hot.dart | 15 +- packages/flutter_tools/lib/src/vmservice.dart | 12 ++ .../test/general.shard/hot_test.dart | 3 + .../general.shard/resident_runner_test.dart | 5 + .../resident_web_runner_test.dart | 2 + 14 files changed, 330 insertions(+), 31 deletions(-) create mode 100644 packages/flutter_tools/lib/src/build_system/targets/scene_importer.dart diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index a6e8a8294576..89724dd22db8 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -107,6 +107,8 @@ enum HostArtifact { // The Impeller shader compiler. impellerc, + // The Impeller Scene 3D model importer. + scenec, // Impeller's tessellation library. libtessellator, } @@ -252,6 +254,8 @@ String _hostArtifactToFileName(HostArtifact artifact, Platform platform) { return 'dart_sdk.js.map'; case HostArtifact.impellerc: return 'impellerc$exe'; + case HostArtifact.scenec: + return 'scenec$exe'; case HostArtifact.libtessellator: return 'libtessellator$dll'; } @@ -432,6 +436,7 @@ class CachedArtifacts implements Artifacts { final String artifactFileName = _hostArtifactToFileName(artifact, _platform); return _cache.getArtifactDirectory('usbmuxd').childFile(artifactFileName); case HostArtifact.impellerc: + case HostArtifact.scenec: case HostArtifact.libtessellator: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); final String engineDir = _getEngineArtifactsPath(_currentHostPlatform(_platform, _operatingSystemUtils))!; @@ -866,6 +871,7 @@ class CachedLocalEngineArtifacts implements Artifacts { final String artifactFileName = _hostArtifactToFileName(artifact, _platform); return _cache.getArtifactDirectory('usbmuxd').childFile(artifactFileName); case HostArtifact.impellerc: + case HostArtifact.scenec: case HostArtifact.libtessellator: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); final File file = _fileSystem.file(_fileSystem.path.join(_hostEngineOutPath, artifactFileName)); @@ -1151,6 +1157,7 @@ class CachedLocalWebSdkArtifacts implements Artifacts { case HostArtifact.iproxy: case HostArtifact.skyEnginePath: case HostArtifact.impellerc: + case HostArtifact.scenec: case HostArtifact.libtessellator: return _parent.getHostArtifact(artifact); } diff --git a/packages/flutter_tools/lib/src/asset.dart b/packages/flutter_tools/lib/src/asset.dart index ea0104f8ef44..81dd56d75e3d 100644 --- a/packages/flutter_tools/lib/src/asset.dart +++ b/packages/flutter_tools/lib/src/asset.dart @@ -70,6 +70,7 @@ enum AssetKind { regular, font, shader, + model, } abstract class AssetBundle { @@ -772,6 +773,20 @@ class ManifestAssetBundle implements AssetBundle { } } + for (final Uri modelUri in flutterManifest.models) { + _parseAssetFromFile( + packageConfig, + flutterManifest, + assetBase, + cache, + result, + modelUri, + packageName: packageName, + attributedPackage: attributedPackage, + assetKind: AssetKind.model, + ); + } + // Add assets referenced in the fonts section of the manifest. for (final Font font in flutterManifest.fonts) { for (final FontAsset fontAsset in font.fontAssets) { diff --git a/packages/flutter_tools/lib/src/build_system/targets/assets.dart b/packages/flutter_tools/lib/src/build_system/targets/assets.dart index 6fdf81bd130b..0abda65ccb76 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/assets.dart @@ -14,6 +14,7 @@ import '../build_system.dart'; import '../depfile.dart'; import 'common.dart'; import 'icon_tree_shaker.dart'; +import 'scene_importer.dart'; import 'shader_compiler.dart'; /// A helper function to copy an asset bundle into an [environment]'s output @@ -84,6 +85,12 @@ Future copyAssets( fileSystem: environment.fileSystem, artifacts: environment.artifacts, ); + final SceneImporter sceneImporter = SceneImporter( + processManager: environment.processManager, + logger: environment.logger, + fileSystem: environment.fileSystem, + artifacts: environment.artifacts, + ); final Map assetEntries = { ...assetBundle.entries, @@ -131,6 +138,12 @@ Future copyAssets( json: targetPlatform == TargetPlatform.web_javascript, ); break; + case AssetKind.model: + doCopy = !await sceneImporter.importScene( + input: content.file as File, + outputPath: file.path, + ); + break; } if (doCopy) { await (content.file as File).copy(file.path); diff --git a/packages/flutter_tools/lib/src/build_system/targets/scene_importer.dart b/packages/flutter_tools/lib/src/build_system/targets/scene_importer.dart new file mode 100644 index 000000000000..1c10dfcd78fa --- /dev/null +++ b/packages/flutter_tools/lib/src/build_system/targets/scene_importer.dart @@ -0,0 +1,156 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:meta/meta.dart'; +import 'package:pool/pool.dart'; +import 'package:process/process.dart'; + +import '../../artifacts.dart'; +import '../../base/error_handling_io.dart'; +import '../../base/file_system.dart'; +import '../../base/io.dart'; +import '../../base/logger.dart'; +import '../../convert.dart'; +import '../../devfs.dart'; +import '../build_system.dart'; + +/// A wrapper around [SceneImporter] to support hot reload of 3D models. +class DevelopmentSceneImporter { + DevelopmentSceneImporter({ + required SceneImporter sceneImporter, + required FileSystem fileSystem, + @visibleForTesting math.Random? random, + }) : _sceneImporter = sceneImporter, + _fileSystem = fileSystem, + _random = random ?? math.Random(); + + final SceneImporter _sceneImporter; + final FileSystem _fileSystem; + final Pool _compilationPool = Pool(4); + final math.Random _random; + + /// Recompile the input ipscene and return a devfs content that should be + /// synced to the attached device in its place. + Future reimportScene(DevFSContent inputScene) async { + final File output = _fileSystem.systemTempDirectory.childFile('${_random.nextDouble()}.temp'); + late File inputFile; + bool cleanupInput = false; + Uint8List result; + PoolResource? resource; + try { + resource = await _compilationPool.request(); + if (inputScene is DevFSFileContent) { + inputFile = inputScene.file as File; + } else { + inputFile = _fileSystem.systemTempDirectory.childFile('${_random.nextDouble()}.temp'); + inputFile.writeAsBytesSync(await inputScene.contentsAsBytes()); + cleanupInput = true; + } + final bool success = await _sceneImporter.importScene( + input: inputFile, + outputPath: output.path, + fatal: false, + ); + if (!success) { + return null; + } + result = output.readAsBytesSync(); + } finally { + resource?.release(); + ErrorHandlingFileSystem.deleteIfExists(output); + if (cleanupInput) { + ErrorHandlingFileSystem.deleteIfExists(inputFile); + } + } + return DevFSByteContent(result); + } +} + +/// A class the wraps the functionality of the Impeller Scene importer scenec. +class SceneImporter { + SceneImporter({ + required ProcessManager processManager, + required Logger logger, + required FileSystem fileSystem, + required Artifacts artifacts, + }) : _processManager = processManager, + _logger = logger, + _fs = fileSystem, + _artifacts = artifacts; + + final ProcessManager _processManager; + final Logger _logger; + final FileSystem _fs; + final Artifacts _artifacts; + + /// The [Source] inputs that targets using this should depend on. + /// + /// See [Target.inputs]. + static const List inputs = [ + Source.pattern( + '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/scene_importer.dart'), + Source.hostArtifact(HostArtifact.scenec), + ]; + + /// Calls scenec, which transforms the [input] 3D model into an imported + /// ipscene at [outputPath]. + /// + /// All parameters are required. + /// + /// If the scene importer subprocess fails, it will print the stdout and + /// stderr to the log and throw a [SceneImporterException]. Otherwise, it + /// will return true. + Future importScene({ + required File input, + required String outputPath, + bool fatal = true, + }) async { + final File scenec = _fs.file( + _artifacts.getHostArtifact(HostArtifact.scenec), + ); + if (!scenec.existsSync()) { + throw SceneImporterException._( + 'The scenec utility is missing at "${scenec.path}". ' + 'Run "flutter doctor".', + ); + } + + final List cmd = [ + scenec.path, + '--input=${input.path}', + '--output=$outputPath', + ]; + _logger.printTrace('scenec command: $cmd'); + final Process scenecProcess = await _processManager.start(cmd); + final int code = await scenecProcess.exitCode; + if (code != 0) { + final String stdout = await utf8.decodeStream(scenecProcess.stdout); + final String stderr = await utf8.decodeStream(scenecProcess.stderr); + _logger.printTrace(stdout); + _logger.printError(stderr); + if (fatal) { + throw SceneImporterException._( + 'Scene import of "${input.path}" to "$outputPath" ' + 'failed with exit code $code.\n' + 'scenec stdout:\n$stdout\n' + 'scenec stderr:\n$stderr', + ); + } + return false; + } + return true; + } +} + +class SceneImporterException implements Exception { + SceneImporterException._(this.message); + + final String message; + + @override + String toString() => 'SceneImporterException: $message\n\n'; +} diff --git a/packages/flutter_tools/lib/src/bundle_builder.dart b/packages/flutter_tools/lib/src/bundle_builder.dart index e14a685b7675..6b055c47467c 100644 --- a/packages/flutter_tools/lib/src/bundle_builder.dart +++ b/packages/flutter_tools/lib/src/bundle_builder.dart @@ -13,6 +13,7 @@ import 'build_info.dart'; import 'build_system/build_system.dart'; import 'build_system/depfile.dart'; import 'build_system/targets/common.dart'; +import 'build_system/targets/scene_importer.dart'; import 'build_system/targets/shader_compiler.dart'; import 'bundle.dart'; import 'cache.dart'; @@ -158,6 +159,13 @@ Future writeBundle( artifacts: globals.artifacts!, ); + final SceneImporter sceneImporter = SceneImporter( + processManager: globals.processManager, + logger: globals.logger, + fileSystem: globals.fs, + artifacts: globals.artifacts!, + ); + // Limit number of open files to avoid running out of file descriptors. final Pool pool = Pool(64); await Future.wait( @@ -189,6 +197,12 @@ Future writeBundle( json: targetPlatform == TargetPlatform.web_javascript, ); break; + case AssetKind.model: + doCopy = !await sceneImporter.importScene( + input: input, + outputPath: file.path, + ); + break; } if (doCopy) { input.copySync(file.path); diff --git a/packages/flutter_tools/lib/src/devfs.dart b/packages/flutter_tools/lib/src/devfs.dart index 2f4cac0fd67a..0e4c5128b9a6 100644 --- a/packages/flutter_tools/lib/src/devfs.dart +++ b/packages/flutter_tools/lib/src/devfs.dart @@ -15,6 +15,7 @@ import 'base/logger.dart'; import 'base/net.dart'; import 'base/os.dart'; import 'build_info.dart'; +import 'build_system/targets/scene_importer.dart'; import 'build_system/targets/shader_compiler.dart'; import 'compile.dart'; import 'convert.dart' show base64, utf8; @@ -483,6 +484,7 @@ class DevFS { final Directory? rootDirectory; final Set assetPathsToEvict = {}; final Set shaderPathsToEvict = {}; + final Set scenePathsToEvict = {}; // A flag to indicate whether we have called `setAssetDirectory` on the target device. bool hasSetAssetDirectory = false; @@ -582,6 +584,7 @@ class DevFS { required PackageConfig packageConfig, required String dillOutputPath, required DevelopmentShaderCompiler shaderCompiler, + DevelopmentSceneImporter? sceneImporter, DevFSWriter? devFSWriter, String? target, AssetBundle? bundle, @@ -600,8 +603,8 @@ class DevFS { // Update modified files final Map dirtyEntries = {}; - final List> pendingShaderCompiles = >[]; - bool shaderCompilationFailed = false; + final List> pendingAssetBuilds = >[]; + bool assetBuildFailed = false; int syncedBytes = 0; if (fullRestart) { generator.reset(); @@ -656,26 +659,48 @@ class DevFS { didUpdateFontManifest = true; } - if (bundle.entryKinds[archivePath] == AssetKind.shader) { - final Future pending = shaderCompiler.recompileShader(content); - pendingShaderCompiles.add(pending); - pending.then((DevFSContent? content) { - if (content == null) { - shaderCompilationFailed = true; - return; + switch (bundle.entryKinds[archivePath]) { + case AssetKind.shader: + final Future pending = shaderCompiler.recompileShader(content); + pendingAssetBuilds.add(pending); + pending.then((DevFSContent? content) { + if (content == null) { + assetBuildFailed = true; + return; + } + dirtyEntries[deviceUri] = content; + syncedBytes += content.size; + if (archivePath != null && !bundleFirstUpload) { + shaderPathsToEvict.add(archivePath); + } + }); + break; + case AssetKind.model: + if (sceneImporter == null) { + break; } + final Future pending = sceneImporter.reimportScene(content); + pendingAssetBuilds.add(pending); + pending.then((DevFSContent? content) { + if (content == null) { + assetBuildFailed = true; + return; + } + dirtyEntries[deviceUri] = content; + syncedBytes += content.size; + if (archivePath != null && !bundleFirstUpload) { + scenePathsToEvict.add(archivePath); + } + }); + break; + case AssetKind.regular: + case AssetKind.font: + case null: dirtyEntries[deviceUri] = content; syncedBytes += content.size; if (archivePath != null && !bundleFirstUpload) { - shaderPathsToEvict.add(archivePath); + assetPathsToEvict.add(archivePath); } - }); - } else { - dirtyEntries[deviceUri] = content; - syncedBytes += content.size; - if (archivePath != null && !bundleFirstUpload) { - assetPathsToEvict.add(archivePath); - } } }); @@ -707,8 +732,8 @@ class DevFS { _logger.printTrace('Updating files.'); final Stopwatch transferTimer = _stopwatchFactory.createStopwatch('transfer')..start(); - await Future.wait(pendingShaderCompiles); - if (shaderCompilationFailed) { + await Future.wait(pendingAssetBuilds); + if (assetBuildFailed) { return UpdateFSReport(); } diff --git a/packages/flutter_tools/lib/src/flutter_manifest.dart b/packages/flutter_tools/lib/src/flutter_manifest.dart index 37753b65b070..e24a93329599 100644 --- a/packages/flutter_tools/lib/src/flutter_manifest.dart +++ b/packages/flutter_tools/lib/src/flutter_manifest.dart @@ -13,6 +13,9 @@ import 'base/user_messages.dart'; import 'base/utils.dart'; import 'plugins.dart'; +/// Whether or not Impeller Scene 3D model import is enabled. +const bool kIs3dSceneSupported = true; + const Set _kValidPluginPlatforms = { 'android', 'ios', 'web', 'windows', 'linux', 'macos', }; @@ -370,28 +373,28 @@ class FlutterManifest { return fonts; } + late final List shaders = _extractAssetUris('shaders', 'Shader'); + late final List models = kIs3dSceneSupported ? _extractAssetUris('models', 'Model') : []; - late final List shaders = _extractShaders(); - - List _extractShaders() { - if (!_flutterDescriptor.containsKey('shaders')) { + List _extractAssetUris(String key, String singularName) { + if (!_flutterDescriptor.containsKey(key)) { return []; } - final List? shaders = _flutterDescriptor['shaders'] as List?; - if (shaders == null) { + final List? items = _flutterDescriptor[key] as List?; + if (items == null) { return const []; } final List results = []; - for (final Object? shader in shaders) { - if (shader is! String || shader == null || shader == '') { - _logger.printError('Shader manifest contains a null or empty uri.'); + for (final Object? item in items) { + if (item is! String || item == null || item == '') { + _logger.printError('$singularName manifest contains a null or empty uri.'); continue; } try { - results.add(Uri(pathSegments: shader.split('/'))); + results.add(Uri(pathSegments: item.split('/'))); } on FormatException { - _logger.printError('Shader manifest contains invalid uri: $shader.'); + _logger.printError('$singularName manifest contains invalid uri: $item.'); } } return results; @@ -545,6 +548,17 @@ void _validateFlutter(YamlMap? yaml, List errors) { ); } break; + case 'models': + if (yamlValue is! YamlList) { + errors.add('Expected "$yamlKey" to be a list, but got $yamlValue (${yamlValue.runtimeType}).'); + } else if (yamlValue.isEmpty) { + break; + } else if (yamlValue[0] is! String) { + errors.add( + 'Expected "$yamlKey" to be a list of strings, but the first element is $yamlValue (${yamlValue.runtimeType}).', + ); + } + break; case 'fonts': if (yamlValue is! YamlList) { errors.add('Expected "$yamlKey" to be a list, but got $yamlValue (${yamlValue.runtimeType}).'); diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart index 6ba31f4b79c2..3f4db028d9b1 100644 --- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart +++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart @@ -27,6 +27,7 @@ import '../base/logger.dart'; import '../base/net.dart'; import '../base/platform.dart'; import '../build_info.dart'; +import '../build_system/targets/scene_importer.dart'; import '../build_system/targets/shader_compiler.dart'; import '../build_system/targets/web.dart'; import '../bundle_builder.dart'; @@ -816,6 +817,7 @@ class WebDevFS implements DevFS { required PackageConfig packageConfig, required String dillOutputPath, required DevelopmentShaderCompiler shaderCompiler, + DevelopmentSceneImporter? sceneImporter, DevFSWriter? devFSWriter, String? target, AssetBundle? bundle, @@ -968,6 +970,9 @@ class WebDevFS implements DevFS { @override Set get shaderPathsToEvict => {}; + + @override + Set get scenePathsToEvict => {}; } class ReleaseAssetServer { diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 0ab91c700a50..27fa9b1c444e 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -26,6 +26,7 @@ import 'build_info.dart'; import 'build_system/build_system.dart'; import 'build_system/targets/dart_plugin_registrant.dart'; import 'build_system/targets/localizations.dart'; +import 'build_system/targets/scene_importer.dart'; import 'build_system/targets/shader_compiler.dart'; import 'bundle.dart'; import 'cache.dart'; @@ -51,6 +52,7 @@ class FlutterDevice { ResidentCompiler? generator, this.userIdentifier, required this.developmentShaderCompiler, + this.developmentSceneImporter, }) : assert(buildInfo.trackWidgetCreation != null), generator = generator ?? ResidentCompiler( globals.artifacts!.getArtifactPath( @@ -99,6 +101,16 @@ class FlutterDevice { fileSystem: globals.fs, ); + final DevelopmentSceneImporter sceneImporter = DevelopmentSceneImporter( + sceneImporter: SceneImporter( + artifacts: globals.artifacts!, + logger: globals.logger, + processManager: globals.processManager, + fileSystem: globals.fs, + ), + fileSystem: globals.fs, + ); + // For both web and non-web platforms we initialize dill to/from // a shared location for faster bootstrapping. If the compiler fails // due to a kernel target or version mismatch, no error is reported @@ -200,6 +212,7 @@ class FlutterDevice { buildInfo: buildInfo, userIdentifier: userIdentifier, developmentShaderCompiler: shaderCompiler, + developmentSceneImporter: sceneImporter, ); } @@ -209,6 +222,7 @@ class FlutterDevice { final BuildInfo buildInfo; final String? userIdentifier; final DevelopmentShaderCompiler developmentShaderCompiler; + final DevelopmentSceneImporter? developmentSceneImporter; DevFSWriter? devFSWriter; Stream? observatoryUris; @@ -584,6 +598,7 @@ class FlutterDevice { packageConfig: packageConfig, devFSWriter: devFSWriter, shaderCompiler: developmentShaderCompiler, + sceneImporter: developmentSceneImporter, dartPluginRegistrant: FlutterProject.current().dartPluginRegistrant, ); } on DevFSException { diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 2c26dfe66fa6..79340e7f9f39 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -507,6 +507,7 @@ class HotRunner extends ResidentRunner { } devFS.assetPathsToEvict.clear(); devFS.shaderPathsToEvict.clear(); + devFS.scenePathsToEvict.clear(); } } @@ -1044,7 +1045,9 @@ class HotRunner extends ResidentRunner { Future evictDirtyAssets() async { final List> futures = >[]; for (final FlutterDevice? device in flutterDevices) { - if (device!.devFS!.assetPathsToEvict.isEmpty && device.devFS!.shaderPathsToEvict.isEmpty) { + if (device!.devFS!.assetPathsToEvict.isEmpty && + device.devFS!.shaderPathsToEvict.isEmpty && + device.devFS!.scenePathsToEvict.isEmpty) { continue; } final List views = await device.vmService!.getFlutterViews(); @@ -1096,8 +1099,18 @@ class HotRunner extends ResidentRunner { ) ); } + for (final String assetPath in device.devFS!.scenePathsToEvict) { + futures.add( + device.vmService! + .flutterEvictScene( + assetPath, + isolateId: views.first.uiIsolate!.id!, + ) + ); + } device.devFS!.assetPathsToEvict.clear(); device.devFS!.shaderPathsToEvict.clear(); + device.devFS!.scenePathsToEvict.clear(); } await Future.wait(futures); } diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index 423e4a58aafa..47a057721da4 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart @@ -739,6 +739,18 @@ class FlutterVmService { ); } + Future?> flutterEvictScene(String assetPath, { + required String isolateId, + }) { + return invokeFlutterExtensionRpcRaw( + 'ext.ui.window.reinitializeScene', + isolateId: isolateId, + args: { + 'assetKey': assetPath, + }, + ); + } + /// Exit the application by calling [exit] from `dart:io`. /// diff --git a/packages/flutter_tools/test/general.shard/hot_test.dart b/packages/flutter_tools/test/general.shard/hot_test.dart index 7c1f3b986a6d..d20d814e91e4 100644 --- a/packages/flutter_tools/test/general.shard/hot_test.dart +++ b/packages/flutter_tools/test/general.shard/hot_test.dart @@ -571,6 +571,9 @@ class FakeDevFs extends Fake implements DevFS { @override Set shaderPathsToEvict= {}; + @override + Set scenePathsToEvict= {}; + @override Uri? baseUri; } diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 67747d490e0b..a7f212a7cad4 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -18,6 +18,7 @@ import 'package:flutter_tools/src/base/io.dart' as io; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/targets/scene_importer.dart'; import 'package:flutter_tools/src/build_system/targets/shader_compiler.dart'; import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/convert.dart'; @@ -2694,6 +2695,9 @@ class FakeDevFS extends Fake implements DevFS { @override Set shaderPathsToEvict = {}; + @override + Set scenePathsToEvict = {}; + @override bool didUpdateFontManifest = false; @@ -2722,6 +2726,7 @@ class FakeDevFS extends Fake implements DevFS { required PackageConfig packageConfig, required String dillOutputPath, required DevelopmentShaderCompiler shaderCompiler, + DevelopmentSceneImporter? sceneImporter, DevFSWriter? devFSWriter, String? target, AssetBundle? bundle, diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 3d3c5db10607..c5baa2b64006 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -16,6 +16,7 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/time.dart'; import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/targets/scene_importer.dart'; import 'package:flutter_tools/src/build_system/targets/shader_compiler.dart'; import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/devfs.dart'; @@ -1401,6 +1402,7 @@ class FakeWebDevFS extends Fake implements WebDevFS { required PackageConfig packageConfig, required String dillOutputPath, required DevelopmentShaderCompiler shaderCompiler, + DevelopmentSceneImporter? sceneImporter, DevFSWriter? devFSWriter, String? target, AssetBundle? bundle,