mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Reland: [Impeller] add a configuration option that allows defering all PSO construction until needed. (#165622)
The cost of bootstapping the initial PSOs can regress cold startup time for customer money. As an experiment, attempt to defer PSO construction to skia like. --------- Co-authored-by: Aaron Clarke <aaclarke@google.com> Co-authored-by: gaaclarke <30870216+gaaclarke@users.noreply.github.com>
This commit is contained in:
parent
a4b982738e
commit
31ff6497f1
11
.ci.yaml
11
.ci.yaml
@ -2730,6 +2730,17 @@ targets:
|
||||
["devicelab", "android", "linux"]
|
||||
task_name: flutter_gallery__start_up
|
||||
|
||||
# linux mokey benchmark
|
||||
- name: Linux_mokey flutter_gallery_lazy__start_up
|
||||
recipe: devicelab/devicelab_drone
|
||||
presubmit: false
|
||||
bringup: true
|
||||
timeout: 60
|
||||
properties:
|
||||
tags: >
|
||||
["devicelab", "android", "linux"]
|
||||
task_name: flutter_gallery_lazy__start_up
|
||||
|
||||
# linux mokey benchmark
|
||||
- name: Linux_mokey flutter_gallery__start_up_delayed
|
||||
recipe: devicelab/devicelab_drone
|
||||
|
@ -45,6 +45,7 @@
|
||||
/dev/devicelab/bin/tasks/flutter_gallery__image_cache_memory.dart @jtmcdole @flutter/engine
|
||||
/dev/devicelab/bin/tasks/flutter_gallery__memory_nav.dart @jtmcdole @flutter/engine
|
||||
/dev/devicelab/bin/tasks/flutter_gallery__start_up.dart @jtmcdole @flutter/engine
|
||||
/dev/devicelab/bin/tasks/flutter_gallery_lazy__start_up.dart @jtmcdole @flutter/engine
|
||||
/dev/devicelab/bin/tasks/flutter_gallery__start_up_delayed.dart @jtmcdole @flutter/engine
|
||||
/dev/devicelab/bin/tasks/flutter_gallery__transition_perf.dart @jtmcdole @flutter/engine
|
||||
/dev/devicelab/bin/tasks/flutter_gallery__transition_perf_e2e.dart @jtmcdole @flutter/engine
|
||||
|
12
dev/devicelab/bin/tasks/flutter_gallery_lazy__start_up.dart
Normal file
12
dev/devicelab/bin/tasks/flutter_gallery_lazy__start_up.dart
Normal file
@ -0,0 +1,12 @@
|
||||
// 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 'package:flutter_devicelab/framework/devices.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/tasks/perf_tests.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
deviceOperatingSystem = DeviceOperatingSystem.android;
|
||||
await task(createFlutterGalleryStartupTest(enableLazyShaderMode: true));
|
||||
}
|
@ -270,11 +270,13 @@ TaskFunction createOpenPayScrollPerfTest({bool measureCpuGpu = true}) {
|
||||
TaskFunction createFlutterGalleryStartupTest({
|
||||
String target = 'lib/main.dart',
|
||||
Map<String, String>? runEnvironment,
|
||||
bool enableLazyShaderMode = false,
|
||||
}) {
|
||||
return StartupTest(
|
||||
'${flutterDirectory.path}/dev/integration_tests/flutter_gallery',
|
||||
target: target,
|
||||
runEnvironment: runEnvironment,
|
||||
enableLazyShaderMode: enableLazyShaderMode,
|
||||
).run;
|
||||
}
|
||||
|
||||
@ -840,6 +842,17 @@ void _addVulkanGPUTracingToManifest(String testDirectory) {
|
||||
_addMetadataToManifest(testDirectory, keyPairs);
|
||||
}
|
||||
|
||||
/// Opens the file at testDirectory + 'android/app/src/main/AndroidManifest.xml'
|
||||
/// <meta-data
|
||||
/// android:name="io.flutter.embedding.android.ImpellerShaderMode"
|
||||
/// android:value="lazy" />
|
||||
void _addLazyShaderMode(String testDirectory) {
|
||||
final List<(String, String)> keyPairs = <(String, String)>[
|
||||
('io.flutter.embedding.android.ImpellerLazyShaderInitialization', 'true'),
|
||||
];
|
||||
_addMetadataToManifest(testDirectory, keyPairs);
|
||||
}
|
||||
|
||||
/// Opens the file at testDirectory + 'android/app/src/main/AndroidManifest.xml'
|
||||
/// and adds the following entry to the application.
|
||||
/// <meta-data
|
||||
@ -881,10 +894,12 @@ class StartupTest {
|
||||
this.reportMetrics = true,
|
||||
this.target = 'lib/main.dart',
|
||||
this.runEnvironment,
|
||||
this.enableLazyShaderMode = false,
|
||||
});
|
||||
|
||||
final String testDirectory;
|
||||
final bool reportMetrics;
|
||||
final bool enableLazyShaderMode;
|
||||
final String target;
|
||||
final Map<String, String>? runEnvironment;
|
||||
|
||||
@ -895,144 +910,155 @@ class StartupTest {
|
||||
const int iterations = 5;
|
||||
final List<Map<String, dynamic>> results = <Map<String, dynamic>>[];
|
||||
|
||||
section('Building application');
|
||||
String? applicationBinaryPath;
|
||||
switch (deviceOperatingSystem) {
|
||||
case DeviceOperatingSystem.android:
|
||||
await flutter(
|
||||
'build',
|
||||
options: <String>[
|
||||
'apk',
|
||||
'-v',
|
||||
'--profile',
|
||||
'--target-platform=android-arm,android-arm64',
|
||||
'--target=$target',
|
||||
],
|
||||
);
|
||||
applicationBinaryPath = '$testDirectory/build/app/outputs/flutter-apk/app-profile.apk';
|
||||
case DeviceOperatingSystem.androidArm:
|
||||
await flutter(
|
||||
'build',
|
||||
options: <String>[
|
||||
'apk',
|
||||
'-v',
|
||||
'--profile',
|
||||
'--target-platform=android-arm',
|
||||
'--target=$target',
|
||||
],
|
||||
);
|
||||
applicationBinaryPath = '$testDirectory/build/app/outputs/flutter-apk/app-profile.apk';
|
||||
case DeviceOperatingSystem.androidArm64:
|
||||
await flutter(
|
||||
'build',
|
||||
options: <String>[
|
||||
'apk',
|
||||
'-v',
|
||||
'--profile',
|
||||
'--target-platform=android-arm64',
|
||||
'--target=$target',
|
||||
],
|
||||
);
|
||||
applicationBinaryPath = '$testDirectory/build/app/outputs/flutter-apk/app-profile.apk';
|
||||
case DeviceOperatingSystem.fake:
|
||||
case DeviceOperatingSystem.fuchsia:
|
||||
case DeviceOperatingSystem.linux:
|
||||
break;
|
||||
case DeviceOperatingSystem.ios:
|
||||
case DeviceOperatingSystem.macos:
|
||||
await flutter(
|
||||
'build',
|
||||
options: <String>[
|
||||
if (deviceOperatingSystem == DeviceOperatingSystem.ios) 'ios' else 'macos',
|
||||
'-v',
|
||||
'--profile',
|
||||
'--target=$target',
|
||||
if (deviceOperatingSystem == DeviceOperatingSystem.ios) '--no-publish-port',
|
||||
],
|
||||
);
|
||||
final String buildRoot = path.join(testDirectory, 'build');
|
||||
applicationBinaryPath = _findDarwinAppInBuildDirectory(buildRoot);
|
||||
case DeviceOperatingSystem.windows:
|
||||
await flutter(
|
||||
'build',
|
||||
options: <String>['windows', '-v', '--profile', '--target=$target'],
|
||||
);
|
||||
final String basename = path.basename(testDirectory);
|
||||
final String arch = Abi.current() == Abi.windowsX64 ? 'x64' : 'arm64';
|
||||
applicationBinaryPath = path.join(
|
||||
testDirectory,
|
||||
'build',
|
||||
'windows',
|
||||
arch,
|
||||
'runner',
|
||||
'Profile',
|
||||
'$basename.exe',
|
||||
);
|
||||
if (enableLazyShaderMode) {
|
||||
_addLazyShaderMode(testDirectory);
|
||||
}
|
||||
|
||||
const int maxFailures = 3;
|
||||
int currentFailures = 0;
|
||||
for (int i = 0; i < iterations; i += 1) {
|
||||
// Startup should not take more than a few minutes. After 10 minutes,
|
||||
// take a screenshot to help debug.
|
||||
final Timer timer = Timer(const Duration(minutes: 10), () async {
|
||||
print('Startup not completed within 10 minutes. Taking a screenshot...');
|
||||
await _flutterScreenshot(
|
||||
device.deviceId,
|
||||
'screenshot_startup_${DateTime.now().toLocal().toIso8601String()}.png',
|
||||
);
|
||||
});
|
||||
final int result = await flutter(
|
||||
'run',
|
||||
options: <String>[
|
||||
'--no-android-gradle-daemon',
|
||||
'--no-publish-port',
|
||||
'--verbose',
|
||||
'--profile',
|
||||
'--trace-startup',
|
||||
'--target=$target',
|
||||
'-d',
|
||||
device.deviceId,
|
||||
if (applicationBinaryPath != null) '--use-application-binary=$applicationBinaryPath',
|
||||
],
|
||||
environment: runEnvironment,
|
||||
canFail: true,
|
||||
);
|
||||
timer.cancel();
|
||||
if (result == 0) {
|
||||
final Map<String, dynamic> data =
|
||||
json.decode(
|
||||
file(
|
||||
'${testOutputDirectory(testDirectory)}/start_up_info.json',
|
||||
).readAsStringSync(),
|
||||
)
|
||||
as Map<String, dynamic>;
|
||||
results.add(data);
|
||||
} else {
|
||||
currentFailures += 1;
|
||||
await _flutterScreenshot(
|
||||
device.deviceId,
|
||||
'screenshot_startup_failure_$currentFailures.png',
|
||||
);
|
||||
i -= 1;
|
||||
if (currentFailures == maxFailures) {
|
||||
return TaskResult.failure('Application failed to start $maxFailures times');
|
||||
}
|
||||
try {
|
||||
section('Building application');
|
||||
String? applicationBinaryPath;
|
||||
switch (deviceOperatingSystem) {
|
||||
case DeviceOperatingSystem.android:
|
||||
await flutter(
|
||||
'build',
|
||||
options: <String>[
|
||||
'apk',
|
||||
'-v',
|
||||
'--profile',
|
||||
'--target-platform=android-arm,android-arm64',
|
||||
'--target=$target',
|
||||
],
|
||||
);
|
||||
applicationBinaryPath = '$testDirectory/build/app/outputs/flutter-apk/app-profile.apk';
|
||||
case DeviceOperatingSystem.androidArm:
|
||||
await flutter(
|
||||
'build',
|
||||
options: <String>[
|
||||
'apk',
|
||||
'-v',
|
||||
'--profile',
|
||||
'--target-platform=android-arm',
|
||||
'--target=$target',
|
||||
],
|
||||
);
|
||||
applicationBinaryPath = '$testDirectory/build/app/outputs/flutter-apk/app-profile.apk';
|
||||
case DeviceOperatingSystem.androidArm64:
|
||||
await flutter(
|
||||
'build',
|
||||
options: <String>[
|
||||
'apk',
|
||||
'-v',
|
||||
'--profile',
|
||||
'--target-platform=android-arm64',
|
||||
'--target=$target',
|
||||
],
|
||||
);
|
||||
applicationBinaryPath = '$testDirectory/build/app/outputs/flutter-apk/app-profile.apk';
|
||||
case DeviceOperatingSystem.fake:
|
||||
case DeviceOperatingSystem.fuchsia:
|
||||
case DeviceOperatingSystem.linux:
|
||||
break;
|
||||
case DeviceOperatingSystem.ios:
|
||||
case DeviceOperatingSystem.macos:
|
||||
await flutter(
|
||||
'build',
|
||||
options: <String>[
|
||||
if (deviceOperatingSystem == DeviceOperatingSystem.ios) 'ios' else 'macos',
|
||||
'-v',
|
||||
'--profile',
|
||||
'--target=$target',
|
||||
if (deviceOperatingSystem == DeviceOperatingSystem.ios) '--no-publish-port',
|
||||
],
|
||||
);
|
||||
final String buildRoot = path.join(testDirectory, 'build');
|
||||
applicationBinaryPath = _findDarwinAppInBuildDirectory(buildRoot);
|
||||
case DeviceOperatingSystem.windows:
|
||||
await flutter(
|
||||
'build',
|
||||
options: <String>['windows', '-v', '--profile', '--target=$target'],
|
||||
);
|
||||
final String basename = path.basename(testDirectory);
|
||||
final String arch = Abi.current() == Abi.windowsX64 ? 'x64' : 'arm64';
|
||||
applicationBinaryPath = path.join(
|
||||
testDirectory,
|
||||
'build',
|
||||
'windows',
|
||||
arch,
|
||||
'runner',
|
||||
'Profile',
|
||||
'$basename.exe',
|
||||
);
|
||||
}
|
||||
|
||||
await device.uninstallApp();
|
||||
const int maxFailures = 3;
|
||||
int currentFailures = 0;
|
||||
for (int i = 0; i < iterations; i += 1) {
|
||||
// Startup should not take more than a few minutes. After 10 minutes,
|
||||
// take a screenshot to help debug.
|
||||
final Timer timer = Timer(const Duration(minutes: 10), () async {
|
||||
print('Startup not completed within 10 minutes. Taking a screenshot...');
|
||||
await _flutterScreenshot(
|
||||
device.deviceId,
|
||||
'screenshot_startup_${DateTime.now().toLocal().toIso8601String()}.png',
|
||||
);
|
||||
});
|
||||
final int result = await flutter(
|
||||
'run',
|
||||
options: <String>[
|
||||
'--no-android-gradle-daemon',
|
||||
'--no-publish-port',
|
||||
'--verbose',
|
||||
'--profile',
|
||||
'--trace-startup',
|
||||
'--target=$target',
|
||||
'-d',
|
||||
device.deviceId,
|
||||
if (applicationBinaryPath != null) '--use-application-binary=$applicationBinaryPath',
|
||||
],
|
||||
environment: runEnvironment,
|
||||
canFail: true,
|
||||
);
|
||||
timer.cancel();
|
||||
if (result == 0) {
|
||||
final Map<String, dynamic> data =
|
||||
json.decode(
|
||||
file(
|
||||
'${testOutputDirectory(testDirectory)}/start_up_info.json',
|
||||
).readAsStringSync(),
|
||||
)
|
||||
as Map<String, dynamic>;
|
||||
results.add(data);
|
||||
} else {
|
||||
currentFailures += 1;
|
||||
await _flutterScreenshot(
|
||||
device.deviceId,
|
||||
'screenshot_startup_failure_$currentFailures.png',
|
||||
);
|
||||
i -= 1;
|
||||
if (currentFailures == maxFailures) {
|
||||
return TaskResult.failure('Application failed to start $maxFailures times');
|
||||
}
|
||||
}
|
||||
|
||||
await device.uninstallApp();
|
||||
}
|
||||
|
||||
final Map<String, dynamic> averageResults = _average(results, iterations);
|
||||
|
||||
if (!reportMetrics) {
|
||||
return TaskResult.success(averageResults);
|
||||
}
|
||||
|
||||
return TaskResult.success(
|
||||
averageResults,
|
||||
benchmarkScoreKeys: <String>[
|
||||
'timeToFirstFrameMicros',
|
||||
'timeToFirstFrameRasterizedMicros',
|
||||
],
|
||||
);
|
||||
} finally {
|
||||
await _resetManifest(testDirectory);
|
||||
}
|
||||
|
||||
final Map<String, dynamic> averageResults = _average(results, iterations);
|
||||
|
||||
if (!reportMetrics) {
|
||||
return TaskResult.success(averageResults);
|
||||
}
|
||||
|
||||
return TaskResult.success(
|
||||
averageResults,
|
||||
benchmarkScoreKeys: <String>['timeToFirstFrameMicros', 'timeToFirstFrameRasterizedMicros'],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1180,6 +1206,7 @@ class PerfTest {
|
||||
this.disablePartialRepaint = false,
|
||||
this.enableMergedPlatformThread = false,
|
||||
this.enableSurfaceControl = false,
|
||||
this.enableLazyShaderMode = false,
|
||||
this.createPlatforms = const <String>[],
|
||||
}) : _resultFilename = resultFilename;
|
||||
|
||||
@ -1202,6 +1229,7 @@ class PerfTest {
|
||||
this.disablePartialRepaint = false,
|
||||
this.enableMergedPlatformThread = false,
|
||||
this.enableSurfaceControl = false,
|
||||
this.enableLazyShaderMode = false,
|
||||
this.createPlatforms = const <String>[],
|
||||
}) : saveTraceFile = false,
|
||||
timelineFileName = null,
|
||||
@ -1261,6 +1289,9 @@ class PerfTest {
|
||||
/// Whether to enable SurfaceControl swapchain.
|
||||
final bool enableSurfaceControl;
|
||||
|
||||
/// Whether to defer construction of all PSO objects in the Impeller backend.
|
||||
final bool enableLazyShaderMode;
|
||||
|
||||
/// Number of seconds to time out the test after, allowing debug callbacks to run.
|
||||
final int? timeoutSeconds;
|
||||
|
||||
@ -1359,6 +1390,9 @@ class PerfTest {
|
||||
if (enableSurfaceControl) {
|
||||
_addSurfaceControlSupportToManifest(testDirectory);
|
||||
}
|
||||
if (enableLazyShaderMode) {
|
||||
_addLazyShaderMode(testDirectory);
|
||||
}
|
||||
}
|
||||
if (disablePartialRepaint || enableMergedPlatformThread) {
|
||||
changedPlist = true;
|
||||
|
@ -41560,6 +41560,7 @@ ORIGIN: ../../../flutter/impeller/base/backend_cast.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/base/comparable.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/base/comparable.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/base/config.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/base/flags.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/base/mask.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/base/promise.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/base/promise.h + ../../../flutter/LICENSE
|
||||
@ -44532,6 +44533,7 @@ FILE: ../../../flutter/impeller/base/backend_cast.h
|
||||
FILE: ../../../flutter/impeller/base/comparable.cc
|
||||
FILE: ../../../flutter/impeller/base/comparable.h
|
||||
FILE: ../../../flutter/impeller/base/config.h
|
||||
FILE: ../../../flutter/impeller/base/flags.h
|
||||
FILE: ../../../flutter/impeller/base/mask.h
|
||||
FILE: ../../../flutter/impeller/base/promise.cc
|
||||
FILE: ../../../flutter/impeller/base/promise.h
|
||||
|
@ -228,6 +228,9 @@ struct Settings {
|
||||
// Enable android surface control swapchains where supported.
|
||||
bool enable_surface_control = false;
|
||||
|
||||
// Whether to lazily initialize impeller PSO state.
|
||||
bool impeller_enable_lazy_shader_mode = false;
|
||||
|
||||
// Log a warning during shell initialization if Impeller is not enabled.
|
||||
bool warn_on_impeller_opt_out = false;
|
||||
|
||||
|
@ -14,6 +14,7 @@ impeller_component("base") {
|
||||
"comparable.cc",
|
||||
"comparable.h",
|
||||
"config.h",
|
||||
"flags.h",
|
||||
"mask.h",
|
||||
"promise.cc",
|
||||
"promise.h",
|
||||
|
16
engine/src/flutter/impeller/base/flags.h
Normal file
16
engine/src/flutter/impeller/base/flags.h
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
#ifndef FLUTTER_IMPELLER_BASE_FLAGS_H_
|
||||
#define FLUTTER_IMPELLER_BASE_FLAGS_H_
|
||||
|
||||
namespace impeller {
|
||||
struct Flags {
|
||||
/// Whether to defer PSO construction until first use. Usage Will introduce
|
||||
/// raster jank.
|
||||
bool lazy_shader_mode = false;
|
||||
};
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_BASE_FLAGS_H_
|
@ -216,7 +216,6 @@ void ContentContextOptions::ApplyToPipelineDescriptor(
|
||||
}
|
||||
|
||||
desc.SetPrimitiveType(primitive_type);
|
||||
|
||||
desc.SetPolygonMode(wireframe ? PolygonMode::kLine : PolygonMode::kFill);
|
||||
}
|
||||
|
||||
@ -283,11 +282,13 @@ ContentContext::ContentContext(
|
||||
desc.format = PixelFormat::kR8G8B8A8UNormInt;
|
||||
desc.size = ISize{1, 1};
|
||||
empty_texture_ = GetContext()->GetResourceAllocator()->CreateTexture(desc);
|
||||
auto data = Color::BlackTransparent().ToR8G8B8A8();
|
||||
auto cmd_buffer = GetContext()->CreateCommandBuffer();
|
||||
auto blit_pass = cmd_buffer->CreateBlitPass();
|
||||
auto& host_buffer = GetTransientsBuffer();
|
||||
auto buffer_view = host_buffer.Emplace(data);
|
||||
|
||||
std::array<uint8_t, 4> data = Color::BlackTransparent().ToR8G8B8A8();
|
||||
std::shared_ptr<CommandBuffer> cmd_buffer =
|
||||
GetContext()->CreateCommandBuffer();
|
||||
std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
|
||||
HostBuffer& host_buffer = GetTransientsBuffer();
|
||||
BufferView buffer_view = host_buffer.Emplace(data);
|
||||
blit_pass->AddCopy(buffer_view, empty_texture_);
|
||||
|
||||
if (!blit_pass->EncodeCommands() || !GetContext()
|
||||
@ -383,9 +384,14 @@ ContentContext::ContentContext(
|
||||
}
|
||||
clip_pipeline_descriptor->SetColorAttachmentDescriptors(
|
||||
std::move(clip_color_attachments));
|
||||
clip_pipelines_.SetDefault(
|
||||
options,
|
||||
std::make_unique<ClipPipeline>(*context_, clip_pipeline_descriptor));
|
||||
if (GetContext()->GetFlags().lazy_shader_mode) {
|
||||
clip_pipelines_.SetDefaultDescriptor(clip_pipeline_descriptor);
|
||||
clip_pipelines_.SetDefault(options, nullptr);
|
||||
} else {
|
||||
clip_pipelines_.SetDefault(
|
||||
options,
|
||||
std::make_unique<ClipPipeline>(*context_, clip_pipeline_descriptor));
|
||||
}
|
||||
texture_downsample_pipelines_.CreateDefault(
|
||||
*context_, options_no_msaa_no_depth_stencil);
|
||||
rrect_blur_pipelines_.CreateDefault(*context_, options_trianglestrip);
|
||||
@ -671,7 +677,9 @@ void ContentContext::ClearCachedRuntimeEffectPipeline(
|
||||
}
|
||||
|
||||
void ContentContext::InitializeCommonlyUsedShadersIfNeeded() const {
|
||||
TRACE_EVENT0("flutter", "InitializeCommonlyUsedShadersIfNeeded");
|
||||
if (GetContext()->GetFlags().lazy_shader_mode) {
|
||||
return;
|
||||
}
|
||||
GetContext()->InitializeCommonlyUsedShadersIfNeeded();
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "flutter/fml/status_or.h"
|
||||
@ -521,7 +522,13 @@ class ContentContext {
|
||||
void SetDefault(const ContentContextOptions& options,
|
||||
std::unique_ptr<PipelineHandleT> pipeline) {
|
||||
default_options_ = options;
|
||||
Set(options, std::move(pipeline));
|
||||
if (pipeline) {
|
||||
Set(options, std::move(pipeline));
|
||||
}
|
||||
}
|
||||
|
||||
void SetDefaultDescriptor(std::optional<PipelineDescriptor> desc) {
|
||||
desc_ = std::move(desc);
|
||||
}
|
||||
|
||||
void CreateDefault(const Context& context,
|
||||
@ -534,7 +541,13 @@ class ContentContext {
|
||||
return;
|
||||
}
|
||||
options.ApplyToPipelineDescriptor(*desc);
|
||||
SetDefault(options, std::make_unique<PipelineHandleT>(context, desc));
|
||||
desc_ = desc;
|
||||
if (context.GetFlags().lazy_shader_mode) {
|
||||
SetDefault(options, nullptr);
|
||||
} else {
|
||||
SetDefault(options, std::make_unique<PipelineHandleT>(context, desc_,
|
||||
/*async=*/true));
|
||||
}
|
||||
}
|
||||
|
||||
PipelineHandleT* Get(const ContentContextOptions& options) const {
|
||||
@ -547,16 +560,29 @@ class ContentContext {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PipelineHandleT* GetDefault() const {
|
||||
bool IsDefault(const ContentContextOptions& opts) {
|
||||
return default_options_.has_value() &&
|
||||
opts.ToKey() == default_options_.value().ToKey();
|
||||
}
|
||||
|
||||
PipelineHandleT* GetDefault(const Context& context) {
|
||||
if (!default_options_.has_value()) {
|
||||
return nullptr;
|
||||
}
|
||||
PipelineHandleT* result = Get(default_options_.value());
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
SetDefault(
|
||||
default_options_.value(),
|
||||
std::make_unique<PipelineHandleT>(context, desc_, /*async=*/false));
|
||||
return Get(default_options_.value());
|
||||
}
|
||||
|
||||
size_t GetPipelineCount() const { return pipelines_.size(); }
|
||||
|
||||
private:
|
||||
std::optional<PipelineDescriptor> desc_;
|
||||
std::optional<ContentContextOptions> default_options_;
|
||||
std::vector<std::pair<uint64_t, std::unique_ptr<PipelineHandleT>>>
|
||||
pipelines_;
|
||||
@ -688,7 +714,10 @@ class ContentContext {
|
||||
return found;
|
||||
}
|
||||
|
||||
RenderPipelineHandleT* default_handle = container.GetDefault();
|
||||
RenderPipelineHandleT* default_handle = container.GetDefault(*GetContext());
|
||||
if (container.IsDefault(opts)) {
|
||||
return default_handle;
|
||||
}
|
||||
|
||||
// The default must always be initialized in the constructor.
|
||||
FML_CHECK(default_handle != nullptr);
|
||||
|
@ -134,7 +134,7 @@ std::shared_ptr<Context> PlaygroundImplGLES::GetContext() const {
|
||||
}
|
||||
|
||||
auto context = ContextGLES::Create(
|
||||
std::move(gl), ShaderLibraryMappingsForPlayground(), true);
|
||||
Flags{}, std::move(gl), ShaderLibraryMappingsForPlayground(), true);
|
||||
if (!context) {
|
||||
FML_LOG(ERROR) << "Could not create context.";
|
||||
return nullptr;
|
||||
|
@ -77,8 +77,8 @@ PlaygroundImplMTL::PlaygroundImplMTL(PlaygroundSwitches switches)
|
||||
}
|
||||
|
||||
auto context = ContextMTL::Create(
|
||||
ShaderLibraryMappingsForPlayground(), is_gpu_disabled_sync_switch_,
|
||||
"Playground Library",
|
||||
impeller::Flags{}, ShaderLibraryMappingsForPlayground(),
|
||||
is_gpu_disabled_sync_switch_, "Playground Library",
|
||||
switches.enable_wide_gamut
|
||||
? std::optional<PixelFormat>(PixelFormat::kB10G10R10A10XR)
|
||||
: std::nullopt);
|
||||
|
@ -96,7 +96,7 @@ PlaygroundImplVK::PlaygroundImplVK(PlaygroundSwitches switches)
|
||||
context_settings.fatal_missing_validations =
|
||||
switches_.enable_vulkan_validation;
|
||||
|
||||
auto context_vk = ContextVK::Create(std::move(context_settings));
|
||||
auto context_vk = ContextVK::Create(Flags{}, std::move(context_settings));
|
||||
if (!context_vk || !context_vk->IsValid()) {
|
||||
VALIDATION_LOG << "Could not create Vulkan context in the playground.";
|
||||
return;
|
||||
|
@ -19,17 +19,20 @@
|
||||
namespace impeller {
|
||||
|
||||
std::shared_ptr<ContextGLES> ContextGLES::Create(
|
||||
const Flags& flags,
|
||||
std::unique_ptr<ProcTableGLES> gl,
|
||||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries,
|
||||
bool enable_gpu_tracing) {
|
||||
return std::shared_ptr<ContextGLES>(
|
||||
new ContextGLES(std::move(gl), shader_libraries, enable_gpu_tracing));
|
||||
return std::shared_ptr<ContextGLES>(new ContextGLES(
|
||||
flags, std::move(gl), shader_libraries, enable_gpu_tracing));
|
||||
}
|
||||
|
||||
ContextGLES::ContextGLES(
|
||||
const Flags& flags,
|
||||
std::unique_ptr<ProcTableGLES> gl,
|
||||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_mappings,
|
||||
bool enable_gpu_tracing) {
|
||||
bool enable_gpu_tracing)
|
||||
: Context(flags) {
|
||||
reactor_ = std::make_shared<ReactorGLES>(std::move(gl));
|
||||
if (!reactor_->IsValid()) {
|
||||
VALIDATION_LOG << "Could not create valid reactor.";
|
||||
|
@ -25,6 +25,7 @@ class ContextGLES final : public Context,
|
||||
public std::enable_shared_from_this<ContextGLES> {
|
||||
public:
|
||||
static std::shared_ptr<ContextGLES> Create(
|
||||
const Flags& flags,
|
||||
std::unique_ptr<ProcTableGLES> gl,
|
||||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries,
|
||||
bool enable_gpu_tracing);
|
||||
@ -60,6 +61,7 @@ class ContextGLES final : public Context,
|
||||
bool is_valid_ = false;
|
||||
|
||||
ContextGLES(
|
||||
const Flags& flags,
|
||||
std::unique_ptr<ProcTableGLES> gl,
|
||||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries,
|
||||
bool enable_gpu_tracing);
|
||||
|
@ -67,16 +67,19 @@ class ContextMTL final : public Context,
|
||||
public std::enable_shared_from_this<ContextMTL> {
|
||||
public:
|
||||
static std::shared_ptr<ContextMTL> Create(
|
||||
const Flags& flags,
|
||||
const std::vector<std::string>& shader_library_paths,
|
||||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch);
|
||||
|
||||
static std::shared_ptr<ContextMTL> Create(
|
||||
const Flags& flags,
|
||||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
|
||||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
|
||||
const std::string& label,
|
||||
std::optional<PixelFormat> pixel_format_override = std::nullopt);
|
||||
|
||||
static std::shared_ptr<ContextMTL> Create(
|
||||
const Flags& flags,
|
||||
id<MTLDevice> device,
|
||||
id<MTLCommandQueue> command_queue,
|
||||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
|
||||
@ -178,7 +181,8 @@ class ContextMTL final : public Context,
|
||||
#endif // IMPELLER_DEBUG
|
||||
bool is_valid_ = false;
|
||||
|
||||
ContextMTL(id<MTLDevice> device,
|
||||
ContextMTL(const Flags& flags,
|
||||
id<MTLDevice> device,
|
||||
id<MTLCommandQueue> command_queue,
|
||||
NSArray<id<MTLLibrary>>* shader_libraries,
|
||||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
|
||||
|
@ -86,12 +86,14 @@ static std::unique_ptr<Capabilities> InferMetalCapabilities(
|
||||
}
|
||||
|
||||
ContextMTL::ContextMTL(
|
||||
const Flags& flags,
|
||||
id<MTLDevice> device,
|
||||
id<MTLCommandQueue> command_queue,
|
||||
NSArray<id<MTLLibrary>>* shader_libraries,
|
||||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
|
||||
std::optional<PixelFormat> pixel_format_override)
|
||||
: device_(device),
|
||||
: Context(flags),
|
||||
device_(device),
|
||||
command_queue_(command_queue),
|
||||
is_gpu_disabled_sync_switch_(std::move(is_gpu_disabled_sync_switch)) {
|
||||
// Validate device.
|
||||
@ -235,6 +237,7 @@ static id<MTLCommandQueue> CreateMetalCommandQueue(id<MTLDevice> device) {
|
||||
}
|
||||
|
||||
std::shared_ptr<ContextMTL> ContextMTL::Create(
|
||||
const Flags& flags,
|
||||
const std::vector<std::string>& shader_library_paths,
|
||||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch) {
|
||||
auto device = CreateMetalDevice();
|
||||
@ -243,7 +246,7 @@ std::shared_ptr<ContextMTL> ContextMTL::Create(
|
||||
return nullptr;
|
||||
}
|
||||
auto context = std::shared_ptr<ContextMTL>(new ContextMTL(
|
||||
device, command_queue,
|
||||
flags, device, command_queue,
|
||||
MTLShaderLibraryFromFilePaths(device, shader_library_paths),
|
||||
std::move(is_gpu_disabled_sync_switch)));
|
||||
if (!context->IsValid()) {
|
||||
@ -254,6 +257,7 @@ std::shared_ptr<ContextMTL> ContextMTL::Create(
|
||||
}
|
||||
|
||||
std::shared_ptr<ContextMTL> ContextMTL::Create(
|
||||
const Flags& flags,
|
||||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
|
||||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
|
||||
const std::string& library_label,
|
||||
@ -264,7 +268,7 @@ std::shared_ptr<ContextMTL> ContextMTL::Create(
|
||||
return nullptr;
|
||||
}
|
||||
auto context = std::shared_ptr<ContextMTL>(new ContextMTL(
|
||||
device, command_queue,
|
||||
flags, device, command_queue,
|
||||
MTLShaderLibraryFromFileData(device, shader_libraries_data,
|
||||
library_label),
|
||||
std::move(is_gpu_disabled_sync_switch), pixel_format_override));
|
||||
@ -276,13 +280,14 @@ std::shared_ptr<ContextMTL> ContextMTL::Create(
|
||||
}
|
||||
|
||||
std::shared_ptr<ContextMTL> ContextMTL::Create(
|
||||
const Flags& flags,
|
||||
id<MTLDevice> device,
|
||||
id<MTLCommandQueue> command_queue,
|
||||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
|
||||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
|
||||
const std::string& library_label) {
|
||||
auto context = std::shared_ptr<ContextMTL>(
|
||||
new ContextMTL(device, command_queue,
|
||||
new ContextMTL(flags, device, command_queue,
|
||||
MTLShaderLibraryFromFileData(device, shader_libraries_data,
|
||||
library_label),
|
||||
std::move(is_gpu_disabled_sync_switch)));
|
||||
|
@ -34,7 +34,7 @@ std::shared_ptr<Context> CreateContext() {
|
||||
settings.enable_gpu_tracing = false;
|
||||
settings.enable_surface_control = false;
|
||||
|
||||
return ContextVK::Create(std::move(settings));
|
||||
return ContextVK::Create(impeller::Flags{}, std::move(settings));
|
||||
}
|
||||
|
||||
TEST(AndroidVulkanTest, CanImportRGBA) {
|
||||
|
@ -102,8 +102,9 @@ static std::optional<QueueIndexVK> PickQueue(const vk::PhysicalDevice& device,
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::shared_ptr<ContextVK> ContextVK::Create(Settings settings) {
|
||||
auto context = std::shared_ptr<ContextVK>(new ContextVK());
|
||||
std::shared_ptr<ContextVK> ContextVK::Create(const Flags& flags,
|
||||
Settings settings) {
|
||||
auto context = std::shared_ptr<ContextVK>(new ContextVK(flags));
|
||||
context->Setup(std::move(settings));
|
||||
if (!context->IsValid()) {
|
||||
return nullptr;
|
||||
@ -127,7 +128,8 @@ uint64_t CalculateHash(void* ptr) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ContextVK::ContextVK() : hash_(CalculateHash(this)) {}
|
||||
ContextVK::ContextVK(const Flags& flags)
|
||||
: Context(flags), hash_(CalculateHash(this)) {}
|
||||
|
||||
ContextVK::~ContextVK() {
|
||||
if (device_holder_ && device_holder_->device) {
|
||||
@ -150,16 +152,6 @@ void ContextVK::Setup(Settings settings) {
|
||||
|
||||
raster_message_loop_ = fml::ConcurrentMessageLoop::Create(
|
||||
ChooseThreadCountForWorkers(std::thread::hardware_concurrency()));
|
||||
raster_message_loop_->PostTaskToAllWorkers([]() {
|
||||
// Currently we only use the worker task pool for small parts of a frame
|
||||
// workload, if this changes this setting may need to be adjusted.
|
||||
fml::RequestAffinity(fml::CpuAffinity::kNotPerformance);
|
||||
#ifdef FML_OS_ANDROID
|
||||
if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) {
|
||||
VALIDATION_LOG << "Failed to set Workers task runner priority";
|
||||
}
|
||||
#endif // FML_OS_ANDROID
|
||||
});
|
||||
|
||||
auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER;
|
||||
dispatcher.init(settings.proc_address_callback);
|
||||
|
@ -98,7 +98,8 @@ class ContextVK final : public Context,
|
||||
/// Visible for testing.
|
||||
static size_t ChooseThreadCountForWorkers(size_t hardware_concurrency);
|
||||
|
||||
static std::shared_ptr<ContextVK> Create(Settings settings);
|
||||
static std::shared_ptr<ContextVK> Create(const Flags& flags,
|
||||
Settings settings);
|
||||
|
||||
uint64_t GetHash() const { return hash_; }
|
||||
|
||||
@ -300,7 +301,7 @@ class ContextVK final : public Context,
|
||||
|
||||
bool is_valid_ = false;
|
||||
|
||||
ContextVK();
|
||||
explicit ContextVK(const Flags& flags);
|
||||
|
||||
void Setup(Settings settings);
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
namespace impeller {
|
||||
|
||||
SurfaceContextVK::SurfaceContextVK(const std::shared_ptr<ContextVK>& parent)
|
||||
: parent_(parent) {}
|
||||
: Context(parent->GetFlags()), parent_(parent) {}
|
||||
|
||||
SurfaceContextVK::~SurfaceContextVK() = default;
|
||||
|
||||
|
@ -955,7 +955,8 @@ std::shared_ptr<ContextVK> MockVulkanContextBuilder::Build() {
|
||||
g_format_properties_callback = format_properties_callback_;
|
||||
g_physical_device_properties_callback = physical_properties_callback_;
|
||||
settings.embedder_data = embedder_data_;
|
||||
std::shared_ptr<ContextVK> result = ContextVK::Create(std::move(settings));
|
||||
std::shared_ptr<ContextVK> result =
|
||||
ContextVK::Create(Flags{}, std::move(settings));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ namespace impeller {
|
||||
|
||||
Context::~Context() = default;
|
||||
|
||||
Context::Context() = default;
|
||||
Context::Context(const Flags& flags) : flags_(flags) {}
|
||||
|
||||
bool Context::UpdateOffscreenLayerPixelFormat(PixelFormat format) {
|
||||
return false;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "fml/closure.h"
|
||||
#include "impeller/base/flags.h"
|
||||
#include "impeller/core/allocator.h"
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
@ -245,9 +246,12 @@ class Context {
|
||||
/// @brief Submit the command buffer that renders to the onscreen surface.
|
||||
virtual bool SubmitOnscreen(std::shared_ptr<CommandBuffer> cmd_buffer);
|
||||
|
||||
protected:
|
||||
Context();
|
||||
const Flags& GetFlags() const { return flags_; }
|
||||
|
||||
protected:
|
||||
explicit Context(const Flags& flags);
|
||||
|
||||
Flags flags_;
|
||||
std::vector<std::function<void()>> per_frame_task_;
|
||||
|
||||
private:
|
||||
|
@ -23,13 +23,15 @@ Pipeline<T>::~Pipeline() = default;
|
||||
|
||||
PipelineFuture<PipelineDescriptor> CreatePipelineFuture(
|
||||
const Context& context,
|
||||
std::optional<PipelineDescriptor> desc) {
|
||||
std::optional<PipelineDescriptor> desc,
|
||||
bool async) {
|
||||
if (!context.IsValid()) {
|
||||
return {desc, RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(
|
||||
nullptr)};
|
||||
}
|
||||
|
||||
return context.GetPipelineLibrary()->GetPipeline(std::move(desc));
|
||||
return context.GetPipelineLibrary()->GetPipeline(std::move(desc),
|
||||
/*async=*/async);
|
||||
}
|
||||
|
||||
PipelineFuture<ComputePipelineDescriptor> CreatePipelineFuture(
|
||||
|
@ -90,9 +90,18 @@ using PipelineRef = raw_ptr<Pipeline<PipelineDescriptor>>;
|
||||
extern template class Pipeline<PipelineDescriptor>;
|
||||
extern template class Pipeline<ComputePipelineDescriptor>;
|
||||
|
||||
/// @brief Create a pipeline for the given descriptor.
|
||||
///
|
||||
/// If `async` is true, the compilation is performed on a worker thread. The
|
||||
/// returned future will complete once that work is done. If `async` is false,
|
||||
/// the work is done on the current thread.
|
||||
///
|
||||
/// It is more performant to set async to false than to spawn a
|
||||
/// worker and immediately block on the future completion.
|
||||
PipelineFuture<PipelineDescriptor> CreatePipelineFuture(
|
||||
const Context& context,
|
||||
std::optional<PipelineDescriptor> desc);
|
||||
std::optional<PipelineDescriptor> desc,
|
||||
bool async = true);
|
||||
|
||||
PipelineFuture<ComputePipelineDescriptor> CreatePipelineFuture(
|
||||
const Context& context,
|
||||
@ -116,14 +125,17 @@ class RenderPipelineHandle {
|
||||
using FragmentShader = FragmentShader_;
|
||||
using Builder = PipelineBuilder<VertexShader, FragmentShader>;
|
||||
|
||||
explicit RenderPipelineHandle(const Context& context)
|
||||
explicit RenderPipelineHandle(const Context& context, bool async = true)
|
||||
: RenderPipelineHandle(CreatePipelineFuture(
|
||||
context,
|
||||
Builder::MakeDefaultPipelineDescriptor(context))) {}
|
||||
Builder::MakeDefaultPipelineDescriptor(context),
|
||||
async)) {}
|
||||
|
||||
explicit RenderPipelineHandle(const Context& context,
|
||||
std::optional<PipelineDescriptor> desc)
|
||||
: RenderPipelineHandle(CreatePipelineFuture(context, desc)) {}
|
||||
std::optional<PipelineDescriptor> desc,
|
||||
bool async = true)
|
||||
: RenderPipelineHandle(
|
||||
CreatePipelineFuture(context, desc, /*async=*/async)) {}
|
||||
|
||||
explicit RenderPipelineHandle(PipelineFuture<PipelineDescriptor> future)
|
||||
: pipeline_future_(std::move(future)) {}
|
||||
|
@ -140,6 +140,8 @@ class MockCommandBuffer : public CommandBuffer {
|
||||
|
||||
class MockImpellerContext : public Context {
|
||||
public:
|
||||
MockImpellerContext() : Context(Flags{}) {}
|
||||
|
||||
MOCK_METHOD(Context::BackendType, GetBackendType, (), (const, override));
|
||||
|
||||
MOCK_METHOD(std::string, DescribeGpuModel, (), (const, override));
|
||||
|
@ -27,8 +27,8 @@ ScopedObject<Context> ContextGLES::Create(
|
||||
impeller_framebuffer_blend_shaders_gles_data,
|
||||
impeller_framebuffer_blend_shaders_gles_length),
|
||||
};
|
||||
auto impeller_context = impeller::ContextGLES::Create(std::move(proc_table),
|
||||
shader_mappings, false);
|
||||
auto impeller_context = impeller::ContextGLES::Create(
|
||||
Flags{}, std::move(proc_table), shader_mappings, false);
|
||||
if (!impeller_context) {
|
||||
VALIDATION_LOG << "Could not create Impeller context.";
|
||||
return {};
|
||||
|
@ -28,9 +28,9 @@ CreateShaderLibraryMappings() {
|
||||
|
||||
ScopedObject<Context> ContextMTL::Create() {
|
||||
auto impeller_context =
|
||||
impeller::ContextMTL::Create(CreateShaderLibraryMappings(), //
|
||||
std::make_shared<fml::SyncSwitch>(), //
|
||||
"Impeller" //
|
||||
impeller::ContextMTL::Create(Flags{}, CreateShaderLibraryMappings(), //
|
||||
std::make_shared<fml::SyncSwitch>(), //
|
||||
"Impeller" //
|
||||
);
|
||||
if (!impeller_context) {
|
||||
VALIDATION_LOG << "Could not create Impeller context.";
|
||||
|
@ -53,8 +53,8 @@ ScopedObject<Context> ContextVK::Create(const Settings& settings) {
|
||||
impeller_settings.enable_validation = true;
|
||||
sContextVKProcAddressCallback = settings.instance_proc_address_callback;
|
||||
impeller_settings.proc_address_callback = ContextVKGetInstanceProcAddress;
|
||||
auto impeller_context =
|
||||
impeller::ContextVK::Create(std::move(impeller_settings));
|
||||
auto impeller_context = impeller::ContextVK::Create(
|
||||
impeller::Flags{}, std::move(impeller_settings));
|
||||
sContextVKProcAddressCallback = nullptr;
|
||||
if (!impeller_context) {
|
||||
VALIDATION_LOG << "Could not create Impeller context.";
|
||||
|
@ -40,7 +40,7 @@ namespace impeller {
|
||||
|
||||
class TestImpellerContext : public impeller::Context {
|
||||
public:
|
||||
TestImpellerContext() = default;
|
||||
TestImpellerContext() : impeller::Context(impeller::Flags{}) {}
|
||||
|
||||
BackendType GetBackendType() const override { return BackendType::kMetal; }
|
||||
|
||||
|
@ -61,7 +61,7 @@ ShellTestPlatformViewGL::ShellTestPlatformViewGL(
|
||||
return;
|
||||
}
|
||||
impeller_context_ = impeller::ContextGLES::Create(
|
||||
std::move(gl), ShaderLibraryMappings(), true);
|
||||
impeller::Flags{}, std::move(gl), ShaderLibraryMappings(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -532,6 +532,9 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
|
||||
settings.merged_platform_ui_thread = !command_line.HasOption(
|
||||
FlagForSwitch(Switch::DisableMergedPlatformUIThread));
|
||||
|
||||
settings.impeller_enable_lazy_shader_mode =
|
||||
command_line.HasOption(FlagForSwitch(Switch::ImpellerLazyShaderMode));
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
@ -300,6 +300,10 @@ DEF_SWITCH(DisableMergedPlatformUIThread,
|
||||
DEF_SWITCH(EnableAndroidSurfaceControl,
|
||||
"enable-surface-control",
|
||||
"Enable the SurfaceControl backed swapchain when supported.")
|
||||
DEF_SWITCH(ImpellerLazyShaderMode,
|
||||
"impeller-lazy-shader-mode",
|
||||
"Whether to defer initialization of all required PSOs for the "
|
||||
"Impeller backend. Defaults to false.")
|
||||
DEF_SWITCHES_END
|
||||
|
||||
void PrintUsage(const std::string& executable_name);
|
||||
|
@ -54,7 +54,8 @@ static std::shared_ptr<impeller::ContextMTL> CreateImpellerContext() {
|
||||
impeller_framebuffer_blend_shaders_length),
|
||||
};
|
||||
auto sync_switch = std::make_shared<fml::SyncSwitch>(false);
|
||||
return impeller::ContextMTL::Create(shader_mappings, sync_switch, "Impeller Library");
|
||||
return impeller::ContextMTL::Create(impeller::Flags{}, shader_mappings, sync_switch,
|
||||
"Impeller Library");
|
||||
}
|
||||
|
||||
TEST(GPUSurfaceMetalImpeller, InvalidImpellerContextCreatesCausesSurfaceToBeInvalid) {
|
||||
|
@ -79,7 +79,7 @@ static std::shared_ptr<impeller::Context> CreateImpellerContext(
|
||||
};
|
||||
|
||||
auto context = impeller::ContextGLES::Create(
|
||||
std::move(proc_table),
|
||||
impeller::Flags{}, std::move(proc_table),
|
||||
is_gles3 ? gles3_shader_mappings : gles2_shader_mappings,
|
||||
enable_gpu_tracing);
|
||||
if (!context) {
|
||||
|
@ -36,7 +36,7 @@ TaskRunners MakeTaskRunners(const std::string& thread_label,
|
||||
|
||||
class TestImpellerContext : public impeller::Context {
|
||||
public:
|
||||
TestImpellerContext() {}
|
||||
TestImpellerContext() : Context(impeller::Flags{}) {}
|
||||
|
||||
~TestImpellerContext() {}
|
||||
|
||||
|
@ -49,7 +49,11 @@ static std::shared_ptr<impeller::Context> CreateImpellerContext(
|
||||
settings.enable_gpu_tracing = p_settings.enable_gpu_tracing;
|
||||
settings.enable_surface_control = p_settings.enable_surface_control;
|
||||
|
||||
auto context = impeller::ContextVK::Create(std::move(settings));
|
||||
auto context = impeller::ContextVK::Create(
|
||||
impeller::Flags{
|
||||
.lazy_shader_mode = p_settings.enable_lazy_shader_mode,
|
||||
},
|
||||
std::move(settings));
|
||||
|
||||
if (!p_settings.quiet) {
|
||||
if (context && impeller::CapabilitiesVK::Cast(*context->GetCapabilities())
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "flutter/fml/concurrent_message_loop.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/impeller/display_list/aiks_context.h"
|
||||
#include "flutter/impeller/renderer/backend/vulkan/surface_context_vk.h"
|
||||
#include "flutter/shell/platform/android/android_context_vk_impeller.h"
|
||||
#include "flutter/shell/platform/android/surface/android_native_window.h"
|
||||
|
@ -25,6 +25,7 @@ class AndroidContext {
|
||||
bool enable_validation = false;
|
||||
bool enable_gpu_tracing = false;
|
||||
bool enable_surface_control = false;
|
||||
bool enable_lazy_shader_mode = false;
|
||||
bool quiet = false;
|
||||
};
|
||||
|
||||
|
@ -51,6 +51,8 @@ public class FlutterLoader {
|
||||
"io.flutter.embedding.android.DisableMergedPlatformUIThread";
|
||||
private static final String ENABLE_SURFACE_CONTROL =
|
||||
"io.flutter.embedding.android.EnableSurfaceControl";
|
||||
private static final String IMPELLER_LAZY_SHADER_MODE =
|
||||
"io.flutter.embedding.android.ImpellerLazyShaderInitialization";
|
||||
|
||||
/**
|
||||
* Set whether leave or clean up the VM after the last shell shuts down. It can be set from app's
|
||||
@ -377,6 +379,9 @@ public class FlutterLoader {
|
||||
if (backend != null) {
|
||||
shellArgs.add("--impeller-backend=" + backend);
|
||||
}
|
||||
if (metaData.getBoolean(IMPELLER_LAZY_SHADER_MODE)) {
|
||||
shellArgs.add("--impeller-lazy-shader-mode");
|
||||
}
|
||||
}
|
||||
|
||||
final String leakVM = isLeakVM(metaData) ? "true" : "false";
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "flutter/shell/platform/android/surface_texture_external_texture_gl_skia.h"
|
||||
#include "flutter/shell/platform/android/surface_texture_external_texture_vk_impeller.h"
|
||||
#include "fml/logging.h"
|
||||
#include "impeller/display_list/aiks_context.h"
|
||||
#if IMPELLER_ENABLE_VULKAN // b/258506856 for why this is behind an if
|
||||
#include "flutter/shell/platform/android/android_surface_vk_impeller.h"
|
||||
#include "flutter/shell/platform/android/image_external_texture_vk_impeller.h"
|
||||
@ -52,14 +53,19 @@ AndroidContext::ContextSettings CreateContextSettings(
|
||||
settings.enable_gpu_tracing = p_settings.enable_vulkan_gpu_tracing;
|
||||
settings.enable_validation = p_settings.enable_vulkan_validation;
|
||||
settings.enable_surface_control = p_settings.enable_surface_control;
|
||||
settings.enable_lazy_shader_mode =
|
||||
p_settings.impeller_enable_lazy_shader_mode;
|
||||
return settings;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AndroidSurfaceFactoryImpl::AndroidSurfaceFactoryImpl(
|
||||
const std::shared_ptr<AndroidContext>& context,
|
||||
bool enable_impeller)
|
||||
: android_context_(context), enable_impeller_(enable_impeller) {}
|
||||
bool enable_impeller,
|
||||
bool lazy_shader_mode)
|
||||
: android_context_(context),
|
||||
enable_impeller_(enable_impeller),
|
||||
lazy_shader_mode_(lazy_shader_mode) {}
|
||||
|
||||
AndroidSurfaceFactoryImpl::~AndroidSurfaceFactoryImpl() = default;
|
||||
|
||||
@ -132,8 +138,10 @@ PlatformViewAndroid::PlatformViewAndroid(
|
||||
FML_CHECK(android_context_->IsValid())
|
||||
<< "Could not create surface from invalid Android context.";
|
||||
surface_factory_ = std::make_shared<AndroidSurfaceFactoryImpl>(
|
||||
android_context_, //
|
||||
delegate.OnPlatformViewGetSettings().enable_impeller //
|
||||
android_context_, //
|
||||
delegate.OnPlatformViewGetSettings().enable_impeller, //
|
||||
delegate.OnPlatformViewGetSettings()
|
||||
.impeller_enable_lazy_shader_mode //
|
||||
);
|
||||
android_surface_ = surface_factory_->CreateSurface();
|
||||
android_use_new_platform_view_ =
|
||||
|
@ -26,7 +26,8 @@ namespace flutter {
|
||||
class AndroidSurfaceFactoryImpl : public AndroidSurfaceFactory {
|
||||
public:
|
||||
AndroidSurfaceFactoryImpl(const std::shared_ptr<AndroidContext>& context,
|
||||
bool enable_impeller);
|
||||
bool enable_impeller,
|
||||
bool lazy_shader_mode);
|
||||
|
||||
~AndroidSurfaceFactoryImpl() override;
|
||||
|
||||
@ -35,6 +36,7 @@ class AndroidSurfaceFactoryImpl : public AndroidSurfaceFactory {
|
||||
private:
|
||||
const std::shared_ptr<AndroidContext>& android_context_;
|
||||
const bool enable_impeller_;
|
||||
const bool lazy_shader_mode_;
|
||||
};
|
||||
|
||||
class PlatformViewAndroid final : public PlatformView {
|
||||
|
@ -315,6 +315,35 @@ public class FlutterLoaderTest {
|
||||
assertTrue(arguments.contains(disabledControlArg));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itSetsShaderInitModeFromMetaData() {
|
||||
FlutterJNI mockFlutterJNI = mock(FlutterJNI.class);
|
||||
FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNI);
|
||||
Bundle metaData = new Bundle();
|
||||
metaData.putBoolean("io.flutter.embedding.android.ImpellerLazyShaderInitialization", true);
|
||||
ctx.getApplicationInfo().metaData = metaData;
|
||||
|
||||
FlutterLoader.Settings settings = new FlutterLoader.Settings();
|
||||
assertFalse(flutterLoader.initialized());
|
||||
flutterLoader.startInitialization(ctx, settings);
|
||||
flutterLoader.ensureInitializationComplete(ctx, null);
|
||||
shadowOf(getMainLooper()).idle();
|
||||
|
||||
final String shaderModeArg = "--impeller-lazy-shader-mode";
|
||||
ArgumentCaptor<String[]> shellArgsCaptor = ArgumentCaptor.forClass(String[].class);
|
||||
verify(mockFlutterJNI, times(1))
|
||||
.init(
|
||||
eq(ctx),
|
||||
shellArgsCaptor.capture(),
|
||||
anyString(),
|
||||
anyString(),
|
||||
anyString(),
|
||||
anyLong(),
|
||||
anyInt());
|
||||
List<String> arguments = Arrays.asList(shellArgsCaptor.getValue());
|
||||
assertTrue(arguments.contains(shaderModeArg));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TargetApi(API_LEVELS.API_23)
|
||||
@Config(sdk = API_LEVELS.API_23)
|
||||
|
@ -25,8 +25,8 @@ static std::shared_ptr<impeller::ContextMTL> CreateImpellerContext(
|
||||
std::make_shared<fml::NonOwnedMapping>(impeller_framebuffer_blend_shaders_data,
|
||||
impeller_framebuffer_blend_shaders_length),
|
||||
};
|
||||
return impeller::ContextMTL::Create(shader_mappings, is_gpu_disabled_sync_switch,
|
||||
"Impeller Library");
|
||||
return impeller::ContextMTL::Create(impeller::Flags{}, shader_mappings,
|
||||
is_gpu_disabled_sync_switch, "Impeller Library");
|
||||
}
|
||||
|
||||
@implementation FlutterDarwinContextMetalImpeller
|
||||
|
@ -41,7 +41,8 @@ static std::shared_ptr<impeller::ContextMTL> CreateImpellerContext() {
|
||||
impeller_framebuffer_blend_shaders_length),
|
||||
};
|
||||
auto sync_switch = std::make_shared<fml::SyncSwitch>(false);
|
||||
return impeller::ContextMTL::Create(shader_mappings, sync_switch, "Impeller Library");
|
||||
return impeller::ContextMTL::Create(impeller::Flags{}, shader_mappings, sync_switch,
|
||||
"Impeller Library");
|
||||
}
|
||||
|
||||
@interface TestExternalTexture : NSObject <FlutterTexture>
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "impeller/display_list/aiks_context.h"
|
||||
#include "impeller/entity/gles/entity_shaders_gles.h"
|
||||
#include "impeller/entity/gles/framebuffer_blend_shaders_gles.h"
|
||||
#include "impeller/entity/gles/modern_shaders_gles.h"
|
||||
@ -80,7 +81,8 @@ EmbedderSurfaceGLImpeller::EmbedderSurfaceGLImpeller(
|
||||
}
|
||||
|
||||
impeller_context_ = impeller::ContextGLES::Create(
|
||||
std::move(gl), shader_mappings, /*enable_gpu_tracing=*/false);
|
||||
impeller::Flags{}, std::move(gl), shader_mappings,
|
||||
/*enable_gpu_tracing=*/false);
|
||||
|
||||
if (!impeller_context_) {
|
||||
FML_LOG(ERROR) << "Could not create Impeller context.";
|
||||
|
@ -41,6 +41,7 @@ EmbedderSurfaceMetalImpeller::EmbedderSurfaceMetalImpeller(
|
||||
impeller_framebuffer_blend_shaders_length),
|
||||
};
|
||||
context_ = impeller::ContextMTL::Create(
|
||||
impeller::Flags{},
|
||||
(__bridge id<MTLDevice>)device, // device
|
||||
(__bridge id<MTLCommandQueue>)command_queue, // command_queue
|
||||
shader_mappings, // shader_libraries_data
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "flutter/impeller/entity/vk/framebuffer_blend_shaders_vk.h"
|
||||
#include "flutter/impeller/entity/vk/modern_shaders_vk.h"
|
||||
#include "flutter/shell/gpu/gpu_surface_vulkan.h"
|
||||
#include "impeller/display_list/aiks_context.h"
|
||||
#include "impeller/renderer/backend/vulkan/context_vk.h"
|
||||
#include "include/gpu/ganesh/GrDirectContext.h"
|
||||
#include "shell/gpu/gpu_surface_vulkan_impeller.h"
|
||||
@ -70,7 +71,8 @@ EmbedderSurfaceVulkanImpeller::EmbedderSurfaceVulkanImpeller(
|
||||
}
|
||||
settings.embedder_data = data;
|
||||
|
||||
context_ = impeller::ContextVK::Create(std::move(settings));
|
||||
context_ =
|
||||
impeller::ContextVK::Create(impeller::Flags{}, std::move(settings));
|
||||
if (!context_) {
|
||||
FML_LOG(ERROR) << "Failed to initialize Vulkan Context.";
|
||||
return;
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#if ALLOW_IMPELLER
|
||||
#include <vulkan/vulkan.h> // nogncheck
|
||||
#include "impeller/display_list/aiks_context.h" // nogncheck
|
||||
#include "impeller/entity/vk/entity_shaders_vk.h" // nogncheck
|
||||
#include "impeller/entity/vk/framebuffer_blend_shaders_vk.h" // nogncheck
|
||||
#include "impeller/entity/vk/modern_shaders_vk.h" // nogncheck
|
||||
@ -74,7 +75,10 @@ bool ImpellerVulkanContextHolder::Initialize(bool enable_validation) {
|
||||
context_settings.cache_directory = fml::paths::GetCachesDirectory();
|
||||
context_settings.enable_validation = enable_validation;
|
||||
|
||||
context = impeller::ContextVK::Create(std::move(context_settings));
|
||||
context = impeller::ContextVK::Create(
|
||||
// Enable lazy shader mode for faster test execution as most tests
|
||||
// will never render anything at all.
|
||||
impeller::Flags{.lazy_shader_mode = true}, std::move(context_settings));
|
||||
if (!context || !context->IsValid()) {
|
||||
VALIDATION_LOG << "Could not create Vulkan context.";
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user