Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] update fallback and rendering state to combine impeller + android backend. #51008

Merged
merged 7 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions common/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@

namespace flutter {

// The combination of targeted graphics API and Impeller support.
enum class AndroidRenderingAPI {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Android"RenderingAPI going in common is unfortunate. I suppose no more so that common itself. Couldn't this go in //flutter/shell/common instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not unless common/settings.h can import flutter/common.

kSoftware,
kImpellerOpenGLES,
kImpellerVulkan,
kSkiaOpenGLES
};

class FrameTiming {
public:
enum Phase {
Expand Down Expand Up @@ -221,8 +229,12 @@ struct Settings {
bool enable_impeller = false;
#endif

// Requests a particular backend to be used (ex "opengles" or "vulkan")
std::optional<std::string> impeller_backend;
// The selected Android rendering API.
AndroidRenderingAPI android_rendering_api =
AndroidRenderingAPI::kSkiaOpenGLES;

// Requests a specific rendering backend.
std::optional<std::string> requested_rendering_backend;

// Enable Vulkan validation on backends that support it. The validation layers
// must be available to the application.
Expand Down
1 change: 0 additions & 1 deletion fml/message_loop.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class MessageLoopImpl;
/// \see fml::Wakeable
class MessageLoop {
public:
FML_EMBEDDER_ONLY
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chinmaygarde not sure what to do here. This macro is flagging usages of this API in flutter_main.cc, it looks like those hadn't been touched in a while. Is there an alternatie usage of this API I can switch to?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the GetCurrent cannot be supported in all configurations because the thread or embedder may not have the ability to fetch the thread local task runner and instead must already have a handle to its task runner. So this is warning (via deprecation tags) that the API may only be used on embedder that have known safe access to the TLS message loop.

If the embedder knows that it is safe to access the TLS message loop slot, it can #define FML_USED_ON_EMBEDDER to make this available. flutter_main.cc should already have this and you shouldn't have to mess with this here.

Ideally, we should get rid of GetCurrent altogether but that is a migration.

static MessageLoop& GetCurrent();

void Run();
Expand Down
2 changes: 1 addition & 1 deletion shell/common/switches.cc
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
if (command_line.GetOptionValue(FlagForSwitch(Switch::ImpellerBackend),
&impeller_backend_value)) {
if (!impeller_backend_value.empty()) {
settings.impeller_backend = impeller_backend_value;
settings.requested_rendering_backend = impeller_backend_value;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion shell/platform/android/android_context_gl_impeller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static std::shared_ptr<impeller::Context> CreateImpellerContext(
AndroidContextGLImpeller::AndroidContextGLImpeller(
std::unique_ptr<impeller::egl::Display> display,
bool enable_gpu_tracing)
: AndroidContext(AndroidRenderingAPI::kOpenGLES),
: AndroidContext(AndroidRenderingAPI::kImpellerOpenGLES),
reactor_worker_(std::shared_ptr<ReactorWorker>(new ReactorWorker())),
display_(std::move(display)) {
if (!display_ || !display_->IsValid()) {
Expand Down
3 changes: 1 addition & 2 deletions shell/platform/android/android_context_gl_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,10 @@ static bool TeardownContext(EGLDisplay display, EGLContext context) {
}

AndroidContextGLSkia::AndroidContextGLSkia(
AndroidRenderingAPI rendering_api,
fml::RefPtr<AndroidEnvironmentGL> environment,
const TaskRunners& task_runners,
uint8_t msaa_samples)
: AndroidContext(AndroidRenderingAPI::kOpenGLES),
: AndroidContext(AndroidRenderingAPI::kSkiaOpenGLES),
environment_(std::move(environment)),
task_runners_(task_runners) {
if (!environment_->IsValid()) {
Expand Down
3 changes: 1 addition & 2 deletions shell/platform/android/android_context_gl_skia.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ class AndroidEGLSurface;
///
class AndroidContextGLSkia : public AndroidContext {
public:
AndroidContextGLSkia(AndroidRenderingAPI rendering_api,
fml::RefPtr<AndroidEnvironmentGL> environment,
AndroidContextGLSkia(fml::RefPtr<AndroidEnvironmentGL> environment,
const TaskRunners& taskRunners,
uint8_t msaa_samples);

Expand Down
26 changes: 13 additions & 13 deletions shell/platform/android/android_context_gl_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ TEST(AndroidContextGl, Create) {
thread_label, ThreadHost::Type::kUi | ThreadHost::Type::kRaster |
ThreadHost::Type::kIo));
TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host);
auto context = std::make_unique<AndroidContextGLSkia>(
AndroidRenderingAPI::kOpenGLES, environment, task_runners, 0);
auto context =
std::make_unique<AndroidContextGLSkia>(environment, task_runners, 0);
context->SetMainSkiaContext(main_context);
EXPECT_NE(context.get(), nullptr);
context.reset();
Expand All @@ -115,7 +115,7 @@ TEST(AndroidContextGl, Create) {
TEST(AndroidContextGl, CreateImpeller) {
auto impeller_context = std::make_shared<TestImpellerContext>();
auto android_context = std::make_unique<TestAndroidContext>(
impeller_context, AndroidRenderingAPI::kOpenGLES);
impeller_context, AndroidRenderingAPI::kImpellerOpenGLES);
EXPECT_FALSE(impeller_context->did_shutdown);

android_context.reset();
Expand All @@ -136,8 +136,8 @@ TEST(AndroidContextGl, CreateSingleThread) {
TaskRunners task_runners =
TaskRunners(thread_label, platform_runner, platform_runner,
platform_runner, platform_runner);
auto context = std::make_unique<AndroidContextGLSkia>(
AndroidRenderingAPI::kOpenGLES, environment, task_runners, 0);
auto context =
std::make_unique<AndroidContextGLSkia>(environment, task_runners, 0);
context->SetMainSkiaContext(main_context);
EXPECT_NE(context.get(), nullptr);
context.reset();
Expand All @@ -155,8 +155,8 @@ TEST(AndroidSurfaceGL, CreateSnapshopSurfaceWhenOnscreenSurfaceIsNotNull) {
thread_label, ThreadHost::Type::kUi | ThreadHost::Type::kRaster |
ThreadHost::Type::kIo));
TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host);
auto android_context = std::make_shared<AndroidContextGLSkia>(
AndroidRenderingAPI::kOpenGLES, environment, task_runners, 0);
auto android_context =
std::make_shared<AndroidContextGLSkia>(environment, task_runners, 0);
auto android_surface =
std::make_unique<AndroidSurfaceGLSkia>(android_context);
auto window = fml::MakeRefCounted<AndroidNativeWindow>(
Expand All @@ -182,8 +182,8 @@ TEST(AndroidSurfaceGL, CreateSnapshopSurfaceWhenOnscreenSurfaceIsNull) {

ThreadHost thread_host(host_config);
TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host);
auto android_context = std::make_shared<AndroidContextGLSkia>(
AndroidRenderingAPI::kOpenGLES, environment, task_runners, 0);
auto android_context =
std::make_shared<AndroidContextGLSkia>(environment, task_runners, 0);
auto android_surface =
std::make_unique<AndroidSurfaceGLSkia>(android_context);
EXPECT_EQ(android_surface->GetOnscreenSurface(), nullptr);
Expand All @@ -204,8 +204,8 @@ TEST(AndroidContextGl, DISABLED_MSAAx4) {
thread_label, ThreadHost::Type::kUi | ThreadHost::Type::kRaster |
ThreadHost::Type::kIo));
TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host);
auto context = std::make_unique<AndroidContextGLSkia>(
AndroidRenderingAPI::kOpenGLES, environment, task_runners, 4);
auto context =
std::make_unique<AndroidContextGLSkia>(environment, task_runners, 4);
context->SetMainSkiaContext(main_context);

EGLint sample_count;
Expand All @@ -226,8 +226,8 @@ TEST(AndroidContextGl, EnsureMakeCurrentChecksCurrentContextStatus) {
thread_label, ThreadHost::Type::kUi | ThreadHost::Type::kRaster |
ThreadHost::Type::kIo));
TaskRunners task_runners = MakeTaskRunners(thread_label, thread_host);
auto context = std::make_unique<AndroidContextGLSkia>(
AndroidRenderingAPI::kOpenGLES, environment, task_runners, 0);
auto context =
std::make_unique<AndroidContextGLSkia>(environment, task_runners, 0);

auto pbuffer_surface = context->CreatePbufferSurface();
auto status = pbuffer_surface->MakeCurrent();
Expand Down
24 changes: 14 additions & 10 deletions shell/platform/android/android_context_vulkan_impeller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ namespace flutter {
static std::shared_ptr<impeller::Context> CreateImpellerContext(
const fml::RefPtr<fml::NativeLibrary>& vulkan_dylib,
bool enable_vulkan_validation,
bool enable_gpu_tracing) {
bool enable_gpu_tracing,
bool quiet) {
if (!vulkan_dylib) {
VALIDATION_LOG << "Could not open the Vulkan dylib.";
return nullptr;
Expand Down Expand Up @@ -57,24 +58,27 @@ static std::shared_ptr<impeller::Context> CreateImpellerContext(

auto context = impeller::ContextVK::Create(std::move(settings));

if (context && impeller::CapabilitiesVK::Cast(*context->GetCapabilities())
.AreValidationsEnabled()) {
FML_LOG(IMPORTANT) << "Using the Impeller rendering backend (Vulkan with "
"Validation Layers).";
} else {
FML_LOG(IMPORTANT) << "Using the Impeller rendering backend (Vulkan).";
if (!quiet) {
if (context && impeller::CapabilitiesVK::Cast(*context->GetCapabilities())
.AreValidationsEnabled()) {
FML_LOG(IMPORTANT) << "Using the Impeller rendering backend (Vulkan with "
"Validation Layers).";
} else {
FML_LOG(IMPORTANT) << "Using the Impeller rendering backend (Vulkan).";
}
}

return context;
}

AndroidContextVulkanImpeller::AndroidContextVulkanImpeller(
bool enable_validation,
bool enable_gpu_tracing)
: AndroidContext(AndroidRenderingAPI::kVulkan),
bool enable_gpu_tracing,
bool quiet)
: AndroidContext(AndroidRenderingAPI::kImpellerVulkan),
vulkan_dylib_(fml::NativeLibrary::Create("libvulkan.so")) {
auto impeller_context = CreateImpellerContext(
vulkan_dylib_, enable_validation, enable_gpu_tracing);
vulkan_dylib_, enable_validation, enable_gpu_tracing, quiet);
SetImpellerContext(impeller_context);
is_valid_ = !!impeller_context;
}
Expand Down
4 changes: 3 additions & 1 deletion shell/platform/android/android_context_vulkan_impeller.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ namespace flutter {

class AndroidContextVulkanImpeller : public AndroidContext {
public:
AndroidContextVulkanImpeller(bool enable_validation, bool enable_gpu_tracing);
AndroidContextVulkanImpeller(bool enable_validation,
bool enable_gpu_tracing,
bool quiet = false);

~AndroidContextVulkanImpeller();

Expand Down
1 change: 1 addition & 0 deletions shell/platform/android/context/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ source_set("context") {
public_configs = [ "//flutter:config" ]

deps = [
"//flutter/common",
"//flutter/fml",
"//flutter/impeller/renderer",
"//flutter/skia",
Expand Down
10 changes: 1 addition & 9 deletions shell/platform/android/context/android_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,14 @@
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_CONTEXT_ANDROID_CONTEXT_H_
#define FLUTTER_SHELL_PLATFORM_ANDROID_CONTEXT_ANDROID_CONTEXT_H_

#include "common/settings.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/task_runner.h"
#include "flutter/impeller/renderer/context.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"

namespace flutter {

enum class AndroidRenderingAPI {
kSoftware,
kOpenGLES,
kVulkan,
/// @brief Attempt to create a Vulkan surface, if that fails then fall back
/// to GLES.
kAutoselect,
};

//------------------------------------------------------------------------------
/// @brief Holds state that is shared across Android surfaces.
///
Expand Down
67 changes: 67 additions & 0 deletions shell/platform/android/flutter_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "common/settings.h"
#include "impeller/base/validation.h"
#define FML_USED_ON_EMBEDDER
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonahwilliams You are running into the message loop error above because this define is not at the top.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦 Thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you are at it, https://google.github.io/styleguide/cppguide.html#Names_and_Order_of_Includes for the include order. These includes would go below the related header.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


#include "flutter/shell/platform/android/flutter_main.h"
Expand All @@ -13,6 +15,7 @@

#include "flutter/fml/command_line.h"
#include "flutter/fml/file.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/message_loop.h"
#include "flutter/fml/native_library.h"
Expand All @@ -25,11 +28,14 @@
#include "flutter/runtime/dart_vm.h"
#include "flutter/shell/common/shell.h"
#include "flutter/shell/common/switches.h"
#include "flutter/shell/platform/android/android_context_vulkan_impeller.h"
#include "third_party/dart/runtime/include/dart_tools_api.h"
#include "txt/platform.h"

namespace flutter {

constexpr int kMinimumAndroidApiLevelForVulkan = 29;

extern "C" {
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
// Used for debugging dart:* sources.
Expand Down Expand Up @@ -91,6 +97,18 @@ void FlutterMain::Init(JNIEnv* env,
}
}

settings.android_rendering_api = SelectedRenderingAPI(settings);
switch (settings.android_rendering_api) {
case AndroidRenderingAPI::kSoftware:
case AndroidRenderingAPI::kSkiaOpenGLES:
settings.enable_impeller = false;
break;
case AndroidRenderingAPI::kImpellerOpenGLES:
case AndroidRenderingAPI::kImpellerVulkan:
settings.enable_impeller = true;
break;
}

#if FLUTTER_RELEASE
// On most platforms the timeline is always disabled in release mode.
// On Android, enable it in release mode only when using systrace.
Expand Down Expand Up @@ -211,4 +229,53 @@ bool FlutterMain::Register(JNIEnv* env) {
return env->RegisterNatives(clazz, methods, fml::size(methods)) == 0;
}

// static
AndroidRenderingAPI FlutterMain::SelectedRenderingAPI(
const flutter::Settings& settings) {
if (settings.enable_software_rendering) {
FML_CHECK(!settings.enable_impeller)
<< "Impeller does not support software rendering. Either disable "
"software rendering or disable impeller.";
return AndroidRenderingAPI::kSoftware;
}
// Debug/Profile only functionality for testing a specific
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should fault instead of falling back on releases? Let's ask the team.

// backend configuration.
#ifndef FLUTTER_RELEASE
if (settings.requested_rendering_backend == "opengles" &
settings.enable_impeller) {
return AndroidRenderingAPI::kImpellerOpenGLES;
}
if (settings.requested_rendering_backend == "vulkan" &&
settings.enable_impeller) {
return AndroidRenderingAPI::kImpellerVulkan;
}
#endif

if (settings.enable_impeller) {
// Vulkan must only be used on API level 29+, as older API levels do not
// have requisite features to support platform views.
//
// Even if this check returns true, Impeller may determine it cannot use
// Vulkan for some other reason, such as a missing required extension or
// feature.
int api_level = android_get_device_api_level();
if (api_level < kMinimumAndroidApiLevelForVulkan) {
return AndroidRenderingAPI::kImpellerOpenGLES;
}
// Determine if Vulkan is supported by creating a Vulkan context and
// checking if it is valid.
impeller::ScopedValidationDisable disable_validation;
auto vulkan_backend = std::make_unique<AndroidContextVulkanImpeller>(
/*enable_vulkan_validation=*/false,
/*enable_vulkan_gpu_tracing=*/false,
/*quiet=*/true);
if (!vulkan_backend->IsValid()) {
return AndroidRenderingAPI::kImpellerOpenGLES;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can implement ImpellerVulkan -> Skia fallback by changing this value (or adding another configuration setting).

}
return AndroidRenderingAPI::kImpellerVulkan;
}

return AndroidRenderingAPI::kSkiaOpenGLES;
}

} // namespace flutter
3 changes: 3 additions & 0 deletions shell/platform/android/flutter_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class FlutterMain {

const flutter::Settings& GetSettings() const;

static AndroidRenderingAPI SelectedRenderingAPI(
const flutter::Settings& settings);

private:
const flutter::Settings settings_;
DartServiceIsolate::CallbackHandle vm_service_uri_callback_ = 0;
Expand Down
Loading