[Impeller] Flutter GPU: Add context override. (flutter/engine#44566)

Adds a way to inject a context override, which allows us to test the API
in the Dart playground without spinning up an Engine/Shell.
This commit is contained in:
Brandon DeRosier
2023-08-10 11:54:56 -07:00
committed by GitHub
parent 046361c1cb
commit 491ce39b6d
5 changed files with 70 additions and 17 deletions

View File

@@ -3,7 +3,7 @@
// found in the LICENSE file.
import 'dart:ui' as ui;
//import 'dart:gpu';
import '../../lib/gpu/lib/gpu.dart' as gpu;
void main() {}
@@ -11,3 +11,9 @@ void main() {}
void sayHi() {
print('Hi');
}
@pragma('vm:entry-point')
void instantiateDefaultContext() {
// ignore: unused_local_variable
final gpu.GpuContext context = gpu.gpuContext;
}

View File

@@ -161,6 +161,7 @@ impeller_component("renderer_dart_unittests") {
":renderer_dart_fixtures",
"../fixtures:shader_fixtures",
"../playground:playground_test",
"//flutter/lib/gpu",
"//flutter/runtime:runtime",
"//flutter/testing:fixture_test",
"//flutter/testing:testing",

View File

@@ -10,6 +10,7 @@
#include "flutter/common/task_runners.h"
#include "flutter/fml/backtrace.h"
#include "flutter/fml/command_line.h"
#include "flutter/lib/gpu/context.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "flutter/runtime/dart_isolate.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
@@ -46,7 +47,13 @@ class RendererDartTest : public PlaygroundTest,
assert(isolate_->get()->GetPhase() == flutter::DartIsolate::Phase::Running);
}
flutter::testing::AutoIsolateShutdown* GetIsolate() { return isolate_.get(); }
flutter::testing::AutoIsolateShutdown* GetIsolate() {
// Sneak the context into the Flutter GPU API.
assert(GetContext() != nullptr);
flutter::Context::SetOverrideContext(GetContext());
return isolate_.get();
}
private:
std::unique_ptr<flutter::testing::AutoIsolateShutdown> CreateDartIsolate() {
@@ -90,5 +97,19 @@ TEST_P(RendererDartTest, CanRunDartInPlaygroundFrame) {
OpenPlaygroundHere(callback);
}
TEST_P(RendererDartTest, CanInstantiateFlutterGPUContext) {
auto isolate = GetIsolate();
bool result = isolate->RunInIsolateScope([]() -> bool {
if (tonic::CheckAndHandleError(::Dart_Invoke(
Dart_RootLibrary(), tonic::ToDart("instantiateDefaultContext"), 0,
nullptr))) {
return false;
}
return true;
});
ASSERT_TRUE(result);
}
} // namespace testing
} // namespace impeller

View File

@@ -15,6 +15,16 @@ namespace flutter {
IMPLEMENT_WRAPPERTYPEINFO(gpu, Context);
std::shared_ptr<impeller::Context> Context::override_context_;
void Context::SetOverrideContext(std::shared_ptr<impeller::Context> context) {
override_context_ = std::move(context);
}
std::shared_ptr<impeller::Context> Context::GetOverrideContext() {
return override_context_;
}
Context::Context(std::shared_ptr<impeller::Context> context)
: context_(std::move(context)) {}
@@ -28,23 +38,28 @@ Context::~Context() = default;
Dart_Handle InternalFlutterGpu_Context_InitializeDefault(Dart_Handle wrapper) {
auto dart_state = flutter::UIDartState::Current();
if (!dart_state->IsImpellerEnabled()) {
return tonic::ToDart(
"Flutter GPU requires the Impeller rendering backend to be enabled.");
std::shared_ptr<impeller::Context> impeller_context =
flutter::Context::GetOverrideContext();
if (!impeller_context) {
if (!dart_state->IsImpellerEnabled()) {
return tonic::ToDart(
"Flutter GPU requires the Impeller rendering backend to be enabled.");
}
// Grab the Impeller context from the IO manager.
std::promise<std::shared_ptr<impeller::Context>> context_promise;
auto impeller_context_future = context_promise.get_future();
dart_state->GetTaskRunners().GetIOTaskRunner()->PostTask(
fml::MakeCopyable([promise = std::move(context_promise),
io_manager = dart_state->GetIOManager()]() mutable {
promise.set_value(io_manager ? io_manager->GetImpellerContext()
: nullptr);
}));
impeller_context = impeller_context_future.get();
}
// Grab the Impeller context from the IO manager.
std::promise<std::shared_ptr<impeller::Context>> context_promise;
auto impeller_context_future = context_promise.get_future();
dart_state->GetTaskRunners().GetIOTaskRunner()->PostTask(
fml::MakeCopyable([promise = std::move(context_promise),
io_manager = dart_state->GetIOManager()]() mutable {
promise.set_value(io_manager ? io_manager->GetImpellerContext()
: nullptr);
}));
auto impeller_context = impeller_context_future.get();
if (!impeller_context) {
return tonic::ToDart("Unable to retrieve the Impeller context.");
}

View File

@@ -16,9 +16,19 @@ class Context : public RefCountedDartWrappable<Context> {
FML_FRIEND_MAKE_REF_COUNTED(Context);
public:
static void SetOverrideContext(std::shared_ptr<impeller::Context> context);
static std::shared_ptr<impeller::Context> GetOverrideContext();
explicit Context(std::shared_ptr<impeller::Context> context);
~Context() override;
protected:
/// An Impeller context that takes precedent over the IO state context when
/// set. This is used to inject the context when running with the Impeller
/// playground, which doesn't instantiate an Engine instance.
static std::shared_ptr<impeller::Context> override_context_;
private:
std::shared_ptr<impeller::Context> context_;