Unverified Commit 08fe78ff authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] write SkSL file to local file (#53859)

parent 98e7791e
...@@ -165,6 +165,12 @@ class CommandHelp { ...@@ -165,6 +165,12 @@ class CommandHelp {
'Toggle CanvasKit rendering.', 'Toggle CanvasKit rendering.',
); );
CommandHelpOption _M;
CommandHelpOption get M => _M ??= _makeOption(
'M',
'Write SkSL shaders to a unique file in the project directory.',
);
CommandHelpOption _makeOption(String key, String description, [ CommandHelpOption _makeOption(String key, String description, [
String inParenthesis = '', String inParenthesis = '',
]) { ]) {
......
...@@ -103,6 +103,9 @@ abstract class ResidentWebRunner extends ResidentRunner { ...@@ -103,6 +103,9 @@ abstract class ResidentWebRunner extends ResidentRunner {
/// WebServer device is debuggable when running with --start-paused. /// WebServer device is debuggable when running with --start-paused.
bool get deviceIsDebuggable => device.device is! WebServerDevice || debuggingOptions.startPaused; bool get deviceIsDebuggable => device.device is! WebServerDevice || debuggingOptions.startPaused;
@override
bool get supportsWriteSkSL => false;
bool get _enableDwds => debuggingEnabled; bool get _enableDwds => debuggingEnabled;
ConnectionResult _connectionResult; ConnectionResult _connectionResult;
......
...@@ -20,6 +20,7 @@ import 'base/utils.dart'; ...@@ -20,6 +20,7 @@ import 'base/utils.dart';
import 'build_info.dart'; import 'build_info.dart';
import 'codegen.dart'; import 'codegen.dart';
import 'compile.dart'; import 'compile.dart';
import 'convert.dart';
import 'dart/package_map.dart'; import 'dart/package_map.dart';
import 'devfs.dart'; import 'devfs.dart';
import 'device.dart'; import 'device.dart';
...@@ -673,6 +674,7 @@ abstract class ResidentRunner { ...@@ -673,6 +674,7 @@ abstract class ResidentRunner {
bool get isRunningRelease => debuggingOptions.buildInfo.isRelease; bool get isRunningRelease => debuggingOptions.buildInfo.isRelease;
bool get supportsServiceProtocol => isRunningDebug || isRunningProfile; bool get supportsServiceProtocol => isRunningDebug || isRunningProfile;
bool get supportsCanvasKit => false; bool get supportsCanvasKit => false;
bool get supportsWriteSkSL => supportsServiceProtocol;
// Returns the Uri of the first connected device for mobile, // Returns the Uri of the first connected device for mobile,
// and only connected device for web. // and only connected device for web.
...@@ -740,6 +742,37 @@ abstract class ResidentRunner { ...@@ -740,6 +742,37 @@ abstract class ResidentRunner {
throw Exception('Canvaskit not supported by this runner.'); throw Exception('Canvaskit not supported by this runner.');
} }
/// Write the SkSL shaders to a zip file in build directory.
Future<void> writeSkSL() async {
if (!supportsWriteSkSL) {
throw Exception('writeSkSL is not supported by this runner.');
}
final Map<String, Object> data = await flutterDevices.first.views.first.getSkSLs();
if (data.isEmpty) {
globals.logger.printStatus(
'No data was receieved. To ensure SkSL data can be generated use a '
'physical device then:\n'
' 1. Pass "--cache-sksl" as an argument to flutter run.\n'
' 2. Interact with the application to force shaders to be compiled.\n'
);
return;
}
final File outputFile = globals.fsUtils.getUniqueFile(
globals.fs.currentDirectory,
'flutter',
'sksl',
);
final Device device = flutterDevices.first.device;
final Map<String, Object> manifest = <String, Object>{
'platform': getNameForTargetPlatform(await flutterDevices.first.device.targetPlatform),
'name': device.name,
'engineRevision': globals.flutterVersion.engineRevision,
'data': data,
};
outputFile.writeAsStringSync(json.encode(manifest));
globals.logger.printStatus('Wrote SkSL data to ${outputFile.path}.');
}
/// The resident runner API for interaction with the reloadMethod vmservice /// The resident runner API for interaction with the reloadMethod vmservice
/// request. /// request.
/// ///
...@@ -1094,6 +1127,9 @@ abstract class ResidentRunner { ...@@ -1094,6 +1127,9 @@ abstract class ResidentRunner {
if (supportsCanvasKit){ if (supportsCanvasKit){
commandHelp.k.print(); commandHelp.k.print();
} }
if (supportsWriteSkSL) {
commandHelp.M.print();
}
commandHelp.v.print(); commandHelp.v.print();
// `P` should precede `a` // `P` should precede `a`
commandHelp.P.print(); commandHelp.P.print();
...@@ -1262,6 +1298,12 @@ class TerminalHandler { ...@@ -1262,6 +1298,12 @@ class TerminalHandler {
return true; return true;
} }
return false; return false;
case 'M':
if (residentRunner.supportsWriteSkSL) {
await residentRunner.writeSkSL();
return true;
}
return false;
case 'p': case 'p':
if (residentRunner.supportsServiceProtocol && residentRunner.isRunningDebug) { if (residentRunner.supportsServiceProtocol && residentRunner.isRunningDebug) {
await residentRunner.debugToggleDebugPaintSizeEnabled(); await residentRunner.debugToggleDebugPaintSizeEnabled();
......
...@@ -1530,6 +1530,16 @@ class FlutterView extends ServiceObject { ...@@ -1530,6 +1530,16 @@ class FlutterView extends ServiceObject {
}); });
} }
Future<Map<String, Object>> getSkSLs() async {
final Map<String, dynamic> response = await owner.vmService.vm.invokeRpcRaw(
'_flutter.getSkSLs',
params: <String, dynamic>{
'viewId': id,
},
);
return response['SkSLs'] as Map<String, Object>;
}
bool get hasIsolate => _uiIsolate != null; bool get hasIsolate => _uiIsolate != null;
Future<void> flushUIThreadTasks() async { Future<void> flushUIThreadTasks() async {
......
...@@ -14,6 +14,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; ...@@ -14,6 +14,7 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart' as io; import 'package:flutter_tools/src/base/io.dart' as io;
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/globals.dart' as globals;
...@@ -387,6 +388,8 @@ void main() { ...@@ -387,6 +388,8 @@ void main() {
expect(residentRunner.isRunningDebug, true); expect(residentRunner.isRunningDebug, true);
// does not support CanvasKit // does not support CanvasKit
expect(residentRunner.supportsCanvasKit, false); expect(residentRunner.supportsCanvasKit, false);
// does support SkSL
expect(residentRunner.supportsWriteSkSL, true);
// commands // commands
expect(testLogger.statusText, equals( expect(testLogger.statusText, equals(
<dynamic>[ <dynamic>[
...@@ -406,6 +409,7 @@ void main() { ...@@ -406,6 +409,7 @@ void main() {
commandHelp.p, commandHelp.p,
commandHelp.o, commandHelp.o,
commandHelp.z, commandHelp.z,
commandHelp.M,
commandHelp.v, commandHelp.v,
commandHelp.P, commandHelp.P,
commandHelp.a, commandHelp.a,
...@@ -415,11 +419,42 @@ void main() { ...@@ -415,11 +419,42 @@ void main() {
)); ));
})); }));
test('ResidentRunner does not support CanvasKit', () => testbed.run(() async { test('ResidentRunner does support CanvasKit', () => testbed.run(() async {
expect(() => residentRunner.toggleCanvaskit(), expect(() => residentRunner.toggleCanvaskit(),
throwsA(isA<Exception>())); throwsA(isA<Exception>()));
})); }));
test('ResidentRunner handles writeSkSL returning no data', () => testbed.run(() async {
when(mockFlutterView.getSkSLs()).thenAnswer((Invocation invocation) async {
return <String, Object>{};
});
await residentRunner.writeSkSL();
expect(testLogger.statusText, contains('No data was receieved'));
}));
test('ResidentRunner can write SkSL data to a unique file with engine revision, platform, and device name', () => testbed.run(() async {
when(mockDevice.targetPlatform).thenAnswer((Invocation invocation) async {
return TargetPlatform.android_arm;
});
when(mockDevice.name).thenReturn('test device');
when(mockFlutterView.getSkSLs()).thenAnswer((Invocation invocation) async {
return <String, Object>{
'A': 'B',
};
});
await residentRunner.writeSkSL();
expect(testLogger.statusText, contains('flutter_01.sksl'));
expect(globals.fs.file('flutter_01.sksl'), exists);
expect(json.decode(globals.fs.file('flutter_01.sksl').readAsStringSync()), <String, Object>{
'platform': 'android-arm',
'name': 'test device',
'engineRevision': '42.2', // From FakeFlutterVersion
'data': <String, Object>{'A': 'B'}
});
}));
test('ResidentRunner can take screenshot on debug device', () => testbed.run(() async { test('ResidentRunner can take screenshot on debug device', () => testbed.run(() async {
when(mockDevice.supportsScreenshot).thenReturn(true); when(mockDevice.supportsScreenshot).thenReturn(true);
when(mockDevice.takeScreenshot(any)) when(mockDevice.takeScreenshot(any))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment