提交 925298d9 编写于 作者: C Chinmay Garde 提交者: Jeff Brown

Update the content handler to use the Mozart session API. (#3887)

上级 d098b358
......@@ -7,6 +7,15 @@
#include "lib/ftl/tasks/task_runner.h"
#define ASSERT_IS_PLATFORM_THREAD \
FTL_DCHECK(::blink::Threads::Platform()->RunsTasksOnCurrentThread());
#define ASSERT_IS_GPU_THREAD \
FTL_DCHECK(::blink::Threads::Gpu()->RunsTasksOnCurrentThread());
#define ASSERT_IS_UI_THREAD \
FTL_DCHECK(::blink::Threads::UI()->RunsTasksOnCurrentThread());
#define ASSERT_IS_IO_THREAD \
FTL_DCHECK(::blink::Threads::IO()->RunsTasksOnCurrentThread());
namespace blink {
class Threads {
......
......@@ -6,11 +6,6 @@ assert(is_fuchsia)
import("//build/vulkan/config.gni")
declare_args() {
flutter_enable_vulkan = fuchsia_use_vulkan
flutter_use_vulkan_native_surface = false
}
template("flutter_content_handler") {
invoker_output_name = invoker.output_name
extra_deps = invoker.extra_deps
......@@ -27,8 +22,6 @@ template("flutter_content_handler") {
"app.h",
"application_controller_impl.cc",
"application_controller_impl.h",
"content_handler_thread.cc",
"content_handler_thread.h",
"main.cc",
"rasterizer.cc",
"rasterizer.h",
......@@ -36,66 +29,46 @@ template("flutter_content_handler") {
"runtime_holder.h",
"service_protocol_hooks.cc",
"service_protocol_hooks.h",
"software_rasterizer.cc",
"software_rasterizer.h",
"session_connection.cc",
"session_connection.h",
"vulkan_rasterizer.cc",
"vulkan_rasterizer.h",
"vulkan_surface.cc",
"vulkan_surface.h",
"vulkan_surface_pool.cc",
"vulkan_surface_pool.h",
"vulkan_surface_producer.cc",
"vulkan_surface_producer.h",
]
deps = [
"//application/lib/app",
"//application/lib/svc",
"//apps/icu_data/lib",
"//apps/mozart/lib/flutter/sdk_ext",
"//apps/mozart/lib/skia:vmo",
"//apps/mozart/services/buffers",
"//apps/mozart/services/buffers/cpp",
"//apps/mozart/services/composition",
"//apps/mozart/services/input",
"//apps/mozart/services/views",
"//apps/tracing/lib/trace:provider",
# TODO(abarth): We shouldn't need to depend on libdart_builtin but we fail
# to link otherwise.
"//dart/runtime/bin:libdart_builtin",
"//dart/runtime/vm:libdart_platform",
"//flutter/assets",
"//flutter/common",
"//flutter/flow",
"//flutter/glue",
"//flutter/lib/ui",
"//flutter/runtime",
"//flutter/sky/engine/platform",
"//lib/fidl/dart/sdk_ext",
"//lib/ftl",
"//lib/mtl",
"//lib/tonic/mx",
"//lib/zip",
"//third_party/rapidjson",
"//third_party/skia",
]
deps += extra_deps
if (flutter_enable_vulkan) {
defines += [ "FLUTTER_ENABLE_VULKAN=1" ]
if (flutter_use_vulkan_native_surface) {
defines += [ "FLUTTER_USE_VULKAN_NATIVE_SURFACE=1" ]
sources += [
"vulkan_native_rasterizer.cc",
"vulkan_native_rasterizer.h",
]
libs += [ "hid" ]
} else {
sources += [
"vulkan_rasterizer.cc",
"vulkan_rasterizer.h",
]
}
deps += [
"//flutter/vulkan",
"//magma:vulkan",
]
}
"//application/lib/app",
"//application/lib/svc",
"//apps/icu_data/lib",
"//apps/mozart/lib/flutter/sdk_ext",
"//apps/mozart/lib/scene:client",
"//apps/mozart/services/input",
"//apps/mozart/services/views",
"//apps/tracing/lib/trace:provider",
"//dart/runtime/bin:libdart_builtin",
"//dart/runtime/vm:libdart_platform",
"//flutter/assets",
"//flutter/common",
"//flutter/flow",
"//flutter/glue",
"//flutter/lib/ui",
"//flutter/runtime",
"//flutter/sky/engine/platform",
"//flutter/vulkan",
"//lib/fidl/dart/sdk_ext",
"//lib/ftl",
"//lib/mtl",
"//lib/tonic/mx",
"//lib/zip",
"//magma:vulkan",
"//third_party/rapidjson",
"//third_party/skia",
] + extra_deps
# The flags below are needed so that Dart's CPU profiler can walk the
# C++ stack.
......@@ -103,6 +76,7 @@ template("flutter_content_handler") {
"-mno-omit-leaf-frame-pointer",
"-fno-omit-frame-pointer",
]
# This flag is needed so that the call to dladdr() in Dart's native symbol
# resolver can report good symbol information for the CPU profiler.
ldflags = [ "-rdynamic" ]
......
......@@ -40,11 +40,14 @@ App::App() {
tracing::InitializeTracer(context_.get(), {});
gpu_thread_ = std::make_unique<Thread>();
io_thread_ = std::make_unique<Thread>();
gpu_thread_ = std::make_unique<mtl::Thread>();
io_thread_ = std::make_unique<mtl::Thread>();
FTL_CHECK(gpu_thread_->IsValid()) << "Must be able to create the GPU thread";
FTL_CHECK(io_thread_->IsValid()) << "Must be able to create the IO thread";
auto gpu_thread_success = gpu_thread_->Run();
auto io_thread_success = io_thread_->Run();
FTL_CHECK(gpu_thread_success) << "Must be able to create the GPU thread";
FTL_CHECK(io_thread_success) << "Must be able to create the IO thread";
auto ui_task_runner = mtl::MessageLoop::GetCurrent()->task_runner();
auto gpu_task_runner = gpu_thread_->TaskRunner();
......
......@@ -11,9 +11,9 @@
#include "application/lib/app/application_context.h"
#include "application/services/application_runner.fidl.h"
#include "flutter/content_handler/application_controller_impl.h"
#include "flutter/content_handler/content_handler_thread.h"
#include "lib/ftl/macros.h"
#include "lib/ftl/synchronization/waitable_event.h"
#include "lib/mtl/threading/thread.h"
namespace flutter_runner {
......@@ -26,10 +26,10 @@ class App : public app::ApplicationRunner {
// |app::ApplicationRunner| implementation:
void StartApplication(app::ApplicationPackagePtr application,
app::ApplicationStartupInfoPtr startup_info,
fidl::InterfaceRequest<app::ApplicationController>
controller) override;
void StartApplication(
app::ApplicationPackagePtr application,
app::ApplicationStartupInfoPtr startup_info,
fidl::InterfaceRequest<app::ApplicationController> controller) override;
void Destroy(ApplicationControllerImpl* controller);
......@@ -43,13 +43,13 @@ class App : public app::ApplicationRunner {
private:
void WaitForPlatformViewsIdsUIThread(
std::vector<PlatformViewInfo>* platform_view_ids,
ftl::AutoResetWaitableEvent* latch);
std::vector<PlatformViewInfo>* platform_view_ids,
ftl::AutoResetWaitableEvent* latch);
void UpdateProcessLabel();
std::unique_ptr<app::ApplicationContext> context_;
std::unique_ptr<Thread> gpu_thread_;
std::unique_ptr<Thread> io_thread_;
std::unique_ptr<mtl::Thread> gpu_thread_;
std::unique_ptr<mtl::Thread> io_thread_;
fidl::BindingSet<app::ApplicationRunner> runner_bindings_;
std::unordered_map<ApplicationControllerImpl*,
std::unique_ptr<ApplicationControllerImpl>>
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/content_handler/content_handler_thread.h"
#include <unistd.h>
#include "lib/ftl/logging.h"
#include "lib/mtl/tasks/incoming_task_queue.h"
#include "lib/mtl/tasks/message_loop.h"
namespace flutter_runner {
typedef void (*ThreadEntry)(Thread*);
static size_t NextPageSizeMultiple(size_t size) {
const size_t page_size = sysconf(_SC_PAGE_SIZE);
FTL_CHECK(page_size != 0);
size = std::max<size_t>(size, page_size);
size_t rem = size % page_size;
if (rem == 0) {
return size;
}
return size + page_size - rem;
}
static bool CreateThread(pthread_t* thread,
ThreadEntry main,
Thread* argument,
size_t stack_size) {
pthread_attr_t thread_attributes;
if (pthread_attr_init(&thread_attributes) != 0) {
return false;
}
stack_size = std::max<size_t>(NextPageSizeMultiple(PTHREAD_STACK_MIN),
NextPageSizeMultiple(stack_size));
if (pthread_attr_setstacksize(&thread_attributes, stack_size) != 0) {
return false;
}
auto result =
pthread_create(thread, &thread_attributes,
reinterpret_cast<void* (*)(void*)>(main), argument);
pthread_attr_destroy(&thread_attributes);
return result == 0;
}
Thread::Thread()
: task_runner_(ftl::MakeRefCounted<mtl::internal::IncomingTaskQueue>()) {
valid_ = CreateThread(&thread_, [](Thread* thread) { thread->Main(); }, this,
1 << 20);
}
Thread::~Thread() {
Join();
}
bool Thread::IsValid() const {
return valid_;
}
ftl::RefPtr<ftl::TaskRunner> Thread::TaskRunner() const {
return task_runner_;
}
void Thread::Main() {
mtl::MessageLoop message_loop(task_runner_);
message_loop.Run();
}
bool Thread::Join() {
if (!valid_) {
return false;
}
return pthread_join(thread_, nullptr) == 0;
}
} // namespace flutter_runner
// Copyright 2017 The Chromium 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_CONTENT_HANDLER_CONTENT_HANDLER_THREAD_H_
#define FLUTTER_CONTENT_HANDLER_CONTENT_HANDLER_THREAD_H_
#include <pthread.h>
#include <functional>
#include "lib/ftl/macros.h"
#include "lib/ftl/memory/ref_ptr.h"
#include "lib/ftl/tasks/task_runner.h"
namespace mtl {
namespace internal {
class IncomingTaskQueue;
} // namespace internal
} // namespace mtl
namespace flutter_runner {
class Thread {
public:
Thread();
~Thread();
ftl::RefPtr<ftl::TaskRunner> TaskRunner() const;
bool Join();
bool IsValid() const;
private:
bool valid_;
pthread_t thread_;
ftl::RefPtr<mtl::internal::IncomingTaskQueue> task_runner_;
void Main();
FTL_DISALLOW_COPY_AND_ASSIGN(Thread);
};
} // namespace flutter_runner
#endif // FLUTTER_CONTENT_HANDLER_CONTENT_HANDLER_THREAD_H_
......@@ -3,41 +3,17 @@
// found in the LICENSE file.
#include "flutter/content_handler/rasterizer.h"
#include "flutter/content_handler/software_rasterizer.h"
#if FLUTTER_ENABLE_VULKAN
#if FLUTTER_USE_VULKAN_NATIVE_SURFACE
#include "flutter/content_handler/vulkan_native_rasterizer.h"
#else // FLUTTER_USE_VULKAN_NATIVE_SURFACE
#include "flutter/content_handler/vulkan_rasterizer.h"
#endif // FLUTTER_USE_VULKAN_NATIVE_SURFACE
#endif // FLUTTER_ENABLE_VULKAN
namespace flutter_runner {
Rasterizer::~Rasterizer() = default;
std::unique_ptr<Rasterizer> Rasterizer::Create() {
#if FLUTTER_ENABLE_VULKAN
#if FLUTTER_USE_VULKAN_NATIVE_SURFACE
auto vulkan_rasterizer = std::make_unique<VulkanNativeRasterizer>();
#else // FLUTTER_USE_VULKAN_NATIVE_SURFACE
auto vulkan_rasterizer = std::make_unique<VulkanRasterizer>();
#endif // FLUTTER_USE_VULKAN_NATIVE_SURFACE
if (!vulkan_rasterizer->IsValid()) {
FTL_DLOG(INFO) << "Could not initialize a valid vulkan rasterizer. "
"Attempting to fallback to the software rasterizer.";
return std::make_unique<SoftwareRasterizer>();
}
FTL_DLOG(INFO) << "Successfully initialized a valid vulkan rasterizer.";
FTL_CHECK(vulkan_rasterizer)
<< "The vulkan rasterizer must be correctly initialized.";
return vulkan_rasterizer;
#else // FLUTTER_ENABLE_VULKAN
return std::make_unique<SoftwareRasterizer>();
#endif // FLUTTER_ENABLE_VULKAN
}
} // namespace flutter_runner
......@@ -7,10 +7,11 @@
#include <memory>
#include "apps/mozart/services/composition/scenes.fidl.h"
#include "apps/mozart/services/scene/session.fidl.h"
#include "flutter/flow/layers/layer_tree.h"
#include "lib/ftl/functional/closure.h"
#include "lib/ftl/macros.h"
#include "magenta/system/ulib/mx/include/mx/eventpair.h"
namespace flutter_runner {
......@@ -20,7 +21,8 @@ class Rasterizer {
static std::unique_ptr<Rasterizer> Create();
virtual void SetScene(fidl::InterfaceHandle<mozart::Scene> scene) = 0;
virtual void SetSession(fidl::InterfaceHandle<mozart2::Session> session,
mx::eventpair import_token) = 0;
virtual void Draw(std::unique_ptr<flow::LayerTree> layer_tree,
ftl::Closure callback) = 0;
......
......@@ -44,13 +44,6 @@ constexpr char kAssetChannel[] = "flutter/assets";
constexpr char kKeyEventChannel[] = "flutter/keyevent";
constexpr char kTextInputChannel[] = "flutter/textinput";
// Maximum number of frames in flight.
constexpr int kMaxPipelineDepth = 3;
// When the max pipeline depth is exceeded, drain to this number of frames
// to recover before acknowleding the invalidation and scheduling more frames.
constexpr int kRecoveryPipelineDepth = 1;
blink::PointerData::Change GetChangeFromPointerEventPhase(
mozart::PointerEvent::Phase phase) {
switch (phase) {
......@@ -98,10 +91,6 @@ RuntimeHolder::~RuntimeHolder() {
ftl::MakeCopyable([rasterizer = std::move(rasterizer_)](){
// Deletes rasterizer.
}));
if (deferred_invalidation_callback_) {
// Must be called before being destroyed.
deferred_invalidation_callback_();
}
}
void RuntimeHolder::Init(
......@@ -192,14 +181,23 @@ void RuntimeHolder::CreateView(
}
}
// Create the view.
mx::eventpair import_token, export_token;
mx_status_t status = mx::eventpair::create(0u, &import_token, &export_token);
if (status != MX_OK) {
FTL_LOG(ERROR) << "Could not create an event pair.";
return;
}
mozart::ViewListenerPtr view_listener;
view_listener_binding_.Bind(fidl::GetProxy(&view_listener));
view_manager_->CreateView(fidl::GetProxy(&view_),
std::move(view_owner_request),
std::move(view_listener), script_uri);
view_listener_binding_.Bind(view_listener.NewRequest());
view_manager_->CreateView(view_.NewRequest(), // view
std::move(view_owner_request), // view owner
std::move(view_listener), // view listener
std::move(export_token), // export token
script_uri // diagnostic label
);
app::ServiceProviderPtr view_services;
view_->GetServiceProvider(fidl::GetProxy(&view_services));
view_->GetServiceProvider(view_services.NewRequest());
// Listen for input events.
ConnectToService(view_services.get(), fidl::GetProxy(&input_connection_));
......@@ -207,11 +205,20 @@ void RuntimeHolder::CreateView(
input_listener_binding_.Bind(GetProxy(&input_listener));
input_connection_->SetEventListener(std::move(input_listener));
mozart::ScenePtr scene;
view_->CreateScene(fidl::GetProxy(&scene));
// Setup the session.
mozart2::SessionPtr session;
mozart2::SceneManagerPtr scene_manager;
view_manager_->GetSceneManager(scene_manager.NewRequest());
scene_manager->CreateSession(session.NewRequest(),
nullptr /* session listener */);
blink::Threads::Gpu()->PostTask(ftl::MakeCopyable([
rasterizer = rasterizer_.get(), scene = std::move(scene)
]() mutable { rasterizer->SetScene(std::move(scene)); }));
rasterizer = rasterizer_.get(), //
session = session.PassInterfaceHandle(), //
import_token = std::move(import_token) //
]() mutable {
ASSERT_IS_GPU_THREAD;
rasterizer->SetSession(std::move(session), std::move(import_token));
}));
runtime_ = blink::RuntimeController::Create(this);
......@@ -259,30 +266,50 @@ std::string RuntimeHolder::DefaultRouteName() {
}
void RuntimeHolder::ScheduleFrame() {
if (pending_invalidation_ || deferred_invalidation_callback_)
return;
pending_invalidation_ = true;
view_->Invalidate();
ASSERT_IS_UI_THREAD;
if (!frame_scheduled_) {
frame_scheduled_ = true;
if (!frame_outstanding_)
PostBeginFrame();
}
}
void RuntimeHolder::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
if (!is_ready_to_draw_)
return; // Only draw once per frame.
is_ready_to_draw_ = false;
if (!frame_outstanding_ || frame_rendering_) {
// TODO(MZ-193): We probably shouldn't be discarding the layer tree here.
// But then, Flutter shouldn't be calling Render() if we didn't call
// BeginFrame().
return; // Spurious.
}
frame_rendering_ = true;
layer_tree->set_construction_time(ftl::TimePoint::Now() -
last_begin_frame_time_);
layer_tree->set_frame_size(SkISize::Make(viewport_metrics_.physical_width,
viewport_metrics_.physical_height));
layer_tree->set_scene_version(scene_version_);
// We are on the Platform/UI thread. Post to the GPU thread to render.
ASSERT_IS_PLATFORM_THREAD;
blink::Threads::Gpu()->PostTask(ftl::MakeCopyable([
rasterizer = rasterizer_.get(), layer_tree = std::move(layer_tree),
self = GetWeakPtr()
rasterizer = rasterizer_.get(), //
layer_tree = std::move(layer_tree), //
weak_runtime_holder = GetWeakPtr() //
]() mutable {
rasterizer->Draw(std::move(layer_tree), [self]() {
if (self)
self->OnFrameComplete();
// On the GPU Thread.
ASSERT_IS_GPU_THREAD;
rasterizer->Draw(std::move(layer_tree), [weak_runtime_holder]() {
// This is on the GPU thread thread. Post to the Platform/UI thread for
// the completion callback.
ASSERT_IS_GPU_THREAD;
blink::Threads::Platform()->PostTask([weak_runtime_holder]() {
// On the Platform/UI thread.
ASSERT_IS_UI_THREAD;
if (weak_runtime_holder) {
weak_runtime_holder->frame_rendering_ = false;
weak_runtime_holder->OnFrameComplete();
}
});
});
}));
}
......@@ -550,41 +577,27 @@ void RuntimeHolder::OnEvent(mozart::InputEventPtr event,
callback(handled);
}
void RuntimeHolder::OnInvalidation(mozart::ViewInvalidationPtr invalidation,
const OnInvalidationCallback& callback) {
FTL_DCHECK(invalidation);
pending_invalidation_ = false;
void RuntimeHolder::OnPropertiesChanged(
mozart::ViewPropertiesPtr properties,
const OnPropertiesChangedCallback& callback) {
FTL_DCHECK(properties);
// Apply view property changes.
if (invalidation->properties) {
view_properties_ = std::move(invalidation->properties);
viewport_metrics_.physical_width =
view_properties_->view_layout->size->width;
viewport_metrics_.physical_height =
view_properties_->view_layout->size->height;
viewport_metrics_.device_pixel_ratio = 2.0;
// TODO(abarth): Use view_properties_->display_metrics->device_pixel_ratio
// once that's reasonable.
runtime_->SetViewportMetrics(viewport_metrics_);
// Attempt to read the device pixel ratio.
float pixel_ratio = 1.0;
if (auto& metrics = properties->display_metrics) {
pixel_ratio = metrics->device_pixel_ratio;
}
// Remember the scene version for rendering.
scene_version_ = invalidation->scene_version;
// TODO(jeffbrown): Flow the frame time through the rendering pipeline.
if (outstanding_requests_ >= kMaxPipelineDepth) {
FTL_DCHECK(!deferred_invalidation_callback_);
deferred_invalidation_callback_ = callback;
return;
// Apply view property changes.
if (auto& layout = properties->view_layout) {
viewport_metrics_.physical_width = layout->size->width;
viewport_metrics_.physical_height = layout->size->height;
viewport_metrics_.device_pixel_ratio = pixel_ratio;
runtime_->SetViewportMetrics(viewport_metrics_);
}
++outstanding_requests_;
BeginFrame();
ScheduleFrame();
// TODO(jeffbrown): Consider running the callback earlier.
// Note that this may result in the view processing stale view properties
// (such as size) if it prematurely acks the frame but takes too long
// to handle it.
callback();
}
......@@ -645,9 +658,8 @@ void RuntimeHolder::OnAction(mozart::InputMethodAction action) {
args.PushBack("TextInputAction.done", allocator);
document.SetObject();
document.AddMember("method",
rapidjson::Value("TextInputClient.performAction"),
allocator);
document.AddMember(
"method", rapidjson::Value("TextInputClient.performAction"), allocator);
document.AddMember("args", args, allocator);
rapidjson::StringBuffer buffer;
......@@ -664,39 +676,32 @@ ftl::WeakPtr<RuntimeHolder> RuntimeHolder::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void RuntimeHolder::BeginFrame() {
FTL_DCHECK(outstanding_requests_ > 0);
FTL_DCHECK(outstanding_requests_ <= kMaxPipelineDepth)
<< outstanding_requests_;
void RuntimeHolder::PostBeginFrame() {
blink::Threads::Platform()->PostTask([weak_runtime_holder = GetWeakPtr()]() {
// On the Platform/UI thread.
ASSERT_IS_UI_THREAD;
if (weak_runtime_holder) {
weak_runtime_holder->BeginFrame();
}
});
}
FTL_DCHECK(!is_ready_to_draw_);
is_ready_to_draw_ = true;
void RuntimeHolder::BeginFrame() {
ASSERT_IS_UI_THREAD
FTL_DCHECK(frame_scheduled_);
FTL_DCHECK(!frame_outstanding_);
frame_scheduled_ = false;
frame_outstanding_ = true;
last_begin_frame_time_ = ftl::TimePoint::Now();
runtime_->BeginFrame(last_begin_frame_time_);
const bool was_ready_to_draw = is_ready_to_draw_;
is_ready_to_draw_ = false;
// If we were still ready to draw when done with the frame, that means we
// didn't draw anything this frame and we should acknowledge the frame
// ourselves instead of waiting for the rasterizer to acknowledge it.
if (was_ready_to_draw)
OnFrameComplete();
}
void RuntimeHolder::OnFrameComplete() {
FTL_DCHECK(outstanding_requests_ > 0);
--outstanding_requests_;
if (deferred_invalidation_callback_ &&
outstanding_requests_ <= kRecoveryPipelineDepth) {
// Schedule frame first to avoid potentially generating a second
// invalidation in case the view manager already has one pending
// awaiting acknowledgement of the deferred invalidation.
OnInvalidationCallback callback =
std::move(deferred_invalidation_callback_);
ScheduleFrame();
callback();
}
ASSERT_IS_UI_THREAD
FTL_DCHECK(frame_outstanding_);
frame_outstanding_ = false;
if (frame_scheduled_)
PostBeginFrame();
}
} // namespace flutter_runner
......@@ -67,8 +67,9 @@ class RuntimeHolder : public blink::RuntimeDelegate,
const OnEventCallback& callback) override;
// |mozart::ViewListener| implementation:
void OnInvalidation(mozart::ViewInvalidationPtr invalidation,
const OnInvalidationCallback& callback) override;
void OnPropertiesChanged(
mozart::ViewPropertiesPtr properties,
const OnPropertiesChangedCallback& callback) override;
// |mozart::InputMethodEditorClient| implementation:
void DidUpdateState(mozart::TextInputStatePtr state,
......@@ -85,40 +86,32 @@ class RuntimeHolder : public blink::RuntimeDelegate,
void InitFidlInternal();
void InitMozartInternal();
void PostBeginFrame();
void BeginFrame();
void OnFrameComplete();
void Invalidate();
std::unique_ptr<app::ApplicationContext> context_;
fidl::InterfaceRequest<app::ServiceProvider> outgoing_services_;
std::vector<char> root_bundle_data_;
ftl::RefPtr<blink::ZipAssetStore> asset_store_;
void* dylib_handle_ = nullptr;
std::unique_ptr<Rasterizer> rasterizer_;
std::unique_ptr<blink::RuntimeController> runtime_;
blink::ViewportMetrics viewport_metrics_;
mozart::ViewManagerPtr view_manager_;
fidl::Binding<mozart::ViewListener> view_listener_binding_;
fidl::Binding<mozart::InputListener> input_listener_binding_;
mozart::InputConnectionPtr input_connection_;
mozart::ViewPtr view_;
mozart::ViewPropertiesPtr view_properties_;
uint32_t scene_version_ = mozart::kSceneVersionNone;
std::unordered_set<int> down_pointers_;
bool pending_invalidation_ = false;
OnInvalidationCallback deferred_invalidation_callback_;
bool is_ready_to_draw_ = false;
int outstanding_requests_ = 0;
mozart::InputMethodEditorPtr input_method_editor_;
fidl::Binding<mozart::InputMethodEditorClient> text_input_binding_;
int current_text_input_client_ = 0;
ftl::TimePoint last_begin_frame_time_;
bool frame_outstanding_ = false;
bool frame_scheduled_ = false;
bool frame_rendering_ = false;
ftl::WeakPtrFactory<RuntimeHolder> weak_factory_;
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/content_handler/session_connection.h"
#include "apps/mozart/lib/scene/session_helpers.h"
namespace flutter_runner {
SessionConnection::SessionConnection(
fidl::InterfaceHandle<mozart2::Session> session_handle,
mx::eventpair import_token)
: session_(mozart2::SessionPtr::Create(std::move(session_handle))),
root_node_(&session_),
surface_producer_(std::make_unique<VulkanSurfaceProducer>(&session_)),
scene_update_context_(&session_, surface_producer_.get()) {
ASSERT_IS_GPU_THREAD;
root_node_.Bind(std::move(import_token));
session_.set_connection_error_handler(
std::bind(&SessionConnection::OnSessionError, this));
present_callback_ =
std::bind(&SessionConnection::OnPresent, this, std::placeholders::_1);
}
SessionConnection::~SessionConnection() {
ASSERT_IS_GPU_THREAD;
}
void SessionConnection::OnSessionError() {
ASSERT_IS_GPU_THREAD;
// TODO: Not this.
FTL_CHECK(false) << "Session connection was terminated.";
}
void SessionConnection::Present(flow::CompositorContext::ScopedFrame& frame,
ftl::Closure on_present_callback) {
ASSERT_IS_GPU_THREAD;
FTL_DCHECK(pending_on_present_callback_ == nullptr);
FTL_DCHECK(on_present_callback != nullptr);
pending_on_present_callback_ = on_present_callback;
// Flush all session ops. Paint tasks have not yet executed but those are
// fenced. The compositor can start processing ops while we finalize paint
// tasks.
session_.Present(0, // presentation_time. Placeholder for now.
present_callback_ // callback
);
// Execute paint tasks and signal fences.
auto surfaces_to_submit = scene_update_context_.ExecutePaintTasks(frame);
// Tell the surface producer that a present has occurred so it can perform
// book-keeping on buffer caches.
surface_producer_->OnSurfacesPresented(std::move(surfaces_to_submit));
// Prepare for the next frame.
EnqueueClearOps();
}
void SessionConnection::OnPresent(mozart2::PresentationInfoPtr info) {
ASSERT_IS_GPU_THREAD;
auto callback = pending_on_present_callback_;
pending_on_present_callback_ = nullptr;
callback();
}
void SessionConnection::EnqueueClearOps() {
ASSERT_IS_GPU_THREAD;
// We are going to be sending down a fresh node hierarchy every frame. So just
// enqueue a detach op on the imported root node.
session_.Enqueue(mozart::NewDetachChildrenOp(root_node_.id()));
}
} // namespace flutter_runner
// Copyright 2017 The Chromium 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_CONTENT_HANDLER_SESSION_CONNECTION_H_
#define FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_
#include "apps/mozart/lib/scene/client/resources.h"
#include "apps/mozart/lib/scene/client/session.h"
#include "flutter/common/threads.h"
#include "flutter/content_handler/vulkan_surface_producer.h"
#include "flutter/flow/compositor_context.h"
#include "flutter/flow/scene_update_context.h"
#include "lib/fidl/cpp/bindings/interface_handle.h"
#include "lib/ftl/macros.h"
#include "magenta/system/ulib/mx/include/mx/eventpair.h"
namespace flutter_runner {
class SessionConnection {
public:
SessionConnection(fidl::InterfaceHandle<mozart2::Session> session_handle,
mx::eventpair import_token);
~SessionConnection();
flow::SceneUpdateContext& scene_update_context() {
return scene_update_context_;
}
mozart::client::ImportNode& root_node() {
ASSERT_IS_GPU_THREAD;
return root_node_;
}
void Present(flow::CompositorContext::ScopedFrame& frame,
ftl::Closure on_present_callback);
private:
mozart::client::Session session_;
mozart::client::ImportNode root_node_;
mozart::client::Session::PresentCallback present_callback_;
ftl::Closure pending_on_present_callback_;
std::unique_ptr<VulkanSurfaceProducer> surface_producer_;
flow::SceneUpdateContext scene_update_context_;
void OnSessionError();
void EnqueueClearOps();
void OnPresent(mozart2::PresentationInfoPtr info);
FTL_DISALLOW_COPY_AND_ASSIGN(SessionConnection);
};
} // namespace flutter_runner
#endif // FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/content_handler/software_rasterizer.h"
#include <memory>
#include <utility>
#include "apps/mozart/lib/skia/skia_vmo_surface.h"
#include "lib/ftl/logging.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace flutter_runner {
SoftwareRasterizer::RasterSurfaceProducer::RasterSurfaceProducer() {
buffer_producer_.reset(new mozart::BufferProducer());
}
sk_sp<SkSurface> SoftwareRasterizer::RasterSurfaceProducer::ProduceSurface(
SkISize size,
mozart::ImagePtr* out_image) {
return mozart::MakeSkSurface(size, buffer_producer_.get(), out_image);
}
SoftwareRasterizer::SoftwareRasterizer() : compositor_context_(nullptr) {}
SoftwareRasterizer::~SoftwareRasterizer() = default;
void SoftwareRasterizer::SetScene(fidl::InterfaceHandle<mozart::Scene> scene) {
scene_.Bind(std::move(scene));
surface_producer_.reset(new RasterSurfaceProducer());
}
void SoftwareRasterizer::Draw(std::unique_ptr<flow::LayerTree> layer_tree,
ftl::Closure callback) {
FTL_DCHECK(layer_tree);
if (!scene_) {
callback();
return;
}
compositor_context_.engine_time().SetLapTime(layer_tree->construction_time());
const SkISize& frame_size = layer_tree->frame_size();
auto update = mozart::SceneUpdate::New();
// TODO(abarth): Support incremental updates.
update->clear_resources = true;
update->clear_nodes = true;
if (frame_size.isEmpty()) {
update->nodes.insert(mozart::kSceneRootNodeId, mozart::Node::New());
// Publish the updated scene contents.
// TODO(jeffbrown): We should set the metadata's presentation_time here too.
scene_->Update(std::move(update));
auto metadata = mozart::SceneMetadata::New();
metadata->version = layer_tree->scene_version();
scene_->Publish(std::move(metadata));
callback();
return;
}
flow::CompositorContext::ScopedFrame frame = compositor_context_.AcquireFrame(
nullptr, nullptr, true /* instrumentation enabled */);
layer_tree->Preroll(frame);
flow::SceneUpdateContext context(update.get(), surface_producer_.get());
auto root_node = mozart::Node::New();
root_node->hit_test_behavior = mozart::HitTestBehavior::New();
layer_tree->UpdateScene(context, root_node.get());
update->nodes.insert(mozart::kSceneRootNodeId, std::move(root_node));
// Publish the updated scene contents.
// TODO(jeffbrown): We should set the metadata's presentation_time here too.
scene_->Update(std::move(update));
auto metadata = mozart::SceneMetadata::New();
metadata->version = layer_tree->scene_version();
scene_->Publish(std::move(metadata));
// Draw the contents of the scene to a surface.
// We do this after publishing to take advantage of pipelining.
// The image buffer's fence is signalled automatically when the surface
// goes out of scope.
context.ExecutePaintTasks(frame);
surface_producer_->Tick();
callback();
}
} // namespace flutter_runner
// Copyright 2017 The Chromium 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_CONTENT_HANDLER_SOFTWARE_RASTERIZER_H_
#define FLUTTER_CONTENT_HANDLER_SOFTWARE_RASTERIZER_H_
#include <memory>
#include "apps/mozart/services/buffers/cpp/buffer_producer.h"
#include "flutter/content_handler/rasterizer.h"
#include "flutter/flow/compositor_context.h"
#include "lib/ftl/macros.h"
namespace flutter_runner {
class SoftwareRasterizer : public Rasterizer {
public:
SoftwareRasterizer();
~SoftwareRasterizer() override;
void SetScene(fidl::InterfaceHandle<mozart::Scene> scene) override;
void Draw(std::unique_ptr<flow::LayerTree> layer_tree,
ftl::Closure callback) override;
private:
class RasterSurfaceProducer
: public flow::SceneUpdateContext::SurfaceProducer {
public:
RasterSurfaceProducer();
sk_sp<SkSurface> ProduceSurface(SkISize size,
mozart::ImagePtr* out_image) override;
void Tick() { buffer_producer_->Tick(); }
private:
std::unique_ptr<mozart::BufferProducer> buffer_producer_;
};
mozart::ScenePtr scene_;
std::unique_ptr<RasterSurfaceProducer> surface_producer_;
flow::CompositorContext compositor_context_;
FTL_DISALLOW_COPY_AND_ASSIGN(SoftwareRasterizer);
};
} // namespace flutter_runner
#endif // FLUTTER_CONTENT_HANDLER_SOFTWARE_RASTERIZER_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/content_handler/vulkan_native_rasterizer.h"
#include <utility>
#include "flutter/vulkan/vulkan_native_surface_magma.h"
namespace flutter_runner {
VulkanNativeRasterizer::VulkanNativeRasterizer()
: compositor_context_(nullptr) {
auto proc_table = ftl::MakeRefCounted<vulkan::VulkanProcTable>();
if (!proc_table->HasAcquiredMandatoryProcAddresses()) {
return;
}
auto native_surface = std::make_unique<vulkan::VulkanNativeSurfaceMagma>();
if (!native_surface->IsValid()) {
return;
}
auto window = std::make_unique<vulkan::VulkanWindow>(
proc_table, std::move(native_surface));
if (!window->IsValid()) {
return;
}
window_ = std::move(window);
}
VulkanNativeRasterizer::~VulkanNativeRasterizer() = default;
bool VulkanNativeRasterizer::IsValid() const {
return window_ == nullptr ? false : window_->IsValid();
}
void VulkanNativeRasterizer::SetScene(
fidl::InterfaceHandle<mozart::Scene> scene) {
// TODO: Composition is currently unsupported using the Vulkan backend.
}
void VulkanNativeRasterizer::Draw(std::unique_ptr<flow::LayerTree> layer_tree,
ftl::Closure callback) {
Draw(std::move(layer_tree));
callback();
}
bool VulkanNativeRasterizer::Draw(std::unique_ptr<flow::LayerTree> layer_tree) {
if (layer_tree == nullptr) {
FTL_DLOG(INFO) << "Layer tree was not valid.";
return false;
}
if (!window_->IsValid()) {
FTL_DLOG(INFO) << "Vulkan window was not valid.";
return false;
}
auto surface = window_->AcquireSurface();
if (!surface && surface->getCanvas() != nullptr) {
FTL_DLOG(INFO) << "Could not acquire a vulkan surface.";
return false;
}
{
auto compositor_frame = compositor_context_.AcquireFrame(
window_->GetSkiaGrContext(), // GrContext*
surface->getCanvas(), // SkCanvas
true // instrumentation
);
layer_tree->Raster(compositor_frame);
}
if (!window_->SwapBuffers()) {
FTL_DLOG(INFO) << "Could not swap buffers successfully.";
return false;
}
return true;
}
} // namespace flutter_runner
// Copyright 2017 The Chromium 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_CONTENT_HANDLER_VULKAN_RASTERIZER_H_
#define FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_
#include <memory>
#include "flutter/content_handler/rasterizer.h"
#include "flutter/flow/compositor_context.h"
#include "flutter/vulkan/vulkan_window.h"
#include "lib/ftl/macros.h"
namespace flutter_runner {
class VulkanNativeRasterizer : public Rasterizer {
public:
VulkanNativeRasterizer();
~VulkanNativeRasterizer() override;
bool IsValid() const;
void SetScene(fidl::InterfaceHandle<mozart::Scene> scene) override;
void Draw(std::unique_ptr<flow::LayerTree> layer_tree,
ftl::Closure callback) override;
private:
std::unique_ptr<vulkan::VulkanWindow> window_;
flow::CompositorContext compositor_context_;
bool Draw(std::unique_ptr<flow::LayerTree> layer_tree);
FTL_DISALLOW_COPY_AND_ASSIGN(VulkanNativeRasterizer);
};
} // namespace flutter_runner
#endif // FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_
\ No newline at end of file
......@@ -13,22 +13,22 @@
#include <thread>
#include <utility>
#include "lib/ftl/files/unique_fd.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/vk/GrVkTypes.h"
#include "third_party/skia/src/gpu/vk/GrVkUtil.h"
#include "flutter/common/threads.h"
#include "flutter/glue/trace_event.h"
#include "lib/ftl/files/unique_fd.h"
namespace flutter_runner {
namespace {
constexpr char kDisplayDriverClass[] = "/dev/class/display";
static mx_status_t DriverWatcher(int dirfd, int event, const char* fn, void* cookie) {
if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) {
return MX_ERR_STOP;
}
return MX_OK;
static mx_status_t DriverWatcher(int dirfd,
int event,
const char* fn,
void* cookie) {
if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) {
return MX_ERR_STOP;
}
return MX_OK;
}
bool WaitForFirstDisplayDriver() {
......@@ -38,481 +38,72 @@ bool WaitForFirstDisplayDriver() {
return false;
}
mx_status_t status = mxio_watch_directory(fd.get(), DriverWatcher,
mx_deadline_after(MX_SEC(1)),
nullptr);
mx_status_t status = mxio_watch_directory(
fd.get(), DriverWatcher, mx_deadline_after(MX_SEC(1)), nullptr);
return status == MX_ERR_STOP;
}
} // namespace
VulkanRasterizer::VulkanSurfaceProducer::VulkanSurfaceProducer() {
valid_ = Initialize();
if (!valid_)
FTL_LOG(ERROR) << "VulkanSurfaceProducer failed to initialize";
}
VulkanRasterizer::VulkanSurfaceProducer::~VulkanSurfaceProducer() {
for (auto& surface_info : pending_surfaces_)
mtl::MessageLoop::GetCurrent()->RemoveHandler(
surface_info.second.handler_key);
}
std::unique_ptr<VulkanRasterizer::VulkanSurfaceProducer::Surface>
VulkanRasterizer::VulkanSurfaceProducer::CreateSurface(uint32_t width,
uint32_t height) {
VkResult vk_result;
VkImageCreateInfo image_create_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
.imageType = VK_IMAGE_TYPE_2D,
.format = VK_FORMAT_B8G8R8A8_UNORM,
.extent = VkExtent3D{width, height, 1},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
};
VkImage vk_image;
vk_result = VK_CALL_LOG_ERROR(vkCreateImage(
backend_context_->fDevice, &image_create_info, nullptr, &vk_image));
if (vk_result)
return nullptr;
VkMemoryRequirements memory_reqs;
vkGetImageMemoryRequirements(backend_context_->fDevice, vk_image,
&memory_reqs);
uint32_t memory_type = 0;
for (; memory_type < 32; memory_type++) {
if ((memory_reqs.memoryTypeBits & (1 << memory_type)))
break;
}
VkMemoryAllocateInfo alloc_info = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = nullptr,
.allocationSize = memory_reqs.size,
.memoryTypeIndex = memory_type,
};
VkDeviceMemory vk_memory;
vk_result = VK_CALL_LOG_ERROR(vkAllocateMemory(
backend_context_->fDevice, &alloc_info, NULL, &vk_memory));
if (vk_result)
return nullptr;
vk_result = VK_CALL_LOG_ERROR(
vkBindImageMemory(backend_context_->fDevice, vk_image, vk_memory, 0));
if (vk_result)
return nullptr;
const GrVkImageInfo image_info = {
.fImage = vk_image,
.fAlloc = {vk_memory, 0, memory_reqs.size, 0},
.fImageTiling = image_create_info.tiling,
.fImageLayout = image_create_info.initialLayout,
.fFormat = image_create_info.format,
.fLevelCount = image_create_info.mipLevels,
};
GrBackendRenderTargetDesc desc;
desc.fWidth = width;
desc.fHeight = height;
desc.fConfig = kSBGRA_8888_GrPixelConfig;
desc.fOrigin = kTopLeft_GrSurfaceOrigin;
desc.fSampleCnt = 0;
desc.fStencilBits = 0;
desc.fRenderTargetHandle = reinterpret_cast<GrBackendObject>(&image_info);
SkSurfaceProps props(SkSurfaceProps::InitType::kLegacyFontHost_InitType);
auto sk_surface = SkSurface::MakeFromBackendRenderTarget(context_.get(), desc,
nullptr, &props);
if (!sk_surface) {
FTL_LOG(ERROR) << "MakeFromBackendRenderTarget Failed";
return nullptr;
}
uint32_t vmo_handle;
vk_result = VK_CALL_LOG_ERROR(vkExportDeviceMemoryMAGMA(
backend_context_->fDevice, vk_memory, &vmo_handle));
if (vk_result)
return nullptr;
mx::vmo vmo(vmo_handle);
size_t vmo_size;
vmo.get_size(&vmo_size);
FTL_DCHECK(vmo_size >= memory_reqs.size);
mx::eventpair retention_events[2];
auto mx_status =
mx::eventpair::create(0, &retention_events[0], &retention_events[1]);
if (mx_status) {
FTL_LOG(ERROR) << "Failed to create retention eventpair";
return nullptr;
}
if (!sk_surface || sk_surface->getCanvas() == nullptr) {
FTL_LOG(ERROR) << "surface invalid";
return nullptr;
}
return std::make_unique<Surface>(backend_context_, sk_surface, std::move(vmo),
std::move(retention_events[0]),
std::move(retention_events[1]), vk_image,
vk_memory);
}
sk_sp<SkSurface> VulkanRasterizer::VulkanSurfaceProducer::ProduceSurface(
SkISize size,
mozart::ImagePtr* out_image) {
if (size.isEmpty()) {
FTL_LOG(ERROR) << "Attempting to create surface with empty size";
return nullptr;
}
// these casts are safe because of the early out on frame_size.isEmpty()
auto width = static_cast<uint32_t>(size.width());
auto height = static_cast<uint32_t>(size.height());
std::unique_ptr<Surface> surface;
// try and find a Swapchain with surfaces of the right size
auto it = available_surfaces_.find(MakeSizeKey(width, height));
if (it == available_surfaces_.end()) {
// No matching Swapchain exists, create a new surfaces
surface = CreateSurface(width, height);
} else {
auto& swapchain = it->second;
if (swapchain.queue.size() == 0) {
// matching Swapchain exists, but does not have any buffers available in
// it
surface = CreateSurface(width, height);
} else {
surface = std::move(swapchain.queue.front());
swapchain.queue.pop();
swapchain.tick_count = 0;
// Need to do some skia foo here to clear all the canvas state from the
// last frame
surface->sk_surface->getCanvas()->restoreToCount(0);
surface->sk_surface->getCanvas()->save();
surface->sk_surface->getCanvas()->resetMatrix();
}
}
if (!surface) {
FTL_LOG(ERROR) << "Failed to produce surface";
return nullptr;
}
mx_status_t status;
auto buffer = mozart::Buffer::New();
status = surface->vmo.duplicate(MX_RIGHT_SAME_RIGHTS, &buffer->vmo);
if (status) {
FTL_LOG(ERROR) << "failed to duplicate vmo";
return nullptr;
}
buffer->memory_type = mozart::Buffer::MemoryType::VK_DEVICE_MEMORY;
mx::eventpair fence_event;
status = mx::eventpair::create(0, &fence_event, &buffer->fence);
if (status) {
FTL_LOG(ERROR) << "failed to create fence eventpair";
return nullptr;
}
mtl::MessageLoop::HandlerKey handler_key =
mtl::MessageLoop::GetCurrent()->AddHandler(this, fence_event.get(),
MX_EPAIR_PEER_CLOSED);
status = surface->remote_retention_event.duplicate(MX_RIGHT_SAME_RIGHTS,
&buffer->retention);
if (status) {
FTL_LOG(ERROR) << "failed to duplicate retention eventpair";
return nullptr;
}
auto image = mozart::Image::New();
image->size = mozart::Size::New();
image->size->width = width;
image->size->height = height;
image->stride = 4 * width;
image->pixel_format = mozart::Image::PixelFormat::B8G8R8A8;
image->alpha_format = mozart::Image::AlphaFormat::OPAQUE;
image->color_space = mozart::Image::ColorSpace::SRGB;
image->buffer = std::move(buffer);
*out_image = std::move(image);
auto sk_surface = surface->sk_surface;
PendingSurfaceInfo info;
info.handler_key = handler_key;
info.surface = std::move(surface);
info.production_fence = std::move(fence_event);
outstanding_surfaces_.push_back(std::move(info));
return sk_surface;
}
bool VulkanRasterizer::VulkanSurfaceProducer::FinishFrame() {
mx_status_t status;
// Finish Rendering
context_->flush();
VkResult result =
VK_CALL_LOG_ERROR(vkQueueWaitIdle(backend_context_->fQueue));
if (result)
return false;
for (auto& info : outstanding_surfaces_) {
// info.surface->sk_surface->prepareForExternalIO();
// Signal the compositor
status = info.production_fence.signal_peer(0u, MX_EPAIR_SIGNALED);
if (status) {
FTL_LOG(ERROR) << "failed to signal fence event";
return false;
}
pending_surfaces_.insert(
std::make_pair(info.production_fence.get(), std::move(info)));
}
outstanding_surfaces_.clear();
return true;
}
void VulkanRasterizer::VulkanSurfaceProducer::Tick() {
for (auto it = available_surfaces_.begin();
it != available_surfaces_.end();) {
auto& swapchain = it->second;
swapchain.tick_count++;
if (swapchain.tick_count > Swapchain::kMaxTickBeforeDiscard)
it = available_surfaces_.erase(it);
else
it++;
}
}
void VulkanRasterizer::VulkanSurfaceProducer::OnHandleReady(
mx_handle_t handle,
mx_signals_t pending,
uint64_t count) {
FTL_DCHECK(pending & MX_EPAIR_PEER_CLOSED);
auto it = pending_surfaces_.find(handle);
FTL_DCHECK(it != pending_surfaces_.end());
// Add the newly available buffer to the swapchain.
PendingSurfaceInfo& info = it->second;
mtl::MessageLoop::GetCurrent()->RemoveHandler(info.handler_key);
// try and find a Swapchain with surfaces of the right size
size_key_t key = MakeSizeKey(info.surface->sk_surface->width(),
info.surface->sk_surface->height());
auto swapchain_it = available_surfaces_.find(key);
if (swapchain_it == available_surfaces_.end()) {
// No matching Swapchain exists, create one
Swapchain swapchain;
if (swapchain.queue.size() + 1 <= Swapchain::kMaxSurfaces) {
swapchain.queue.push(std::move(info.surface));
}
available_surfaces_.insert(std::make_pair(key, std::move(swapchain)));
} else {
auto& swapchain = swapchain_it->second;
if (swapchain.queue.size() + 1 <= Swapchain::kMaxSurfaces) {
swapchain.queue.push(std::move(info.surface));
}
}
pending_surfaces_.erase(it);
}
bool VulkanRasterizer::VulkanSurfaceProducer::Initialize() {
vk_ = ftl::MakeRefCounted<vulkan::VulkanProcTable>();
std::vector<std::string> extensions = {VK_KHR_SURFACE_EXTENSION_NAME};
application_ = std::make_unique<vulkan::VulkanApplication>(
*vk_, "Flutter", std::move(extensions));
if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) {
// Make certain the application instance was created and it setup the
// instance proc table entries.
FTL_LOG(ERROR) << "Instance proc addresses have not been setup.";
return false;
}
// Create the device.
logical_device_ = application_->AcquireFirstCompatibleLogicalDevice();
if (logical_device_ == nullptr || !logical_device_->IsValid() ||
!vk_->AreDeviceProcsSetup()) {
// Make certain the device was created and it setup the device proc table
// entries.
FTL_LOG(ERROR) << "Device proc addresses have not been setup.";
return false;
}
if (!vk_->HasAcquiredMandatoryProcAddresses()) {
FTL_LOG(ERROR) << "Failed to acquire mandatory proc addresses";
return false;
}
if (!vk_->IsValid()) {
FTL_LOG(ERROR) << "VulkanProcTable invalid";
return false;
}
auto interface = vk_->CreateSkiaInterface();
if (interface == nullptr || !interface->validate(0)) {
FTL_LOG(ERROR) << "interface invalid";
return false;
}
uint32_t skia_features = 0;
if (!logical_device_->GetPhysicalDeviceFeaturesSkia(&skia_features)) {
FTL_LOG(ERROR) << "Failed to get physical device features";
return false;
}
backend_context_ = sk_make_sp<GrVkBackendContext>();
backend_context_->fInstance = application_->GetInstance();
backend_context_->fPhysicalDevice =
logical_device_->GetPhysicalDeviceHandle();
backend_context_->fDevice = logical_device_->GetHandle();
backend_context_->fQueue = logical_device_->GetQueueHandle();
backend_context_->fGraphicsQueueIndex =
logical_device_->GetGraphicsQueueIndex();
backend_context_->fMinAPIVersion = application_->GetAPIVersion();
backend_context_->fFeatures = skia_features;
backend_context_->fInterface.reset(interface.release());
logical_device_->ReleaseDeviceOwnership();
application_->ReleaseInstanceOwnership();
context_.reset(GrContext::Create(
kVulkan_GrBackend,
reinterpret_cast<GrBackendContext>(backend_context_.get())));
context_->setResourceCacheLimits(vulkan::kGrCacheMaxCount,
vulkan::kGrCacheMaxByteSize);
FTL_DLOG(INFO) << "Successfully initialized VulkanRasterizer";
return true;
}
VulkanRasterizer::VulkanRasterizer() : compositor_context_(nullptr) {
valid_ = WaitForFirstDisplayDriver();
surface_producer_.reset(new VulkanSurfaceProducer());
}
VulkanRasterizer::~VulkanRasterizer() = default;
bool VulkanRasterizer::IsValid() const {
return valid_ && surface_producer_ && surface_producer_->IsValid();
return valid_;
}
void VulkanRasterizer::SetScene(fidl::InterfaceHandle<mozart::Scene> scene) {
scene_.Bind(std::move(scene));
void VulkanRasterizer::SetSession(
fidl::InterfaceHandle<mozart2::Session> session,
mx::eventpair import_token) {
ASSERT_IS_GPU_THREAD;
FTL_DCHECK(valid_ && !session_connection_);
session_connection_ = std::make_unique<SessionConnection>(
std::move(session), std::move(import_token));
}
void VulkanRasterizer::Draw(std::unique_ptr<flow::LayerTree> layer_tree,
ftl::Closure callback) {
Draw(std::move(layer_tree));
callback();
}
ASSERT_IS_GPU_THREAD;
FTL_DCHECK(callback != nullptr);
bool VulkanRasterizer::Draw(std::unique_ptr<flow::LayerTree> layer_tree) {
if (layer_tree == nullptr) {
FTL_LOG(ERROR) << "Layer tree was not valid.";
return false;
callback();
return;
}
if (!scene_) {
FTL_LOG(ERROR) << "Scene was not valid.";
return false;
if (!session_connection_) {
FTL_LOG(ERROR) << "Session was not valid.";
callback();
return;
}
compositor_context_.engine_time().SetLapTime(layer_tree->construction_time());
const SkISize& frame_size = layer_tree->frame_size();
auto update = mozart::SceneUpdate::New();
// TODO(abarth): Support incremental updates.
update->clear_resources = true;
update->clear_nodes = true;
if (frame_size.isEmpty()) {
update->nodes.insert(mozart::kSceneRootNodeId, mozart::Node::New());
// Publish the updated scene contents.
// TODO(jeffbrown): We should set the metadata's presentation_time here too.
scene_->Update(std::move(update));
auto metadata = mozart::SceneMetadata::New();
metadata->version = layer_tree->scene_version();
scene_->Publish(std::move(metadata));
FTL_LOG(ERROR) << "Publishing empty node";
return false;
}
flow::CompositorContext::ScopedFrame frame = compositor_context_.AcquireFrame(
nullptr, nullptr, true /* instrumentation enabled */);
{
// Preroll the Flutter layer tree. This allows Flutter to perform pre-paint
// optimizations.
TRACE_EVENT0("flutter", "Preroll");
layer_tree->Preroll(frame);
}
flow::SceneUpdateContext context(update.get(), surface_producer_.get());
auto root_node = mozart::Node::New();
{
// Traverse the Flutter layer tree so that the necessary session ops to
// represent the frame are enqueued in the underlying session.
TRACE_EVENT0("flutter", "UpdateScene");
root_node->hit_test_behavior = mozart::HitTestBehavior::New();
layer_tree->UpdateScene(context, root_node.get());
update->nodes.insert(mozart::kSceneRootNodeId, std::move(root_node));
// Publish the updated scene contents.
// TODO(jeffbrown): We should set the metadata's presentation_time here too.
scene_->Update(std::move(update));
}
{
TRACE_EVENT0("flutter", "Publish");
auto metadata = mozart::SceneMetadata::New();
metadata->version = layer_tree->scene_version();
scene_->Publish(std::move(metadata));
layer_tree->UpdateScene(session_connection_->scene_update_context(),
session_connection_->root_node());
}
{
TRACE_EVENT0("flutter", "ExecutePaintTasks");
// Draw the contents of the scene to a surface.
// We do this after publishing to take advantage of pipelining.
context.ExecutePaintTasks(frame);
// Flush all pending session ops.
TRACE_EVENT0("flutter", "SessionPresent");
session_connection_->Present(
frame, [callback = std::move(callback)]() { callback(); });
}
{
TRACE_EVENT0("flutter", "FinishFrame/Tick");
if (!surface_producer_->FinishFrame()) {
FTL_LOG(ERROR) << "Failed to Finish Frame";
return false;
}
surface_producer_->Tick();
}
return true;
}
} // namespace flutter_runner
......@@ -6,17 +6,11 @@
#define FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_
#include <memory>
#include <queue>
#include <unordered_map>
#include <vector>
#include "apps/mozart/services/buffers/cpp/buffer_producer.h"
#include "flutter/content_handler/rasterizer.h"
#include "flutter/content_handler/session_connection.h"
#include "flutter/flow/compositor_context.h"
#include "flutter/vulkan/vulkan_application.h"
#include "flutter/vulkan/vulkan_device.h"
#include "lib/ftl/macros.h"
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
namespace flutter_runner {
......@@ -28,124 +22,17 @@ class VulkanRasterizer : public Rasterizer {
bool IsValid() const;
void SetScene(fidl::InterfaceHandle<mozart::Scene> scene) override;
void SetSession(fidl::InterfaceHandle<mozart2::Session> session,
mx::eventpair import_token) override;
void Draw(std::unique_ptr<flow::LayerTree> layer_tree,
ftl::Closure callback) override;
private:
class VulkanSurfaceProducer
: public flow::SceneUpdateContext::SurfaceProducer,
private mtl::MessageLoopHandler {
public:
VulkanSurfaceProducer();
~VulkanSurfaceProducer() override;
sk_sp<SkSurface> ProduceSurface(SkISize size,
mozart::ImagePtr* out_image) override;
void Tick();
bool FinishFrame();
bool IsValid() const { return valid_; }
private:
// |mtl::MessageLoopHandler|
void OnHandleReady(mx_handle_t handle,
mx_signals_t pending,
uint64_t count) override;
struct Surface {
sk_sp<GrVkBackendContext> backend_context;
sk_sp<SkSurface> sk_surface;
mx::vmo vmo;
mx::eventpair local_retention_event;
mx::eventpair remote_retention_event;
VkImage vk_image;
VkDeviceMemory vk_memory;
Surface(sk_sp<GrVkBackendContext> backend_context,
sk_sp<SkSurface> sk_surface,
mx::vmo vmo,
mx::eventpair local_retention_event,
mx::eventpair remote_retention_event,
VkImage vk_image,
VkDeviceMemory vk_memory)
: backend_context(std::move(backend_context)),
sk_surface(std::move(sk_surface)),
vmo(std::move(vmo)),
local_retention_event(std::move(local_retention_event)),
remote_retention_event(std::move(remote_retention_event)),
vk_image(vk_image),
vk_memory(vk_memory) {}
~Surface() {
FTL_DCHECK(backend_context);
vkFreeMemory(backend_context->fDevice, vk_memory, NULL);
vkDestroyImage(backend_context->fDevice, vk_image, NULL);
}
};
std::unique_ptr<Surface> CreateSurface(uint32_t width, uint32_t height);
struct Swapchain {
std::queue<std::unique_ptr<Surface>> queue;
uint32_t tick_count = 0;
static constexpr uint32_t kMaxSurfaces = 3;
static constexpr uint32_t kMaxTickBeforeDiscard = 3;
};
using size_key_t = uint64_t;
static size_key_t MakeSizeKey(uint32_t width, uint32_t height) {
return (static_cast<uint64_t>(width) << 32) |
static_cast<uint64_t>(height);
}
// Note: the order here is very important. The proctable bust be destroyed
// last because it contains the function pointers for VkDestroyDevice and
// VkDestroyInstance. The backend context owns the VkDevice and the
// VkInstance, so it must be destroyed after the logical device and the
// application, which own other vulkan objects associated with the device
// and instance
ftl::RefPtr<vulkan::VulkanProcTable> vk_;
sk_sp<GrVkBackendContext> backend_context_;
std::unique_ptr<vulkan::VulkanDevice> logical_device_;
std::unique_ptr<vulkan::VulkanApplication> application_;
sk_sp<GrContext> context_;
// These three containers hold surfaces in various stages of recycling
// Buffers exist in available_surfaces_ when they are ready to be recycled
// ProduceSurface will look here for an appropriately sized surface before
// creating a new one
// The Swapchain's tick_count is incremented in Tick and decremented when
// a surface is taken from the queue, when the tick count goes above
// kMaxTickBeforeDiscard the Swapchain is discarded. Newly surfaces are
// added to the queue iff there aar less than kMaxSurfaces already in the
// queue
std::unordered_map<size_key_t, Swapchain> available_surfaces_;
struct PendingSurfaceInfo {
mtl::MessageLoop::HandlerKey handler_key;
std::unique_ptr<Surface> surface;
mx::eventpair production_fence;
};
// Surfaces produced by ProduceSurface live in outstanding_surfaces_ until
// FinishFrame is called, at which point they are moved to pending_surfaces_
std::vector<PendingSurfaceInfo> outstanding_surfaces_;
// Surfaces exist in pendind surfaces until they are released by the buffer
// consumer
std::unordered_map<mx_handle_t, PendingSurfaceInfo> pending_surfaces_;
bool valid_;
bool Initialize();
};
flow::CompositorContext compositor_context_;
mozart::ScenePtr scene_;
std::unique_ptr<VulkanSurfaceProducer> surface_producer_;
std::unique_ptr<SessionConnection> session_connection_;
bool valid_;
bool Draw(std::unique_ptr<flow::LayerTree> layer_tree);
FTL_DISALLOW_COPY_AND_ASSIGN(VulkanRasterizer);
};
......
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/content_handler/vulkan_surface.h"
#include "flutter/common/threads.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/src/gpu/vk/GrVkImage.h"
namespace flutter_runner {
VulkanSurface::VulkanSurface(vulkan::VulkanProcTable& p_vk,
sk_sp<GrContext> context,
sk_sp<GrVkBackendContext> backend_context,
mozart::client::Session* session,
const SkISize& size)
: vk_(p_vk),
backend_context_(std::move(backend_context)),
session_(session) {
ASSERT_IS_GPU_THREAD;
FTL_DCHECK(session_);
mx::vmo exported_vmo;
if (!AllocateDeviceMemory(std::move(context), size, exported_vmo)) {
FTL_DLOG(INFO) << "Could not allocate device memory.";
return;
}
if (!CreateFences()) {
FTL_DLOG(INFO) << "Could not create signal fences.";
return;
}
if (!PushSessionImageSetupOps(session, std::move(exported_vmo))) {
FTL_DLOG(INFO) << "Could not push session image setup ops.";
return;
}
event_handler_key_ = mtl::MessageLoop::GetCurrent()->AddHandler(
this, release_event_.get(), MX_USER_SIGNAL_0);
// Probably not necessary as the events should be in the unsignalled state
// already.
Reset();
valid_ = true;
}
VulkanSurface::~VulkanSurface() {
ASSERT_IS_GPU_THREAD;
if (event_handler_key_ != 0) {
mtl::MessageLoop::GetCurrent()->RemoveHandler(event_handler_key_);
event_handler_key_ = 0;
}
}
bool VulkanSurface::IsValid() const {
return valid_;
}
SkISize VulkanSurface::GetSize() const {
if (!valid_) {
return SkISize::Make(0, 0);
}
return SkISize::Make(sk_surface_->width(), sk_surface_->height());
}
bool VulkanSurface::CreateFences() {
if (mx::event::create(0, &acquire_event_) != MX_OK) {
return false;
}
if (mx::event::create(0, &release_event_) != MX_OK) {
return false;
}
return true;
}
bool VulkanSurface::AllocateDeviceMemory(sk_sp<GrContext> context,
const SkISize& size,
mx::vmo& exported_vmo) {
if (size.isEmpty()) {
return false;
}
if (backend_context_ == nullptr) {
return false;
}
// Create the image.
const VkImageCreateInfo image_create_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
.imageType = VK_IMAGE_TYPE_2D,
.format = VK_FORMAT_B8G8R8A8_UNORM,
.extent = VkExtent3D{static_cast<uint32_t>(size.width()),
static_cast<uint32_t>(size.height()), 1},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
};
{
VkImage vk_image = VK_NULL_HANDLE;
if (VK_CALL_LOG_ERROR(vk_.CreateImage(backend_context_->fDevice,
&image_create_info, nullptr,
&vk_image)) != VK_SUCCESS) {
return false;
}
vk_image_ = {vk_image, [this](VkImage image) {
vk_.DestroyImage(backend_context_->fDevice, image, NULL);
}};
}
// Create the memory.
VkMemoryRequirements memory_reqs;
vk_.GetImageMemoryRequirements(backend_context_->fDevice, //
vk_image_, //
&memory_reqs //
);
uint32_t memory_type = 0;
for (; memory_type < 32; memory_type++) {
if ((memory_reqs.memoryTypeBits & (1 << memory_type))) {
break;
}
}
const VkMemoryAllocateInfo alloc_info = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = nullptr,
.allocationSize = memory_reqs.size,
.memoryTypeIndex = memory_type,
};
{
VkDeviceMemory vk_memory = VK_NULL_HANDLE;
if (VK_CALL_LOG_ERROR(vk_.AllocateMemory(backend_context_->fDevice,
&alloc_info, NULL, &vk_memory)) !=
VK_SUCCESS) {
return false;
}
vk_memory_ = {vk_memory, [this](VkDeviceMemory memory) {
vk_.FreeMemory(backend_context_->fDevice, memory, NULL);
}};
}
// Bind image memory.
if (VK_CALL_LOG_ERROR(vk_.BindImageMemory(
backend_context_->fDevice, vk_image_, vk_memory_, 0)) != VK_SUCCESS) {
return false;
}
{
// Acquire the VMO for the device memory.
uint32_t vmo_handle = 0;
if (VK_CALL_LOG_ERROR(vk_.ExportDeviceMemoryMAGMA(
backend_context_->fDevice, vk_memory_, &vmo_handle)) !=
VK_SUCCESS) {
return false;
}
exported_vmo.reset(static_cast<mx_handle_t>(vmo_handle));
}
// Assert that the VMO size was sufficient.
size_t vmo_size = 0;
if (exported_vmo.get_size(&vmo_size) != MX_OK ||
vmo_size < memory_reqs.size) {
return false;
}
return SetupSkiaSurface(std::move(context), size, image_create_info,
memory_reqs);
}
bool VulkanSurface::SetupSkiaSurface(sk_sp<GrContext> context,
const SkISize& size,
const VkImageCreateInfo& image_create_info,
const VkMemoryRequirements& memory_reqs) {
if (context == nullptr) {
return false;
}
const GrVkImageInfo image_info = {
.fImage = vk_image_,
.fAlloc = {vk_memory_, 0, memory_reqs.size, 0},
.fImageTiling = image_create_info.tiling,
.fImageLayout = image_create_info.initialLayout,
.fFormat = image_create_info.format,
.fLevelCount = image_create_info.mipLevels,
};
GrBackendRenderTargetDesc sk_render_target_desc;
sk_render_target_desc.fWidth = size.width();
sk_render_target_desc.fHeight = size.height();
sk_render_target_desc.fConfig = kSBGRA_8888_GrPixelConfig;
sk_render_target_desc.fOrigin = kTopLeft_GrSurfaceOrigin;
sk_render_target_desc.fSampleCnt = 0;
sk_render_target_desc.fStencilBits = 0;
sk_render_target_desc.fRenderTargetHandle =
reinterpret_cast<GrBackendObject>(&image_info);
SkSurfaceProps sk_surface_props(
SkSurfaceProps::InitType::kLegacyFontHost_InitType);
auto sk_surface =
SkSurface::MakeFromBackendRenderTarget(context.get(), //
sk_render_target_desc, //
nullptr, //
&sk_surface_props //
);
if (!sk_surface || sk_surface->getCanvas() == nullptr) {
return false;
}
sk_surface_ = std::move(sk_surface);
return true;
}
bool VulkanSurface::PushSessionImageSetupOps(mozart::client::Session* session,
mx::vmo exported_vmo) {
if (sk_surface_ == nullptr) {
return false;
}
mozart::client::Memory memory(session, std::move(exported_vmo),
mozart2::MemoryType::VK_DEVICE_MEMORY);
auto image_info = mozart2::ImageInfo::New();
image_info->width = sk_surface_->width();
image_info->height = sk_surface_->height();
image_info->stride = 4 * sk_surface_->width();
image_info->pixel_format = mozart2::ImageInfo::PixelFormat::BGRA_8;
image_info->color_space = mozart2::ImageInfo::ColorSpace::SRGB;
image_info->tiling = mozart2::ImageInfo::Tiling::LINEAR;
session_image_ = std::make_unique<mozart::client::Image>(
memory, 0 /* memory offset */, std::move(image_info));
return session_image_ != nullptr;
}
mozart::client::Image* VulkanSurface::GetImage() {
ASSERT_IS_GPU_THREAD;
if (!valid_) {
return 0;
}
return session_image_.get();
}
sk_sp<SkSurface> VulkanSurface::GetSkiaSurface() const {
ASSERT_IS_GPU_THREAD;
return valid_ ? sk_surface_ : nullptr;
}
size_t VulkanSurface::AdvanceAndGetAge() {
age_++;
return age_;
}
bool VulkanSurface::FlushSessionAcquireAndReleaseEvents() {
mx::event acquire, release;
if (acquire_event_.duplicate(MX_RIGHT_SAME_RIGHTS, &acquire) != MX_OK ||
release_event_.duplicate(MX_RIGHT_SAME_RIGHTS, &release) != MX_OK) {
return false;
}
session_->EnqueueAcquireFence(std::move(acquire));
session_->EnqueueReleaseFence(std::move(release));
age_ = 0;
return true;
}
void VulkanSurface::SignalWritesFinished(
std::function<void(void)> on_writes_committed) {
ASSERT_IS_GPU_THREAD;
FTL_DCHECK(on_writes_committed);
if (!valid_) {
on_writes_committed();
return;
}
FTL_CHECK(pending_on_writes_committed_ == nullptr)
<< "Attempted to signal a write on the surface when the previous write "
"has not yet been acknowledged by the compositor.";
// Signal the acquire end to the compositor.
if (acquire_event_.signal(0u, MX_USER_SIGNAL_0) != MX_OK) {
on_writes_committed();
return;
}
pending_on_writes_committed_ = on_writes_committed;
}
void VulkanSurface::Reset() {
ASSERT_IS_GPU_THREAD;
if (acquire_event_.signal(MX_USER_SIGNAL_0, 0u) != MX_OK ||
release_event_.signal(MX_USER_SIGNAL_0, 0u) != MX_OK) {
valid_ = false;
FTL_DLOG(ERROR)
<< "Could not reset fences. The surface is no longer valid.";
}
// It is safe for the caller to collect the surface in the callback.
auto callback = pending_on_writes_committed_;
pending_on_writes_committed_ = nullptr;
if (callback) {
callback();
}
}
void VulkanSurface::OnHandleReady(mx_handle_t handle,
mx_signals_t pending,
uint64_t count) {
ASSERT_IS_GPU_THREAD;
FTL_DCHECK(pending & MX_USER_SIGNAL_0);
FTL_DCHECK(handle == release_event_.get());
Reset();
}
} // namespace flutter_runner
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <memory>
#include "apps/mozart/lib/scene/client/resources.h"
#include "flutter/flow/scene_update_context.h"
#include "flutter/vulkan/vulkan_handle.h"
#include "flutter/vulkan/vulkan_proc_table.h"
#include "lib/ftl/macros.h"
#include "lib/mtl/tasks/message_loop.h"
#include "lib/mtl/tasks/message_loop_handler.h"
#include "mx/event.h"
#include "mx/vmo.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
namespace flutter_runner {
class VulkanSurface : public flow::SceneUpdateContext::SurfaceProducerSurface,
public mtl::MessageLoopHandler {
public:
VulkanSurface(vulkan::VulkanProcTable& p_vk,
sk_sp<GrContext> context,
sk_sp<GrVkBackendContext> backend_context,
mozart::client::Session* session,
const SkISize& size);
~VulkanSurface() override;
size_t AdvanceAndGetAge() override;
bool FlushSessionAcquireAndReleaseEvents() override;
bool IsValid() const override;
SkISize GetSize() const override;
// Note: It is safe for the caller to collect the surface in the
// |on_writes_committed| callback.
void SignalWritesFinished(
std::function<void(void)> on_writes_committed) override;
// |flow::SceneUpdateContext::SurfaceProducerSurface|
mozart::client::Image* GetImage() override;
// |flow::SceneUpdateContext::SurfaceProducerSurface|
sk_sp<SkSurface> GetSkiaSurface() const override;
private:
vulkan::VulkanProcTable& vk_;
sk_sp<GrVkBackendContext> backend_context_;
mozart::client::Session* session_;
vulkan::VulkanHandle<VkImage> vk_image_;
vulkan::VulkanHandle<VkDeviceMemory> vk_memory_;
sk_sp<SkSurface> sk_surface_;
std::unique_ptr<mozart::client::Image> session_image_;
mx::event acquire_event_;
mx::event release_event_;
mtl::MessageLoop::HandlerKey event_handler_key_ = 0;
std::function<void(void)> pending_on_writes_committed_;
size_t age_ = 0;
bool valid_ = false;
// |mtl::MessageLoopHandler|
void OnHandleReady(mx_handle_t handle,
mx_signals_t pending,
uint64_t count) override;
bool AllocateDeviceMemory(sk_sp<GrContext> context,
const SkISize& size,
mx::vmo& exported_vmo);
bool SetupSkiaSurface(sk_sp<GrContext> context,
const SkISize& size,
const VkImageCreateInfo& image_create_info,
const VkMemoryRequirements& memory_reqs);
bool CreateFences();
bool PushSessionImageSetupOps(mozart::client::Session* session,
mx::vmo exported_vmo);
void Reset();
FTL_DISALLOW_COPY_AND_ASSIGN(VulkanSurface);
};
} // namespace flutter_runner
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/content_handler/vulkan_surface_pool.h"
#include "apps/tracing/lib/trace/event.h"
#include "third_party/skia/include/gpu/GrContext.h"
namespace flutter_runner {
VulkanSurfacePool::VulkanSurfacePool(vulkan::VulkanProcTable& p_vk,
sk_sp<GrContext> context,
sk_sp<GrVkBackendContext> backend_context,
mozart::client::Session* mozart_session)
: vk_(p_vk),
context_(std::move(context)),
backend_context_(std::move(backend_context)),
mozart_session_(mozart_session) {}
VulkanSurfacePool::~VulkanSurfacePool() {}
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
VulkanSurfacePool::AcquireSurface(const SkISize& size) {
auto surface = GetCachedOrCreateSurface(size);
if (surface == nullptr) {
FTL_DLOG(ERROR) << "Could not acquire surface";
return nullptr;
}
if (!surface->FlushSessionAcquireAndReleaseEvents()) {
FTL_DLOG(ERROR) << "Could not flush acquir/release events for buffer.";
return nullptr;
}
return surface;
}
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
VulkanSurfacePool::GetCachedOrCreateSurface(const SkISize& size) {
auto found_in_available = available_surfaces_.find(size);
if (found_in_available == available_surfaces_.end()) {
return CreateSurface(size);
}
SurfacesSet& available_surfaces = found_in_available->second;
FTL_DCHECK(available_surfaces.size() > 0);
auto acquired_surface = std::move(available_surfaces.back());
available_surfaces.pop_back();
if (available_surfaces.size() == 0) {
available_surfaces_.erase(found_in_available);
}
if (acquired_surface->IsValid()) {
trace_surfaces_reused_++;
return acquired_surface;
}
// This is only likely to happen if the surface was invalidated between the
// time it was sent into the available buffers cache and accessed now.
// Extremely unlikely.
return CreateSurface(size);
}
void VulkanSurfacePool::SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
p_surface) {
if (!p_surface) {
return;
}
uintptr_t surface_key = reinterpret_cast<uintptr_t>(p_surface.get());
auto insert_iterator =
pending_surfaces_.insert(std::make_pair(surface_key, // key
std::move(p_surface) // value
));
if (insert_iterator.second) {
insert_iterator.first->second->SignalWritesFinished(
std::bind(&VulkanSurfacePool::RecycleSurface, this, surface_key));
}
}
std::unique_ptr<VulkanSurface> VulkanSurfacePool::CreateSurface(
const SkISize& size) {
auto surface = std::make_unique<VulkanSurface>(
vk_, context_, backend_context_, mozart_session_, size);
if (!surface->IsValid()) {
return nullptr;
}
trace_surfaces_created_++;
return surface;
}
void VulkanSurfacePool::RecycleSurface(uintptr_t surface_key) {
// Before we do anything, we must clear the surface from the collection of
// pending surfaces.
auto found_in_pending = pending_surfaces_.find(surface_key);
if (found_in_pending == pending_surfaces_.end()) {
return;
}
// Grab a hold of the surface to recycle and clear the entry in the pending
// surfaces collection.
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
surface_to_recycle = std::move(found_in_pending->second);
pending_surfaces_.erase(found_in_pending);
// The surface may have become invalid (for example it the fences could
// not be reset).
if (!surface_to_recycle->IsValid()) {
return;
}
// Recycle the buffer by putting it in the list of available surfaces if the
// maximum size of buffers in the collection is not already present.
auto& available_surfaces = available_surfaces_[surface_to_recycle->GetSize()];
if (available_surfaces.size() < kMaxSurfacesOfSameSize) {
available_surfaces.emplace_back(std::move(surface_to_recycle));
}
}
void VulkanSurfacePool::AgeAndCollectOldBuffers() {
std::vector<SkISize> sizes_to_erase;
for (auto& surface_iterator : available_surfaces_) {
SurfacesSet& old_surfaces = surface_iterator.second;
SurfacesSet new_surfaces;
for (auto& surface : old_surfaces) {
if (surface->AdvanceAndGetAge() < kMaxSurfaceAge) {
new_surfaces.emplace_back(std::move(surface));
}
}
if (new_surfaces.size() == 0) {
sizes_to_erase.emplace_back(surface_iterator.first);
}
old_surfaces.swap(new_surfaces);
}
for (const auto& size : sizes_to_erase) {
available_surfaces_.erase(size);
}
TraceStats();
}
void VulkanSurfacePool::TraceStats() {
// Resources held in cached buffers.
size_t cached_surfaces = 0;
size_t cached_surfaces_bytes = 0;
for (const auto& surfaces : available_surfaces_) {
const auto surface_count = surfaces.second.size();
cached_surfaces += surface_count;
// TODO(chinmaygarde): Assuming for now that all surfaces are 32bpp.
cached_surfaces_bytes +=
(surfaces.first.fWidth * surfaces.first.fHeight * 4 * surface_count);
}
// Resources held by Skia.
int skia_resources = 0;
size_t skia_bytes = 0;
context_->getResourceCacheUsage(&skia_resources, &skia_bytes);
const size_t skia_cache_purgeable =
context_->getResourceCachePurgeableBytes();
TRACE_COUNTER("flutter", "SurfacePool", 0u, //
"CachedCount", cached_surfaces, //
"CachedBytes", cached_surfaces_bytes, //
"Created", trace_surfaces_created_, //
"Reused", trace_surfaces_reused_, //
"PendingInCompositor", pending_surfaces_.size(), //
"SkiaCacheResources", skia_resources, //
"SkiaCacheBytes", skia_bytes, //
"SkiaCachePurgeable", skia_cache_purgeable //
);
// Reset per present/frame stats.
trace_surfaces_created_ = 0;
trace_surfaces_reused_ = 0;
}
} // namespace flutter_runner
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <list>
#include <unordered_map>
#include "flutter/content_handler/vulkan_surface.h"
#include "lib/ftl/macros.h"
namespace flutter_runner {
class VulkanSurfacePool {
public:
static const size_t kMaxSurfacesOfSameSize = 3;
static const size_t kMaxSurfaceAge = 3;
VulkanSurfacePool(vulkan::VulkanProcTable& vk,
sk_sp<GrContext> context,
sk_sp<GrVkBackendContext> backend_context,
mozart::client::Session* mozart_session);
~VulkanSurfacePool();
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
AcquireSurface(const SkISize& size);
void SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
surface);
void AgeAndCollectOldBuffers();
private:
using SurfacesSet = std::list<
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>;
template <class T>
static void HashCombine(size_t& seed, T const& v) {
seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
struct SkISizeHash {
std::size_t operator()(const SkISize& key) const {
size_t seed = 0;
HashCombine(seed, key.fWidth);
HashCombine(seed, key.fHeight);
return seed;
}
};
vulkan::VulkanProcTable& vk_;
sk_sp<GrContext> context_;
sk_sp<GrVkBackendContext> backend_context_;
mozart::client::Session* mozart_session_;
std::unordered_map<SkISize, SurfacesSet, SkISizeHash> available_surfaces_;
std::unordered_map<
uintptr_t,
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>
pending_surfaces_;
size_t trace_surfaces_created_ = 0;
size_t trace_surfaces_reused_ = 0;
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
GetCachedOrCreateSurface(const SkISize& size);
std::unique_ptr<VulkanSurface> CreateSurface(const SkISize& size);
void RecycleSurface(uintptr_t surface_key);
void TraceStats();
FTL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfacePool);
};
} // namespace flutter_runner
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/content_handler/vulkan_surface_producer.h"
#include <memory>
#include <string>
#include <vector>
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/vk/GrVkTypes.h"
#include "third_party/skia/src/gpu/vk/GrVkUtil.h"
namespace flutter_runner {
VulkanSurfaceProducer::VulkanSurfaceProducer(
mozart::client::Session* mozart_session) {
valid_ = Initialize(mozart_session);
FTL_LOG(ERROR) << "Vulkan surface producer initialization: "
<< (valid_ ? "Successful" : "Failed");
}
VulkanSurfaceProducer::~VulkanSurfaceProducer() = default;
bool VulkanSurfaceProducer::Initialize(
mozart::client::Session* mozart_session) {
vk_ = ftl::MakeRefCounted<vulkan::VulkanProcTable>();
std::vector<std::string> extensions = {VK_KHR_SURFACE_EXTENSION_NAME};
application_ = std::make_unique<vulkan::VulkanApplication>(
*vk_, "FlutterContentHandler", std::move(extensions));
if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) {
// Make certain the application instance was created and it setup the
// instance proc table entries.
FTL_LOG(ERROR) << "Instance proc addresses have not been setup.";
return false;
}
// Create the device.
logical_device_ = application_->AcquireFirstCompatibleLogicalDevice();
if (logical_device_ == nullptr || !logical_device_->IsValid() ||
!vk_->AreDeviceProcsSetup()) {
// Make certain the device was created and it setup the device proc table
// entries.
FTL_LOG(ERROR) << "Device proc addresses have not been setup.";
return false;
}
if (!vk_->HasAcquiredMandatoryProcAddresses()) {
FTL_LOG(ERROR) << "Failed to acquire mandatory proc addresses";
return false;
}
if (!vk_->IsValid()) {
FTL_LOG(ERROR) << "VulkanProcTable invalid";
return false;
}
auto interface = vk_->CreateSkiaInterface();
if (interface == nullptr || !interface->validate(0)) {
FTL_LOG(ERROR) << "interface invalid";
return false;
}
uint32_t skia_features = 0;
if (!logical_device_->GetPhysicalDeviceFeaturesSkia(&skia_features)) {
FTL_LOG(ERROR) << "Failed to get physical device features";
return false;
}
backend_context_ = sk_make_sp<GrVkBackendContext>();
backend_context_->fInstance = application_->GetInstance();
backend_context_->fPhysicalDevice =
logical_device_->GetPhysicalDeviceHandle();
backend_context_->fDevice = logical_device_->GetHandle();
backend_context_->fQueue = logical_device_->GetQueueHandle();
backend_context_->fGraphicsQueueIndex =
logical_device_->GetGraphicsQueueIndex();
backend_context_->fMinAPIVersion = application_->GetAPIVersion();
backend_context_->fFeatures = skia_features;
backend_context_->fInterface.reset(interface.release());
logical_device_->ReleaseDeviceOwnership();
application_->ReleaseInstanceOwnership();
context_.reset(GrContext::Create(
kVulkan_GrBackend,
reinterpret_cast<GrBackendContext>(backend_context_.get())));
context_->setResourceCacheLimits(vulkan::kGrCacheMaxCount,
vulkan::kGrCacheMaxByteSize);
surface_pool_ = std::make_unique<VulkanSurfacePool>(
*vk_, context_, backend_context_, mozart_session);
return true;
}
void VulkanSurfaceProducer::OnSurfacesPresented(
std::vector<
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>
surfaces) {
// Do a single flush for all canvases derived from the context.
context_->flush();
// Do a CPU wait.
// TODO(chinmaygarde): Remove this once we have support for Vulkan semaphores.
VkResult wait_result =
VK_CALL_LOG_ERROR(vk_->QueueWaitIdle(backend_context_->fQueue));
FTL_DCHECK(wait_result == VK_SUCCESS);
// Submit surface, this signals acquire events sent along the session.
for (auto& surface : surfaces) {
SubmitSurface(std::move(surface));
}
// Buffer management.
surface_pool_->AgeAndCollectOldBuffers();
}
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
VulkanSurfaceProducer::ProduceSurface(const SkISize& size) {
FTL_DCHECK(valid_);
return surface_pool_->AcquireSurface(size);
}
void VulkanSurfaceProducer::SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface> surface) {
FTL_DCHECK(valid_ && surface != nullptr);
surface_pool_->SubmitSurface(std::move(surface));
}
} // namespace flutter_runner
// Copyright 2017 The Chromium 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_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_
#define FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_
#include "apps/mozart/lib/scene/client/resources.h"
#include "apps/mozart/lib/scene/client/session.h"
#include "flutter/content_handler/vulkan_surface.h"
#include "flutter/content_handler/vulkan_surface_pool.h"
#include "flutter/flow/scene_update_context.h"
#include "flutter/vulkan/vulkan_application.h"
#include "flutter/vulkan/vulkan_device.h"
#include "flutter/vulkan/vulkan_proc_table.h"
#include "lib/ftl/macros.h"
#include "lib/mtl/tasks/message_loop.h"
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
namespace flutter_runner {
class VulkanSurfaceProducer : public flow::SceneUpdateContext::SurfaceProducer {
public:
VulkanSurfaceProducer(mozart::client::Session* mozart_session);
~VulkanSurfaceProducer();
bool IsValid() const { return valid_; }
// |flow::SceneUpdateContext::SurfaceProducer|
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
ProduceSurface(const SkISize& size) override;
// |flow::SceneUpdateContext::SurfaceProducer|
void SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface> surface)
override;
void OnSurfacesPresented(
std::vector<
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>
surfaces);
private:
// Note: the order here is very important. The proctable must be destroyed
// last because it contains the function pointers for VkDestroyDevice and
// VkDestroyInstance. The backend context owns the VkDevice and the
// VkInstance, so it must be destroyed after the logical device and the
// application, which own other vulkan objects associated with the device
// and instance.
ftl::RefPtr<vulkan::VulkanProcTable> vk_;
sk_sp<GrVkBackendContext> backend_context_;
std::unique_ptr<vulkan::VulkanDevice> logical_device_;
std::unique_ptr<vulkan::VulkanApplication> application_;
sk_sp<GrContext> context_;
std::unique_ptr<VulkanSurfacePool> surface_pool_;
bool valid_ = false;
bool Initialize(mozart::client::Session* mozart_session);
FTL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfaceProducer);
};
} // namespace flutter_runner
#endif // FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_
......@@ -47,8 +47,6 @@ source_set("flow") {
"raster_cache.h",
"raster_cache_key.cc",
"raster_cache_key.h",
"scene_update_context.cc",
"scene_update_context.h",
]
deps = [
......@@ -62,12 +60,21 @@ source_set("flow") {
if (is_fuchsia) {
sources += [
"export_node.cc",
"export_node.h",
"layers/child_scene_layer.cc",
"layers/child_scene_layer.h",
"scene_update_context.cc",
"scene_update_context.h",
]
deps += [
"//apps/mozart/lib/scene:client",
"//apps/mozart/services/scene",
]
public_deps = [
"//apps/mozart/lib/skia",
"//apps/mozart/services/composition",
"//magenta/system/ulib/mx",
]
}
}
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/flow/export_node.h"
namespace flow {
ExportNode::ExportNode(uint32_t export_token_handle)
: export_token_(export_token_handle) {}
ExportNode::~ExportNode() {
// TODO(MZ-190): Ensure the node is properly unregistered on the rasterizer
// thread by attaching it to the update context in some way.
}
void ExportNode::Bind(SceneUpdateContext& context,
mozart::client::ContainerNode& container,
const SkPoint& offset,
float scale,
bool hit_testable) {
ftl::MutexLocker lock(&mutex_);
if (export_token_) {
node_.reset(new mozart::client::EntityNode(container.session()));
node_->Export(std::move(export_token_));
}
if (node_) {
container.AddChild(*node_);
node_->SetTranslation(offset.x(), offset.y(), 0.f);
node_->SetScale(scale, scale, 1.f);
node_->SetHitTestBehavior(hit_testable
? mozart2::HitTestBehavior::kDefault
: mozart2::HitTestBehavior::kSuppress);
}
}
} // namespace flow
// Copyright 2017 The Chromium 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_FLOW_EXPORT_NODE_H_
#define FLUTTER_FLOW_EXPORT_NODE_H_
#include <memory>
#include <mx/eventpair.h>
#include "apps/mozart/lib/scene/client/resources.h"
#include "flutter/flow/scene_update_context.h"
#include "lib/ftl/build_config.h"
#include "lib/ftl/macros.h"
#include "lib/ftl/memory/ref_counted.h"
#include "lib/ftl/synchronization/mutex.h"
#include "lib/ftl/synchronization/thread_annotations.h"
#include "third_party/skia/include/core/SkPoint.h"
namespace flow {
// Represents a node which is being exported from the session.
// This object is created on the UI thread but the entity node it contains
// must be created and destroyed by the rasterizer thread.
//
// Therefore this object is thread-safe.
class ExportNode : public ftl::RefCountedThreadSafe<ExportNode> {
public:
ExportNode(uint32_t export_token_handle);
// Binds the export token to the entity node and adds it as a child of
// the specified container.
void Bind(SceneUpdateContext& context,
mozart::client::ContainerNode& container,
const SkPoint& offset,
float scale,
bool hit_testable);
private:
~ExportNode();
ftl::Mutex mutex_;
mx::eventpair export_token_ FTL_GUARDED_BY(mutex_);
std::unique_ptr<mozart::client::EntityNode> node_ FTL_GUARDED_BY(mutex_);
FRIEND_MAKE_REF_COUNTED(ExportNode);
FRIEND_REF_COUNTED_THREAD_SAFE(ExportNode);
FTL_DISALLOW_COPY_AND_ASSIGN(ExportNode);
};
} // namespace flow
#endif // FLUTTER_FLOW_EXPORT_NODE_H_
......@@ -8,15 +8,16 @@
namespace flow {
BackdropFilterLayer::BackdropFilterLayer() {}
BackdropFilterLayer::BackdropFilterLayer() = default;
BackdropFilterLayer::~BackdropFilterLayer() {}
BackdropFilterLayer::~BackdropFilterLayer() = default;
void BackdropFilterLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "BackdropFilterLayer::Paint");
Layer::AutoSaveLayer(
context,
SkCanvas::SaveLayerRec{&paint_bounds(), nullptr, filter_.get(), 0});
FTL_DCHECK(needs_painting());
Layer::AutoSaveLayer(context, SkCanvas::SaveLayerRec{&paint_bounds(), nullptr,
filter_.get(), 0});
PaintChildren(context);
}
......
......@@ -16,7 +16,6 @@ class BackdropFilterLayer : public ContainerLayer {
void set_filter(sk_sp<SkImageFilter> filter) { filter_ = std::move(filter); }
protected:
void Paint(PaintContext& context) override;
private:
......
......@@ -4,9 +4,6 @@
#include "flutter/flow/layers/child_scene_layer.h"
#include "apps/mozart/lib/skia/type_converters.h"
#include "apps/mozart/services/composition/nodes.fidl.h"
namespace flow {
ChildSceneLayer::ChildSceneLayer() = default;
......@@ -15,49 +12,30 @@ ChildSceneLayer::~ChildSceneLayer() = default;
void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
set_needs_system_composite(true);
transform_.setIdentity();
transform_.preTranslate(offset_.x(), offset_.y());
float inverse_device_pixel_ratio = 1.f / device_pixel_ratio_;
transform_.preScale(inverse_device_pixel_ratio, inverse_device_pixel_ratio);
SkRect bounds =
SkRect::MakeXYWH(offset_.x(), offset_.y(),
physical_size_.width() * inverse_device_pixel_ratio,
physical_size_.height() * inverse_device_pixel_ratio);
set_paint_bounds(bounds);
context->child_paint_bounds = bounds;
}
void ChildSceneLayer::Paint(PaintContext& context) {
FTL_DCHECK(false) << "Failed to composite child scene.";
FTL_NOTREACHED() << "This layer never needs painting.";
}
void ChildSceneLayer::UpdateScene(SceneUpdateContext& context,
mozart::Node* container) {
void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) {
FTL_DCHECK(needs_system_composite());
auto resource = mozart::Resource::New();
resource->set_scene(mozart::SceneResource::New());
resource->get_scene()->scene_token = mozart::SceneToken::New();
resource->get_scene()->scene_token->value = scene_token_;
auto node = mozart::Node::New();
if (!hit_testable_) {
node->hit_test_behavior = mozart::HitTestBehavior::New();
node->hit_test_behavior->visibility =
mozart::HitTestBehavior::Visibility::INVISIBLE;
node->hit_test_behavior->prune = true;
// TODO(MZ-191): Set clip.
// It's worth asking whether all children should be clipped implicitly
// or whether we should leave this up to the Flutter application to decide.
// In some situations, it might be useful to allow children to draw
// outside of their layout bounds.
//
// float inverse_device_pixel_ratio = 1.f / device_pixel_ratio_;
// SkRect bounds =
// SkRect::MakeXYWH(offset_.x(), offset_.y(),
// physical_size_.width() * inverse_device_pixel_ratio,
// physical_size_.height() * inverse_device_pixel_ratio);
if (export_node_) {
context.AddChildScene(export_node_.get(), offset_, device_pixel_ratio_,
hit_testable_);
}
node->op = mozart::NodeOp::New();
node->op->set_scene(mozart::SceneNodeOp::New());
node->op->get_scene()->scene_resource_id =
context.AddResource(std::move(resource));
node->content_clip = mozart::RectF::New();
node->content_clip->width = physical_size_.width();
node->content_clip->height = physical_size_.height();
node->content_transform = mozart::Transform::From(transform_);
context.AddChildNode(container, std::move(node));
}
} // namespace flow
......@@ -5,8 +5,8 @@
#ifndef FLUTTER_FLOW_LAYERS_CHILD_SCENE_LAYER_H_
#define FLUTTER_FLOW_LAYERS_CHILD_SCENE_LAYER_H_
#include "flutter/flow/export_node.h"
#include "flutter/flow/layers/layer.h"
#include "apps/mozart/services/composition/scenes.fidl.h"
namespace flow {
......@@ -25,22 +25,24 @@ class ChildSceneLayer : public Layer {
physical_size_ = physical_size;
}
void set_scene_token(uint32_t scene_token) { scene_token_ = scene_token; }
void set_export_node(ftl::RefPtr<ExportNode> export_node) {
export_node_ = std::move(export_node);
}
void set_hit_testable(bool hit_testable) { hit_testable_ = hit_testable; }
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) override;
void UpdateScene(SceneUpdateContext& context,
mozart::Node* container) override;
void UpdateScene(SceneUpdateContext& context) override;
private:
SkPoint offset_;
float device_pixel_ratio_ = 1.0;
SkISize physical_size_;
uint32_t scene_token_ = 0;
ftl::RefPtr<ExportNode> export_node_;
bool hit_testable_ = true;
SkMatrix transform_;
FTL_DISALLOW_COPY_AND_ASSIGN(ChildSceneLayer);
};
......
......@@ -5,37 +5,48 @@
#include "flutter/flow/layers/clip_path_layer.h"
#if defined(OS_FUCHSIA)
#include "apps/mozart/lib/skia/type_converters.h" // nogncheck
#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck
#include "apps/mozart/lib/scene/session_helpers.h" // nogncheck
#endif // defined(OS_FUCHSIA)
namespace flow {
ClipPathLayer::ClipPathLayer() {}
ClipPathLayer::ClipPathLayer() = default;
ClipPathLayer::~ClipPathLayer() {}
ClipPathLayer::~ClipPathLayer() = default;
void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
PrerollChildren(context, matrix);
if (!context->child_paint_bounds.intersect(clip_path_.getBounds()))
context->child_paint_bounds.setEmpty();
set_paint_bounds(context->child_paint_bounds);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (child_paint_bounds.intersect(clip_path_.getBounds())) {
set_paint_bounds(child_paint_bounds);
}
}
#if defined(OS_FUCHSIA)
void ClipPathLayer::UpdateScene(SceneUpdateContext& context,
mozart::Node* container) {
auto node = mozart::Node::New();
node->content_clip = mozart::RectF::From(clip_path_.getBounds());
UpdateSceneChildrenInsideNode(context, container, std::move(node));
void ClipPathLayer::UpdateScene(SceneUpdateContext& context) {
FTL_DCHECK(needs_system_composite());
// TODO(MZ-140): Must be able to specify paths as shapes to nodes.
// Treating the shape as a rectangle for now.
auto bounds = clip_path_.getBounds();
mozart::client::Rectangle shape(context.session(), // session
bounds.width(), // width
bounds.height() // height
);
SceneUpdateContext::Clip clip(context, shape, bounds);
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void ClipPathLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "ClipPathLayer::Paint");
FTL_DCHECK(!needs_system_composite());
FTL_DCHECK(needs_painting());
Layer::AutoSaveLayer save(context, paint_bounds(), nullptr);
context.canvas.clipPath(clip_path_, true);
......
......@@ -16,13 +16,11 @@ class ClipPathLayer : public ContainerLayer {
void set_clip_path(const SkPath& clip_path) { clip_path_ = clip_path; }
protected:
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context,
mozart::Node* container) override;
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
......
......@@ -4,38 +4,40 @@
#include "flutter/flow/layers/clip_rect_layer.h"
#if defined(OS_FUCHSIA)
#include "apps/mozart/lib/skia/type_converters.h" // nogncheck
#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck
#endif // defined(OS_FUCHSIA)
namespace flow {
ClipRectLayer::ClipRectLayer() {}
ClipRectLayer::ClipRectLayer() = default;
ClipRectLayer::~ClipRectLayer() {}
ClipRectLayer::~ClipRectLayer() = default;
void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
PrerollChildren(context, matrix);
if (!context->child_paint_bounds.intersect(clip_rect_))
context->child_paint_bounds.setEmpty();
set_paint_bounds(context->child_paint_bounds);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (child_paint_bounds.intersect(clip_rect_)) {
set_paint_bounds(child_paint_bounds);
}
}
#if defined(OS_FUCHSIA)
void ClipRectLayer::UpdateScene(SceneUpdateContext& context,
mozart::Node* container) {
auto node = mozart::Node::New();
node->content_clip = mozart::RectF::From(clip_rect_);
UpdateSceneChildrenInsideNode(context, container, std::move(node));
void ClipRectLayer::UpdateScene(SceneUpdateContext& context) {
FTL_DCHECK(needs_system_composite());
mozart::client::Rectangle shape(context.session(), // session
clip_rect_.width(), // width
clip_rect_.height() // height
);
SceneUpdateContext::Clip clip(context, shape, clip_rect_);
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void ClipRectLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "ClipRectLayer::Paint");
FTL_DCHECK(!needs_system_composite());
FTL_DCHECK(needs_painting());
SkAutoCanvasRestore save(&context.canvas, true);
context.canvas.clipRect(paint_bounds());
......
......@@ -16,13 +16,11 @@ class ClipRectLayer : public ContainerLayer {
void set_clip_rect(const SkRect& clip_rect) { clip_rect_ = clip_rect; }
protected:
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context,
mozart::Node* container) override;
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
......
......@@ -4,38 +4,47 @@
#include "flutter/flow/layers/clip_rrect_layer.h"
#if defined(OS_FUCHSIA)
#include "apps/mozart/lib/skia/type_converters.h" // nogncheck
#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck
#endif // defined(OS_FUCHSIA)
namespace flow {
ClipRRectLayer::ClipRRectLayer() {}
ClipRRectLayer::ClipRRectLayer() = default;
ClipRRectLayer::~ClipRRectLayer() {}
ClipRRectLayer::~ClipRRectLayer() = default;
void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
PrerollChildren(context, matrix);
if (!context->child_paint_bounds.intersect(clip_rrect_.getBounds()))
context->child_paint_bounds.setEmpty();
set_paint_bounds(context->child_paint_bounds);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (child_paint_bounds.intersect(clip_rrect_.getBounds())) {
set_paint_bounds(child_paint_bounds);
}
}
#if defined(OS_FUCHSIA)
void ClipRRectLayer::UpdateScene(SceneUpdateContext& context,
mozart::Node* container) {
auto node = mozart::Node::New();
node->content_clip = mozart::RectF::From(clip_rrect_.getBounds());
UpdateSceneChildrenInsideNode(context, container, std::move(node));
void ClipRRectLayer::UpdateScene(SceneUpdateContext& context) {
FTL_DCHECK(needs_system_composite());
// TODO(MZ-137): Need to be able to express the radii as vectors.
mozart::client::RoundedRectangle shape(
context.session(), // session
clip_rrect_.width(), // width
clip_rrect_.height(), // height
clip_rrect_.radii(SkRRect::kUpperLeft_Corner).x(), // top_left_radius
clip_rrect_.radii(SkRRect::kUpperRight_Corner).x(), // top_right_radius
clip_rrect_.radii(SkRRect::kLowerRight_Corner)
.x(), // bottom_right_radius
clip_rrect_.radii(SkRRect::kLowerLeft_Corner).x() // bottom_left_radius
);
SceneUpdateContext::Clip clip(context, shape, clip_rrect_.getBounds());
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void ClipRRectLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "ClipRRectLayer::Paint");
FTL_DCHECK(!needs_system_composite());
FTL_DCHECK(needs_painting());
Layer::AutoSaveLayer save(context, paint_bounds(), nullptr);
context.canvas.clipRRect(clip_rrect_, true);
......
......@@ -16,13 +16,11 @@ class ClipRRectLayer : public ContainerLayer {
void set_clip_rrect(const SkRRect& clip_rrect) { clip_rrect_ = clip_rrect; }
protected:
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context,
mozart::Node* container) override;
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
......
......@@ -6,12 +6,14 @@
namespace flow {
ColorFilterLayer::ColorFilterLayer() {}
ColorFilterLayer::ColorFilterLayer() = default;
ColorFilterLayer::~ColorFilterLayer() {}
ColorFilterLayer::~ColorFilterLayer() = default;
void ColorFilterLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "ColorFilterLayer::Paint");
FTL_DCHECK(needs_painting());
sk_sp<SkColorFilter> color_filter =
SkColorFilter::MakeModeFilter(color_, blend_mode_);
SkPaint paint;
......
......@@ -18,7 +18,6 @@ class ColorFilterLayer : public ContainerLayer {
void set_blend_mode(SkBlendMode blend_mode) { blend_mode_ = blend_mode; }
protected:
void Paint(PaintContext& context) override;
private:
......
......@@ -6,11 +6,9 @@
namespace flow {
ContainerLayer::ContainerLayer() {
ctm_.setIdentity();
}
ContainerLayer::ContainerLayer() {}
ContainerLayer::~ContainerLayer() {}
ContainerLayer::~ContainerLayer() = default;
void ContainerLayer::Add(std::unique_ptr<Layer> layer) {
layer->set_parent(this);
......@@ -19,60 +17,52 @@ void ContainerLayer::Add(std::unique_ptr<Layer> layer) {
void ContainerLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ContainerLayer::Preroll");
PrerollChildren(context, matrix);
set_paint_bounds(context->child_paint_bounds);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
set_paint_bounds(child_paint_bounds);
}
void ContainerLayer::PrerollChildren(PrerollContext* context,
const SkMatrix& matrix) {
SkRect child_paint_bounds = SkRect::MakeEmpty();
const SkMatrix& child_matrix,
SkRect* child_paint_bounds) {
for (auto& layer : layers_) {
PrerollContext child_context = *context;
FTL_DCHECK(child_context.child_paint_bounds.isEmpty());
layer->Preroll(&child_context, matrix);
if (layer->needs_system_composite())
layer->Preroll(&child_context, child_matrix);
if (layer->needs_system_composite()) {
set_needs_system_composite(true);
child_paint_bounds.join(child_context.child_paint_bounds);
}
child_paint_bounds->join(layer->paint_bounds());
}
context->child_paint_bounds = child_paint_bounds;
if (needs_system_composite())
ctm_ = matrix;
}
void ContainerLayer::PaintChildren(PaintContext& context) const {
FTL_DCHECK(!needs_system_composite());
FTL_DCHECK(needs_painting());
// Intentionally not tracing here as there should be no self-time
// and the trace event on this common function has a small overhead.
for (auto& layer : layers_)
layer->Paint(context);
for (auto& layer : layers_) {
if (layer->needs_painting()) {
layer->Paint(context);
}
}
}
#if defined(OS_FUCHSIA)
void ContainerLayer::UpdateScene(SceneUpdateContext& context,
mozart::Node* container) {
UpdateSceneChildren(context, container);
void ContainerLayer::UpdateScene(SceneUpdateContext& context) {
UpdateSceneChildren(context);
}
void ContainerLayer::UpdateSceneChildrenInsideNode(SceneUpdateContext& context,
mozart::Node* container,
mozart::NodePtr node) {
void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context) {
FTL_DCHECK(needs_system_composite());
UpdateSceneChildren(context, node.get());
context.FinalizeCurrentPaintTaskIfNeeded(node.get(), ctm());
context.AddChildNode(container, std::move(node));
}
void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context,
mozart::Node* container) {
FTL_DCHECK(needs_system_composite());
// Paint all of the layers which need to be drawn into the container.
// These may be flattened down to a containing
for (auto& layer : layers_) {
if (layer->needs_system_composite()) {
context.FinalizeCurrentPaintTaskIfNeeded(container, ctm());
layer->UpdateScene(context, container);
} else {
context.AddLayerToCurrentPaintTask(layer.get());
layer->UpdateScene(context);
}
}
}
......
......@@ -18,31 +18,26 @@ class ContainerLayer : public Layer {
void Add(std::unique_ptr<Layer> layer);
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void PrerollChildren(PrerollContext* context, const SkMatrix& matrix);
void PaintChildren(PaintContext& context) const;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context,
mozart::Node* container) override;
void UpdateSceneChildrenInsideNode(SceneUpdateContext& context,
mozart::Node* container,
mozart::NodePtr node);
void UpdateSceneChildren(SceneUpdateContext& context,
mozart::Node* container);
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
const std::vector<std::unique_ptr<Layer>>& layers() const { return layers_; }
protected:
// Valid only after preroll when needs_system_composite() is true.
const SkMatrix& ctm() const { return ctm_; }
void PrerollChildren(PrerollContext* context,
const SkMatrix& child_matrix,
SkRect* child_paint_bounds);
void PaintChildren(PaintContext& context) const;
#if defined(OS_FUCHSIA)
void UpdateSceneChildren(SceneUpdateContext& context);
#endif // defined(OS_FUCHSIA)
private:
std::vector<std::unique_ptr<Layer>> layers_;
SkMatrix ctm_;
FTL_DISALLOW_COPY_AND_ASSIGN(ContainerLayer);
};
......
......@@ -12,33 +12,26 @@ namespace flow {
Layer::Layer()
: parent_(nullptr),
needs_system_composite_(false),
has_paint_bounds_(false),
paint_bounds_() {}
paint_bounds_(SkRect::MakeEmpty()) {}
Layer::~Layer() = default;
void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
if (!has_paint_bounds()) {
set_paint_bounds(SkRect::MakeEmpty());
}
}
void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {}
#if defined(OS_FUCHSIA)
void Layer::UpdateScene(SceneUpdateContext& context, mozart::Node* container) {}
#endif
void Layer::UpdateScene(SceneUpdateContext& context) {}
#endif // defined(OS_FUCHSIA)
Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context,
const SkRect& bounds,
const SkPaint* paint)
: paint_context_(paint_context),
bounds_(bounds) {
: paint_context_(paint_context), bounds_(bounds) {
paint_context_.canvas.saveLayer(bounds_, paint);
}
Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context,
const SkCanvas::SaveLayerRec& layer_rec)
: paint_context_(paint_context),
bounds_(*layer_rec.fBounds) {
: paint_context_(paint_context), bounds_(*layer_rec.fBounds) {
paint_context_.canvas.saveLayer(layer_rec);
}
......
......@@ -10,7 +10,6 @@
#include "flutter/flow/instrumentation.h"
#include "flutter/flow/raster_cache.h"
#include "flutter/flow/scene_update_context.h"
#include "flutter/glue/trace_event.h"
#include "lib/ftl/build_config.h"
#include "lib/ftl/logging.h"
......@@ -24,7 +23,16 @@
#include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkRect.h"
#if defined(OS_FUCHSIA)
#include "apps/mozart/lib/scene/client/resources.h" //nogncheck
#include "apps/mozart/lib/scene/client/session.h" //nogncheck
#include "flutter/flow/scene_update_context.h" //nogncheck
#endif // defined(OS_FUCHSIA)
namespace flow {
class ContainerLayer;
class Layer {
......@@ -70,8 +78,8 @@ class Layer {
virtual void Paint(PaintContext& context) = 0;
#if defined(OS_FUCHSIA)
virtual void UpdateScene(SceneUpdateContext& context,
mozart::Node* container);
// Updates the system composited scene.
virtual void UpdateScene(SceneUpdateContext& context);
#endif
ContainerLayer* parent() const { return parent_; }
......@@ -83,23 +91,19 @@ class Layer {
needs_system_composite_ = value;
}
// subclasses should assume this will be true by the time Paint() is called
bool has_paint_bounds() const { return has_paint_bounds_; }
const SkRect& paint_bounds() const {
FTL_DCHECK(has_paint_bounds_);
return paint_bounds_;
}
const SkRect& paint_bounds() const { return paint_bounds_; }
// This must be set by the time Preroll() returns otherwise the layer will
// be assumed to have empty paint bounds (paints no content).
void set_paint_bounds(const SkRect& paint_bounds) {
has_paint_bounds_ = true;
paint_bounds_ = paint_bounds;
}
bool needs_painting() const { return !paint_bounds_.isEmpty(); }
private:
ContainerLayer* parent_;
bool needs_system_composite_;
bool has_paint_bounds_; // if false, paint_bounds_ is not valid
SkRect paint_bounds_;
FTL_DISALLOW_COPY_AND_ASSIGN(Layer);
......
......@@ -11,12 +11,11 @@ namespace flow {
LayerTree::LayerTree()
: frame_size_{},
scene_version_(0),
rasterizer_tracing_threshold_(0),
checkerboard_raster_cache_images_(false),
checkerboard_offscreen_layers_(false) {}
LayerTree::~LayerTree() {}
LayerTree::~LayerTree() = default;
void LayerTree::Raster(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache) {
......@@ -40,15 +39,21 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
#if defined(OS_FUCHSIA)
void LayerTree::UpdateScene(SceneUpdateContext& context,
mozart::Node* container) {
mozart::client::ContainerNode& container) {
TRACE_EVENT0("flutter", "LayerTree::UpdateScene");
SceneUpdateContext::Frame frame(
context,
SkRRect::MakeRect(
SkRect::MakeIWH(frame_size_.width(), frame_size_.height())),
SK_ColorTRANSPARENT, 0.f, 1.f, 1.f);
if (root_layer_->needs_system_composite()) {
root_layer_->UpdateScene(context, container);
} else {
context.AddLayerToCurrentPaintTask(root_layer_.get());
root_layer_->UpdateScene(context);
}
context.FinalizeCurrentPaintTaskIfNeeded(container, SkMatrix::I());
if (root_layer_->needs_painting()) {
frame.AddPaintedLayer(root_layer_.get());
}
container.AddChild(frame.entity_node());
}
#endif
......@@ -58,7 +63,9 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame) {
frame.context().memory_usage(),
checkerboard_offscreen_layers_};
TRACE_EVENT0("flutter", "LayerTree::Paint");
root_layer_->Paint(context);
if (root_layer_->needs_painting())
root_layer_->Paint(context);
}
} // namespace flow
......@@ -31,10 +31,8 @@ class LayerTree {
bool ignore_raster_cache = false);
#if defined(OS_FUCHSIA)
// TODO(abarth): Integrate scene updates with the rasterization pass so that
// we can draw on top of child scenes (and so that we can apply clips and
// blending operations to child scene).
void UpdateScene(SceneUpdateContext& context, mozart::Node* container);
void UpdateScene(SceneUpdateContext& context,
mozart::client::ContainerNode& container);
#endif
void Paint(CompositorContext::ScopedFrame& frame);
......@@ -49,12 +47,6 @@ class LayerTree {
void set_frame_size(const SkISize& frame_size) { frame_size_ = frame_size; }
uint32_t scene_version() const { return scene_version_; }
void set_scene_version(uint32_t scene_version) {
scene_version_ = scene_version;
}
void set_construction_time(const ftl::TimeDelta& delta) {
construction_time_ = delta;
}
......@@ -82,7 +74,6 @@ class LayerTree {
private:
SkISize frame_size_; // Physical pixels.
uint32_t scene_version_;
std::unique_ptr<Layer> root_layer_;
ftl::TimeDelta construction_time_;
uint32_t rasterizer_tracing_threshold_;
......
......@@ -4,35 +4,15 @@
#include "flutter/flow/layers/opacity_layer.h"
#if defined(OS_FUCHSIA)
#include "apps/mozart/lib/skia/type_converters.h" // nogncheck
#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck
#endif // defined(OS_FUCHSIA)
namespace flow {
OpacityLayer::OpacityLayer() {}
OpacityLayer::~OpacityLayer() {}
#if defined(OS_FUCHSIA)
void OpacityLayer::UpdateScene(SceneUpdateContext& context,
mozart::Node* container) {
auto node = mozart::Node::New();
node->op = mozart::NodeOp::New();
node->op->set_layer(mozart::LayerNodeOp::New());
node->op->get_layer()->layer_rect = mozart::RectF::From(paint_bounds());
node->op->get_layer()->blend = mozart::Blend::New();
node->op->get_layer()->blend->alpha = alpha_;
UpdateSceneChildrenInsideNode(context, container, std::move(node));
}
OpacityLayer::OpacityLayer() = default;
#endif // defined(OS_FUCHSIA)
OpacityLayer::~OpacityLayer() = default;
void OpacityLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "OpacityLayer::Paint");
FTL_DCHECK(!needs_system_composite());
FTL_DCHECK(needs_painting());
SkPaint paint;
paint.setAlpha(alpha_);
......
......@@ -16,13 +16,10 @@ class OpacityLayer : public ContainerLayer {
void set_alpha(int alpha) { alpha_ = alpha; }
protected:
void Paint(PaintContext& context) override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context,
mozart::Node* container) override;
#endif // defined(OS_FUCHSIA)
// TODO(chinmaygarde): Once MZ-139 is addressed, introduce a new node in the
// session scene hierarchy.
private:
int alpha_;
......
......@@ -7,45 +7,63 @@
#include "flutter/flow/paint_utils.h"
#include "third_party/skia/include/utils/SkShadowUtils.h"
#if defined(OS_FUCHSIA)
#include "apps/mozart/lib/skia/type_converters.h" // nogncheck
#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck
#endif // defined(OS_FUCHSIA)
namespace flow {
PhysicalModelLayer::PhysicalModelLayer()
: rrect_(SkRRect::MakeEmpty()) {}
PhysicalModelLayer::PhysicalModelLayer() : rrect_(SkRRect::MakeEmpty()) {}
PhysicalModelLayer::~PhysicalModelLayer() {}
PhysicalModelLayer::~PhysicalModelLayer() = default;
void PhysicalModelLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
PrerollChildren(context, matrix);
void PhysicalModelLayer::Preroll(PrerollContext* context,
const SkMatrix& matrix) {
SkRect child_paint_bounds;
PrerollChildren(context, matrix, &child_paint_bounds);
// Add some margin to the paint bounds to leave space for the shadow.
// The margin is hardcoded to an arbitrary maximum for now because Skia
// doesn't provide a way to calculate it.
SkRect bounds(rrect_.getBounds());
bounds.outset(20.0, 20.0);
set_paint_bounds(bounds);
if (elevation_ == 0) {
set_paint_bounds(rrect_.getBounds());
} else {
#if defined(OS_FUCHSIA)
// Let the system compositor draw all shadows for us.
set_needs_system_composite(true);
#else
// Add some margin to the paint bounds to leave space for the shadow.
// The margin is hardcoded to an arbitrary maximum for now because Skia
// doesn't provide a way to calculate it. We fill this whole region
// and clip children to it so we don't need to join the child paint bounds.
SkRect bounds(rrect_.getBounds());
bounds.outset(20.0, 20.0);
set_paint_bounds(bounds);
#endif // defined(OS_FUCHSIA)
}
context->child_paint_bounds = bounds;
#if defined(OS_FUCHSIA)
if (needs_system_composite()) {
scale_x_ = matrix.getScaleX();
scale_y_ = matrix.getScaleY();
}
#endif // defined(OS_FUCHSIA)
}
#if defined(OS_FUCHSIA)
void PhysicalModelLayer::UpdateScene(SceneUpdateContext& context,
mozart::Node* container) {
context.AddLayerToCurrentPaintTask(this);
auto node = mozart::Node::New();
node->content_clip = mozart::RectF::From(rrect_.getBounds());
UpdateSceneChildrenInsideNode(context, container, std::move(node));
void PhysicalModelLayer::UpdateScene(SceneUpdateContext& context) {
FTL_DCHECK(needs_system_composite());
SceneUpdateContext::Frame frame(context, rrect_, color_, elevation_, scale_x_,
scale_y_);
for (auto& layer : layers()) {
if (layer->needs_painting()) {
frame.AddPaintedLayer(layer.get());
}
}
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void PhysicalModelLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "PhysicalModelLayer::Paint");
FTL_DCHECK(needs_painting());
SkPath path;
path.addRRect(rrect_);
......@@ -55,9 +73,6 @@ void PhysicalModelLayer::Paint(PaintContext& context) {
SkColorGetA(color_) != 0xff);
}
if (needs_system_composite())
return;
SkPaint paint;
paint.setColor(color_);
context.canvas.drawPath(path, paint);
......@@ -74,22 +89,20 @@ void PhysicalModelLayer::Paint(PaintContext& context) {
DrawCheckerboard(&context.canvas, rrect_.getBounds());
}
void PhysicalModelLayer::DrawShadow(SkCanvas* canvas, const SkPath& path,
SkColor color, double elevation,
void PhysicalModelLayer::DrawShadow(SkCanvas* canvas,
const SkPath& path,
SkColor color,
float elevation,
bool transparentOccluder) {
SkShadowFlags flags = transparentOccluder ?
SkShadowFlags::kTransparentOccluder_ShadowFlag :
SkShadowFlags::kNone_ShadowFlag;
const SkRect& bounds = path.getBounds();
SkScalar shadow_x = (bounds.left() + bounds.right()) / 2;
SkScalar shadow_y = bounds.top() - 600.0f;
SkShadowUtils::DrawShadow(canvas, path,
elevation,
SkPoint3::Make(shadow_x, shadow_y, 600.0f),
800.0f,
0.039f, 0.25f,
color,
flags);
SkShadowFlags flags = transparentOccluder
? SkShadowFlags::kTransparentOccluder_ShadowFlag
: SkShadowFlags::kNone_ShadowFlag;
const SkRect& bounds = path.getBounds();
SkScalar shadow_x = (bounds.left() + bounds.right()) / 2;
SkScalar shadow_y = bounds.top() - 600.0f;
SkShadowUtils::DrawShadow(canvas, path, elevation,
SkPoint3::Make(shadow_x, shadow_y, 600.0f), 800.0f,
0.039f, 0.25f, color, flags);
}
} // namespace flow
......@@ -15,25 +15,31 @@ class PhysicalModelLayer : public ContainerLayer {
~PhysicalModelLayer() override;
void set_rrect(const SkRRect& rrect) { rrect_ = rrect; }
void set_elevation(double elevation) { elevation_ = elevation; }
void set_elevation(float elevation) { elevation_ = elevation; }
void set_color(SkColor color) { color_ = color; }
static void DrawShadow(SkCanvas* canvas, const SkPath& path,
SkColor color, double elevation, bool transparentOccluder);
static void DrawShadow(SkCanvas* canvas,
const SkPath& path,
SkColor color,
float elevation,
bool transparentOccluder);
protected:
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context,
mozart::Node* container) override;
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
SkRRect rrect_;
double elevation_;
float elevation_;
SkColor color_;
#if defined(OS_FUCHSIA)
SkScalar scale_x_;
SkScalar scale_y_;
#endif // defined(OS_FUCHSIA)
};
} // namespace flow
......
......@@ -9,7 +9,7 @@
namespace flow {
PictureLayer::PictureLayer() {}
PictureLayer::PictureLayer() = default;
PictureLayer::~PictureLayer() {
// The picture may contain references to textures that are associated
......@@ -29,13 +29,12 @@ void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect bounds = picture_->cullRect().makeOffset(offset_.x(), offset_.y());
set_paint_bounds(bounds);
context->child_paint_bounds = bounds;
}
void PictureLayer::Paint(PaintContext& context) {
FTL_DCHECK(picture_);
TRACE_EVENT0("flutter", "PictureLayer::Paint");
FTL_DCHECK(picture_);
FTL_DCHECK(needs_painting());
SkAutoCanvasRestore save(&context.canvas, true);
context.canvas.translate(offset_.x(), offset_.y());
......
......@@ -6,12 +6,14 @@
namespace flow {
ShaderMaskLayer::ShaderMaskLayer() {}
ShaderMaskLayer::ShaderMaskLayer() = default;
ShaderMaskLayer::~ShaderMaskLayer() {}
ShaderMaskLayer::~ShaderMaskLayer() = default;
void ShaderMaskLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "ShaderMaskLayer::Paint");
FTL_DCHECK(needs_painting());
Layer::AutoSaveLayer(context, paint_bounds(), nullptr);
PaintChildren(context);
......
......@@ -20,11 +20,8 @@ class ShaderMaskLayer : public ContainerLayer {
void set_mask_rect(const SkRect& mask_rect) { mask_rect_ = mask_rect; }
void set_blend_mode(SkBlendMode blend_mode) {
blend_mode_ = blend_mode;
}
void set_blend_mode(SkBlendMode blend_mode) { blend_mode_ = blend_mode; }
protected:
void Paint(PaintContext& context) override;
private:
......
......@@ -4,39 +4,37 @@
#include "flutter/flow/layers/transform_layer.h"
#if defined(OS_FUCHSIA)
#include "apps/mozart/lib/skia/type_converters.h" // nogncheck
#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck
#endif // defined(OS_FUCHSIA)
namespace flow {
TransformLayer::TransformLayer() {}
TransformLayer::TransformLayer() = default;
TransformLayer::~TransformLayer() {}
TransformLayer::~TransformLayer() = default;
void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkMatrix childMatrix;
childMatrix.setConcat(matrix, transform_);
PrerollChildren(context, childMatrix);
transform_.mapRect(&context->child_paint_bounds);
set_paint_bounds(context->child_paint_bounds);
SkMatrix child_matrix;
child_matrix.setConcat(matrix, transform_);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, child_matrix, &child_paint_bounds);
transform_.mapRect(&child_paint_bounds);
set_paint_bounds(child_paint_bounds);
}
#if defined(OS_FUCHSIA)
void TransformLayer::UpdateScene(SceneUpdateContext& context,
mozart::Node* container) {
auto node = mozart::Node::New();
node->content_transform = mozart::Transform::From(transform_);
UpdateSceneChildrenInsideNode(context, container, std::move(node));
void TransformLayer::UpdateScene(SceneUpdateContext& context) {
FTL_DCHECK(needs_system_composite());
SceneUpdateContext::Transform transform(context, transform_);
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void TransformLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "TransformLayer::Paint");
FTL_DCHECK(!needs_system_composite());
FTL_DCHECK(needs_painting());
SkAutoCanvasRestore save(&context.canvas, true);
context.canvas.concat(transform_);
......
......@@ -16,13 +16,11 @@ class TransformLayer : public ContainerLayer {
void set_transform(const SkMatrix& transform) { transform_ = transform; }
protected:
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context,
mozart::Node* container) override;
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
......
......@@ -4,124 +4,272 @@
#include "flutter/flow/scene_update_context.h"
#if defined(OS_FUCHSIA)
#include "apps/mozart/lib/skia/skia_vmo_surface.h" // nogncheck
#include "apps/mozart/lib/skia/type_converters.h" // nogncheck
#include "apps/mozart/services/composition/scenes.fidl.h" // nogncheck
#include "flutter/flow/export_node.h"
#include "flutter/flow/layers/layer.h"
#include "flutter/flow/matrix_decomposition.h"
#include "flutter/glue/trace_event.h"
namespace flow {
SceneUpdateContext::CurrentPaintTask::CurrentPaintTask()
: bounds(SkRect::MakeEmpty()) {}
void SceneUpdateContext::CurrentPaintTask::Clear() {
bounds = SkRect::MakeEmpty();
layers.clear();
}
SceneUpdateContext::SceneUpdateContext(mozart::SceneUpdate* update,
SceneUpdateContext::SceneUpdateContext(mozart::client::Session* session,
SurfaceProducer* surface_producer)
: update_(update), surface_producer_(surface_producer) {}
: session_(session), surface_producer_(surface_producer) {
FTL_DCHECK(surface_producer_ != nullptr);
}
SceneUpdateContext::~SceneUpdateContext() = default;
void SceneUpdateContext::AddLayerToCurrentPaintTask(Layer* layer) {
current_paint_task_.bounds.join(layer->paint_bounds());
current_paint_task_.layers.push_back(layer);
}
void SceneUpdateContext::AddChildScene(ExportNode* export_node,
SkPoint offset,
float device_pixel_ratio,
bool hit_testable) {
FTL_DCHECK(top_entity_);
void SceneUpdateContext::FinalizeCurrentPaintTaskIfNeeded(
mozart::Node* container,
const SkMatrix& ctm) {
if (mozart::NodePtr node = FinalizeCurrentPaintTask(ctm))
AddChildNode(container, std::move(node));
export_node->Bind(*this, top_entity_->entity_node(), offset,
1.f / device_pixel_ratio, hit_testable);
}
mozart::NodePtr SceneUpdateContext::FinalizeCurrentPaintTask(
const SkMatrix& ctm) {
if (current_paint_task_.layers.empty())
return nullptr;
void SceneUpdateContext::CreateFrame(mozart::client::EntityNode& entity_node,
const SkRRect& rrect,
SkColor color,
SkScalar scale_x,
SkScalar scale_y,
const SkRect& paint_bounds,
std::vector<Layer*> paint_layers) {
// Frames always clip their children.
entity_node.SetClip(0u, true /* clip to self */);
const SkRect& bounds = current_paint_task_.bounds;
// We don't need a shape if the frame is zero size.
if (rrect.isEmpty())
return;
SkScalar scaleX = ctm.getScaleX();
SkScalar scaleY = ctm.getScaleY();
// Add a part which represents the frame's geometry for clipping purposes
// and possibly for its texture.
// TODO(MZ-137): Need to be able to express the radii as vectors.
SkRect shape_bounds = rrect.getBounds();
mozart::client::RoundedRectangle shape(
session_, // session
rrect.width(), // width
rrect.height(), // height
rrect.radii(SkRRect::kUpperLeft_Corner).x(), // top_left_radius
rrect.radii(SkRRect::kUpperRight_Corner).x(), // top_right_radius
rrect.radii(SkRRect::kLowerRight_Corner).x(), // bottom_right_radius
rrect.radii(SkRRect::kLowerLeft_Corner).x() // bottom_left_radius
);
mozart::client::ShapeNode shape_node(session_);
shape_node.SetShape(shape);
shape_node.SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(),
shape_bounds.height() * 0.5f + shape_bounds.top(),
0.f);
entity_node.AddPart(shape_node);
SkISize physical_size =
SkISize::Make(bounds.width() * scaleX, bounds.height() * scaleY);
// Check whether the painted layers will be visible.
if (paint_bounds.isEmpty() || !paint_bounds.intersects(shape_bounds))
paint_layers.clear();
if (physical_size.isEmpty()) {
current_paint_task_.Clear();
return nullptr;
// Check whether a solid color will suffice.
if (paint_layers.empty()) {
SetShapeColor(shape_node, color);
return;
}
// If the painted area only covers a portion of the frame then we can
// reduce the texture size by drawing just that smaller area.
SkRect inner_bounds = shape_bounds;
inner_bounds.intersect(paint_bounds);
if (inner_bounds != shape_bounds && rrect.contains(inner_bounds)) {
SetShapeColor(shape_node, color);
mozart::client::Rectangle inner_shape(session_, inner_bounds.width(),
inner_bounds.height());
mozart::client::ShapeNode inner_node(session_);
inner_node.SetShape(inner_shape);
inner_node.SetTranslation(inner_bounds.width() * 0.5f + inner_bounds.left(),
inner_bounds.height() * 0.5f + inner_bounds.top(),
0.f);
entity_node.AddPart(inner_node);
SetShapeTextureOrColor(inner_node, color, scale_x, scale_y, inner_bounds,
std::move(paint_layers));
return;
}
mozart::ImagePtr image;
PaintTask task;
task.surface = surface_producer_->ProduceSurface(physical_size, &image);
task.left = bounds.left();
task.top = bounds.top();
task.scaleX = scaleX;
task.scaleY = scaleY;
task.layers = std::move(current_paint_task_.layers);
FTL_DCHECK(task.surface) << "Failed to create surface size="
<< physical_size.width() << "x"
<< physical_size.height();
paint_tasks_.push_back(task);
auto resource = mozart::Resource::New();
resource->set_image(mozart::ImageResource::New());
resource->get_image()->image = std::move(image);
auto node = mozart::Node::New();
node->op = mozart::NodeOp::New();
node->op->set_image(mozart::ImageNodeOp::New());
node->op->get_image()->content_rect = mozart::RectF::From(bounds);
node->op->get_image()->image_resource_id = AddResource(std::move(resource));
current_paint_task_.Clear();
return node;
// Apply a texture to the whole shape.
SetShapeTextureOrColor(shape_node, color, scale_x, scale_y, shape_bounds,
std::move(paint_layers));
}
uint32_t SceneUpdateContext::AddResource(mozart::ResourcePtr resource) {
uint32_t resource_id = next_resource_id_++;
update_->resources.insert(resource_id, std::move(resource));
return resource_id;
void SceneUpdateContext::SetShapeTextureOrColor(
mozart::client::ShapeNode& shape_node,
SkColor color,
SkScalar scale_x,
SkScalar scale_y,
const SkRect& paint_bounds,
std::vector<Layer*> paint_layers) {
mozart::client::Image* image = GenerateImageIfNeeded(
color, scale_x, scale_y, paint_bounds, std::move(paint_layers));
if (image != nullptr) {
mozart::client::Material material(session_);
material.SetTexture(*image);
shape_node.SetMaterial(material);
return;
}
SetShapeColor(shape_node, color);
}
void SceneUpdateContext::AddChildNode(mozart::Node* container,
mozart::NodePtr child) {
uint32_t node_id = next_node_id_++;
update_->nodes.insert(node_id, std::move(child));
container->child_node_ids.push_back(node_id);
void SceneUpdateContext::SetShapeColor(mozart::client::ShapeNode& shape_node,
SkColor color) {
if (SkColorGetA(color) == 0)
return;
mozart::client::Material material(session_);
material.SetColor(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color),
SkColorGetA(color));
shape_node.SetMaterial(material);
}
void SceneUpdateContext::ExecutePaintTasks(
CompositorContext::ScopedFrame& frame) {
TRACE_EVENT0("flutter", "SceneUpdateContext::ExecutePaintTasks");
mozart::client::Image* SceneUpdateContext::GenerateImageIfNeeded(
SkColor color,
SkScalar scale_x,
SkScalar scale_y,
const SkRect& paint_bounds,
std::vector<Layer*> paint_layers) {
// Bail if there's nothing to paint.
if (paint_layers.empty())
return nullptr;
// Bail if the physical bounds are empty after rounding.
SkISize physical_size = SkISize::Make(paint_bounds.width() * scale_x,
paint_bounds.height() * scale_y);
if (physical_size.isEmpty())
return nullptr;
// Acquire a surface from the surface producer and register the paint tasks.
auto surface = surface_producer_->ProduceSurface(physical_size);
if (!surface) {
FTL_LOG(ERROR) << "Could not acquire a surface from the surface producer "
"of size: "
<< physical_size.width() << "x" << physical_size.height();
return nullptr;
}
auto image = surface->GetImage();
// Enqueue the paint task.
paint_tasks_.push_back({.surface = std::move(surface),
.left = paint_bounds.left(),
.top = paint_bounds.top(),
.scale_x = scale_x,
.scale_y = scale_y,
.background_color = color,
.layers = std::move(paint_layers)});
return image;
}
std::vector<std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>
SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) {
TRACE_EVENT0("flutter", "SceneUpdateContext::ExecutePaintTasks");
std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces_to_submit;
for (auto& task : paint_tasks_) {
FTL_DCHECK(task.surface);
SkCanvas* canvas = task.surface->getCanvas();
SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas();
Layer::PaintContext context = {*canvas, frame.context().frame_time(),
frame.context().engine_time(),
frame.context().memory_usage(),
false};
canvas->clear(SK_ColorTRANSPARENT);
canvas->scale(task.scaleX, task.scaleY);
frame.context().memory_usage(), false};
canvas->restoreToCount(1);
canvas->save();
canvas->clear(task.background_color);
canvas->scale(task.scale_x, task.scale_y);
canvas->translate(-task.left, -task.top);
for (Layer* layer : task.layers)
for (Layer* layer : task.layers) {
layer->Paint(context);
}
surfaces_to_submit.emplace_back(std::move(task.surface));
}
paint_tasks_.clear();
return surfaces_to_submit;
}
} // namespace flow
SceneUpdateContext::Entity::Entity(SceneUpdateContext& context)
: context_(context),
previous_entity_(context.top_entity_),
entity_node_(context.session()) {
if (previous_entity_)
previous_entity_->entity_node_.AddChild(entity_node_);
context.top_entity_ = this;
}
SceneUpdateContext::Entity::~Entity() {
FTL_DCHECK(context_.top_entity_ == this);
context_.top_entity_ = previous_entity_;
}
SceneUpdateContext::Clip::Clip(SceneUpdateContext& context,
mozart::client::Shape& shape,
const SkRect& shape_bounds)
: Entity(context) {
mozart::client::ShapeNode shape_node(context.session());
shape_node.SetShape(shape);
shape_node.SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(),
shape_bounds.height() * 0.5f + shape_bounds.top(),
0.f);
entity_node().AddPart(shape_node);
entity_node().SetClip(0u, true /* clip to self */);
}
SceneUpdateContext::Clip::~Clip() = default;
#endif // defined(OS_FUCHSIA)
SceneUpdateContext::Transform::Transform(SceneUpdateContext& context,
const SkMatrix& transform)
: Entity(context) {
// TODO(MZ-192): The perspective and shear components in the matrix
// are not handled correctly.
MatrixDecomposition decomposition(transform);
if (decomposition.IsValid()) {
entity_node().SetTranslation(decomposition.translation().x(), //
decomposition.translation().y(), //
decomposition.translation().z() //
);
entity_node().SetScale(decomposition.scale().x(), //
decomposition.scale().y(), //
decomposition.scale().z() //
);
entity_node().SetRotation(decomposition.rotation().fData[0], //
decomposition.rotation().fData[1], //
decomposition.rotation().fData[2], //
decomposition.rotation().fData[3] //
);
}
}
SceneUpdateContext::Transform::~Transform() = default;
SceneUpdateContext::Frame::Frame(SceneUpdateContext& context,
const SkRRect& rrect,
SkColor color,
float elevation,
SkScalar scale_x,
SkScalar scale_y)
: Entity(context),
rrect_(rrect),
color_(color),
scale_x_(scale_x),
scale_y_(scale_y),
paint_bounds_(SkRect::MakeEmpty()) {
entity_node().SetTranslation(0.f, 0.f, elevation);
}
SceneUpdateContext::Frame::~Frame() {
context().CreateFrame(entity_node(), rrect_, color_, scale_x_, scale_y_,
paint_bounds_, std::move(paint_layers_));
}
void SceneUpdateContext::Frame::AddPaintedLayer(Layer* layer) {
FTL_DCHECK(layer->needs_painting());
paint_layers_.push_back(layer);
paint_bounds_.join(layer->paint_bounds());
}
} // namespace flow
......@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FLOW_MOZART_SCENE_UPDATE_CONTEXT_H_
#define FLUTTER_FLOW_MOZART_SCENE_UPDATE_CONTEXT_H_
#ifndef FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_
#define FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_
#include <memory>
#include <vector>
#include "apps/mozart/lib/scene/client/resources.h"
#include "flutter/flow/compositor_context.h"
#include "lib/ftl/build_config.h"
#include "lib/ftl/logging.h"
......@@ -15,82 +16,157 @@
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkSurface.h"
#if defined(OS_FUCHSIA)
#include "apps/mozart/services/composition/nodes.fidl.h" // nogncheck
#include "apps/mozart/services/composition/resources.fidl.h" // nogncheck
#include "apps/mozart/services/images/image.fidl.h" // nogncheck
#endif // defined(OS_FUCHSIA)
namespace mozart {
class BufferProducer;
class Node;
class SceneUpdate;
} // namespace mozart
namespace flow {
class Layer;
class SceneUpdateContext;
#if defined(OS_FUCHSIA)
class Layer;
class ExportNode;
class SceneUpdateContext {
public:
class SurfaceProducerSurface {
public:
virtual ~SurfaceProducerSurface() = default;
virtual size_t AdvanceAndGetAge() = 0;
virtual bool FlushSessionAcquireAndReleaseEvents() = 0;
virtual bool IsValid() const = 0;
virtual SkISize GetSize() const = 0;
virtual void SignalWritesFinished(
std::function<void(void)> on_writes_committed) = 0;
virtual mozart::client::Image* GetImage() = 0;
virtual sk_sp<SkSurface> GetSkiaSurface() const = 0;
};
class SurfaceProducer {
public:
virtual ~SurfaceProducer() {}
virtual sk_sp<SkSurface> ProduceSurface(SkISize size,
mozart::ImagePtr* out_image) = 0;
virtual std::unique_ptr<SurfaceProducerSurface> ProduceSurface(
const SkISize& size) = 0;
virtual void SubmitSurface(
std::unique_ptr<SurfaceProducerSurface> surface) = 0;
};
SceneUpdateContext(mozart::SceneUpdate* update,
SceneUpdateContext(mozart::client::Session* session,
SurfaceProducer* surface_producer);
~SceneUpdateContext();
mozart::SceneUpdate* update() const { return update_; }
mozart::client::Session* session() { return session_; }
void AddLayerToCurrentPaintTask(Layer* layer);
void FinalizeCurrentPaintTaskIfNeeded(mozart::Node* container,
const SkMatrix& ctm);
class Entity {
public:
Entity(SceneUpdateContext& context);
~Entity();
uint32_t AddResource(mozart::ResourcePtr resource);
void AddChildNode(mozart::Node* container, mozart::NodePtr child);
SceneUpdateContext& context() { return context_; }
mozart::client::EntityNode& entity_node() { return entity_node_; }
void ExecutePaintTasks(CompositorContext::ScopedFrame& frame);
private:
SceneUpdateContext& context_;
Entity* const previous_entity_;
private:
mozart::NodePtr FinalizeCurrentPaintTask(const SkMatrix& ctm);
mozart::client::EntityNode entity_node_;
};
struct CurrentPaintTask {
CurrentPaintTask();
void Clear();
class Clip : public Entity {
public:
Clip(SceneUpdateContext& context,
mozart::client::Shape& shape,
const SkRect& shape_bounds);
~Clip();
};
SkRect bounds;
std::vector<Layer*> layers;
class Transform : public Entity {
public:
Transform(SceneUpdateContext& context, const SkMatrix& transform);
~Transform();
};
class Frame : public Entity {
public:
Frame(SceneUpdateContext& context,
const SkRRect& rrect,
SkColor color,
float elevation,
SkScalar scale_x,
SkScalar scale_y);
~Frame();
void AddPaintedLayer(Layer* layer);
private:
const SkRRect& rrect_;
SkColor const color_;
SkScalar const scale_x_;
SkScalar const scale_y_;
std::vector<Layer*> paint_layers_;
SkRect paint_bounds_;
};
void AddChildScene(ExportNode* export_node,
SkPoint offset,
float device_pixel_ratio,
bool hit_testable);
// TODO(chinmaygarde): This method must submit the surfaces as soon as paint
// tasks are done. However, given that there is no support currently for
// Vulkan semaphores, we need to submit all the surfaces after an explicit
// CPU wait. Once Vulkan semaphores are available, this method must return
// void and the implementation must submit surfaces on its own as soon as the
// specific canvas operations are done.
FTL_WARN_UNUSED_RESULT
std::vector<std::unique_ptr<SurfaceProducerSurface>> ExecutePaintTasks(
CompositorContext::ScopedFrame& frame);
private:
struct PaintTask {
sk_sp<SkSurface> surface;
std::unique_ptr<SurfaceProducerSurface> surface;
SkScalar left;
SkScalar top;
SkScalar scaleX;
SkScalar scaleY;
SkScalar scale_x;
SkScalar scale_y;
SkColor background_color;
std::vector<Layer*> layers;
};
mozart::SceneUpdate* update_;
SurfaceProducer* surface_producer_;
void CreateFrame(mozart::client::EntityNode& entity_node,
const SkRRect& rrect,
SkColor color,
SkScalar scale_x,
SkScalar scale_y,
const SkRect& paint_bounds,
std::vector<Layer*> paint_layers);
void SetShapeTextureOrColor(mozart::client::ShapeNode& shape_node,
SkColor color,
SkScalar scale_x,
SkScalar scale_y,
const SkRect& paint_bounds,
std::vector<Layer*> paint_layers);
void SetShapeColor(mozart::client::ShapeNode& shape_node, SkColor color);
mozart::client::Image* GenerateImageIfNeeded(
SkColor color,
SkScalar scale_x,
SkScalar scale_y,
const SkRect& paint_bounds,
std::vector<Layer*> paint_layers);
Entity* top_entity_ = nullptr;
mozart::client::Session* const session_;
SurfaceProducer* const surface_producer_;
CurrentPaintTask current_paint_task_;
std::vector<PaintTask> paint_tasks_;
uint32_t next_resource_id_ = 1;
uint32_t next_node_id_ = 1;
FTL_DISALLOW_COPY_AND_ASSIGN(SceneUpdateContext);
};
#endif // defined(OS_FUCHSIA)
} // namespace flow
#endif // FLUTTER_FLOW_MOZART_SCENE_UPDATE_CONTEXT_H_
#endif // FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_
......@@ -8,6 +8,8 @@ source_set("ui") {
"compositing/scene.h",
"compositing/scene_builder.cc",
"compositing/scene_builder.h",
"compositing/scene_host.cc",
"compositing/scene_host.h",
"dart_runtime_hooks.cc",
"dart_runtime_hooks.h",
"dart_ui.cc",
......
......@@ -199,16 +199,12 @@ class SceneBuilder extends NativeFieldWrapperClass2 {
/// (Fuchsia-only) Adds a scene rendered by another application to the scene
/// for this application.
///
/// Applications typically obtain scene tokens when embedding other views via
/// the Fuchsia view manager, but this function is agnostic as to the source
/// of scene token.
void addChildScene({
Offset offset: Offset.zero,
double devicePixelRatio: 1.0,
int physicalWidth: 0,
int physicalHeight: 0,
int sceneToken,
SceneHost sceneHost,
bool hitTestable: true
}) {
_addChildScene(offset.dx,
......@@ -216,7 +212,7 @@ class SceneBuilder extends NativeFieldWrapperClass2 {
devicePixelRatio,
physicalWidth,
physicalHeight,
sceneToken,
sceneHost,
hitTestable);
}
void _addChildScene(double dx,
......@@ -224,7 +220,7 @@ class SceneBuilder extends NativeFieldWrapperClass2 {
double devicePixelRatio,
int physicalWidth,
int physicalHeight,
int sceneToken,
SceneHost sceneHost,
bool hitTestable) native "SceneBuilder_addChildScene";
/// Sets a threshold after which additional debugging information should be recorded.
......@@ -268,3 +264,24 @@ class SceneBuilder extends NativeFieldWrapperClass2 {
/// cannot be used further.
Scene build() native "SceneBuilder_build";
}
/// (Fuchsia-only) Hosts content provided by another application.
class SceneHost extends NativeFieldWrapperClass2 {
/// Creates a host for a child scene.
///
/// The export token is bound to a scene graph node which acts as a container
/// for the child's content. The creator of the scene host is responsible for
/// sending the corresponding import token (the other endpoint of the event pair)
/// to the child.
///
/// The scene host takes ownership of the provided export token handle.
SceneHost(int export_token_handle) {
_constructor(export_token_handle);
}
void _constructor(int export_token_handle) native "SceneHost_constructor";
/// Releases the resources associated with the child scene host.
///
/// After calling this function, the child scene host cannot be used further.
void dispose() native "SceneHost_dispose";
}
......@@ -52,7 +52,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, SceneBuilder);
V(SceneBuilder, addChildScene) \
V(SceneBuilder, addPerformanceOverlay) \
V(SceneBuilder, setRasterizerTracingThreshold) \
V(SceneBuilder, setCheckerboardOffscreenLayers) \
V(SceneBuilder, setCheckerboardOffscreenLayers) \
V(SceneBuilder, setCheckerboardRasterCacheImages) \
V(SceneBuilder, build)
......@@ -163,7 +163,8 @@ void SceneBuilder::pushPhysicalModel(const RRect& rrect,
if (!cullRect.intersect(rrect.sk_rrect.rect(), m_cullRects.top()))
cullRect = SkRect::MakeEmpty();
std::unique_ptr<flow::PhysicalModelLayer> layer(new flow::PhysicalModelLayer());
std::unique_ptr<flow::PhysicalModelLayer> layer(
new flow::PhysicalModelLayer());
layer->set_rrect(rrect.sk_rrect);
layer->set_elevation(elevation);
layer->set_color(color);
......@@ -221,7 +222,7 @@ void SceneBuilder::addChildScene(double dx,
double devicePixelRatio,
int physicalWidth,
int physicalHeight,
uint32_t sceneToken,
SceneHost* sceneHost,
bool hitTestable) {
#if defined(OS_FUCHSIA)
if (!m_currentLayer)
......@@ -236,7 +237,7 @@ void SceneBuilder::addChildScene(double dx,
layer->set_offset(SkPoint::Make(dx, dy));
layer->set_device_pixel_ratio(devicePixelRatio);
layer->set_physical_size(SkISize::Make(physicalWidth, physicalHeight));
layer->set_scene_token(sceneToken);
layer->set_export_node(sceneHost->exportNode());
layer->set_hit_testable(hitTestable);
m_currentLayer->Add(std::move(layer));
#endif
......
......@@ -11,6 +11,7 @@
#include "flutter/flow/layers/container_layer.h"
#include "flutter/lib/ui/compositing/scene.h"
#include "flutter/lib/ui/compositing/scene_host.h"
#include "flutter/lib/ui/painting/image_filter.h"
#include "flutter/lib/ui/painting/path.h"
#include "flutter/lib/ui/painting/picture.h"
......@@ -61,7 +62,7 @@ class SceneBuilder : public ftl::RefCountedThreadSafe<SceneBuilder>,
double devicePixelRatio,
int physicalWidth,
int physicalHeight,
uint32_t sceneToken,
SceneHost* sceneHost,
bool hitTestable);
void setRasterizerTracingThreshold(uint32_t frameInterval);
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/lib/ui/compositing/scene_host.h"
#include "lib/tonic/dart_args.h"
#include "lib/tonic/dart_binding_macros.h"
#include "lib/tonic/dart_library_natives.h"
namespace blink {
static void SceneHost_constructor(Dart_NativeArguments args) {
DartCallConstructor(&SceneHost::create, args);
}
IMPLEMENT_WRAPPERTYPEINFO(ui, SceneHost);
#define FOR_EACH_BINDING(V) V(SceneHost, dispose)
FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
void SceneHost::RegisterNatives(tonic::DartLibraryNatives* natives) {
natives->Register({{"SceneHost_constructor", SceneHost_constructor, 2, true},
FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
}
ftl::RefPtr<SceneHost> SceneHost::create(int export_token_handle) {
return ftl::MakeRefCounted<SceneHost>(export_token_handle);
}
SceneHost::SceneHost(int export_token_handle) {
#if defined(OS_FUCHSIA)
export_node_ = ftl::MakeRefCounted<flow::ExportNode>(export_token_handle);
#endif
}
SceneHost::~SceneHost() {}
void SceneHost::dispose() {
ClearDartWrapper();
}
} // namespace blink
// Copyright 2017 The Chromium 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_LIB_UI_COMPOSITING_SCENE_HOST_H_
#define FLUTTER_LIB_UI_COMPOSITING_SCENE_HOST_H_
#include <stdint.h>
#include "lib/tonic/dart_wrappable.h"
#if defined(OS_FUCHSIA)
#include "flutter/flow/export_node.h"
#endif
namespace tonic {
class DartLibraryNatives;
} // namespace tonic
namespace blink {
class SceneHost : public ftl::RefCountedThreadSafe<SceneHost>,
public tonic::DartWrappable {
DEFINE_WRAPPERTYPEINFO();
FRIEND_MAKE_REF_COUNTED(SceneHost);
public:
static ftl::RefPtr<SceneHost> create(int export_token_handle);
~SceneHost() override;
#if defined(OS_FUCHSIA)
const ftl::RefPtr<flow::ExportNode>& exportNode() const {
return export_node_;
}
#endif
void dispose();
static void RegisterNatives(tonic::DartLibraryNatives* natives);
private:
#if defined(OS_FUCHSIA)
ftl::RefPtr<flow::ExportNode> export_node_;
#endif
explicit SceneHost(int export_token_handle);
};
} // namespace blink
#endif // FLUTTER_LIB_UI_COMPOSITING_SCENE_HOST_H_
......@@ -64,6 +64,7 @@ void DartUI::InitForGlobal() {
PictureRecorder::RegisterNatives(g_natives);
Scene::RegisterNatives(g_natives);
SceneBuilder::RegisterNatives(g_natives);
SceneHost::RegisterNatives(g_natives);
SemanticsUpdate::RegisterNatives(g_natives);
SemanticsUpdateBuilder::RegisterNatives(g_natives);
Vertices::RegisterNatives(g_natives);
......
......@@ -1169,6 +1169,7 @@ FILE: ../../../flutter/content_handler/rasterizer.cc
FILE: ../../../flutter/content_handler/rasterizer.h
FILE: ../../../flutter/content_handler/runtime_holder.cc
FILE: ../../../flutter/content_handler/runtime_holder.h
FILE: ../../../flutter/flow/export_node.cc
FILE: ../../../flutter/flow/layers/backdrop_filter_layer.cc
FILE: ../../../flutter/flow/layers/backdrop_filter_layer.h
FILE: ../../../flutter/flow/layers/child_scene_layer.cc
......@@ -1353,20 +1354,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
====================================================================================================
LIBRARY: engine
ORIGIN: ../../../flutter/content_handler/content_handler_thread.cc + ../../../LICENSE
ORIGIN: ../../../flutter/content_handler/service_protocol_hooks.cc + ../../../LICENSE
TYPE: LicenseType.bsd
FILE: ../../../flutter/content_handler/content_handler_thread.cc
FILE: ../../../flutter/content_handler/content_handler_thread.h
FILE: ../../../flutter/content_handler/service_protocol_hooks.cc
FILE: ../../../flutter/content_handler/service_protocol_hooks.h
FILE: ../../../flutter/content_handler/software_rasterizer.cc
FILE: ../../../flutter/content_handler/software_rasterizer.h
FILE: ../../../flutter/content_handler/vulkan_native_rasterizer.cc
FILE: ../../../flutter/content_handler/vulkan_native_rasterizer.h
FILE: ../../../flutter/content_handler/session_connection.cc
FILE: ../../../flutter/content_handler/session_connection.h
FILE: ../../../flutter/content_handler/vulkan_rasterizer.cc
FILE: ../../../flutter/content_handler/vulkan_rasterizer.h
FILE: ../../../flutter/content_handler/vulkan_surface_producer.cc
FILE: ../../../flutter/content_handler/vulkan_surface_producer.h
FILE: ../../../flutter/flow/debug_print.cc
FILE: ../../../flutter/flow/debug_print.h
FILE: ../../../flutter/flow/export_node.h
FILE: ../../../flutter/flow/layers/physical_model_layer.cc
FILE: ../../../flutter/flow/layers/physical_model_layer.h
FILE: ../../../flutter/flow/matrix_decomposition.cc
......@@ -1424,6 +1424,8 @@ FILE: ../../../flutter/fml/thread_local_unittests.cc
FILE: ../../../flutter/fml/thread_unittests.cc
FILE: ../../../flutter/fml/trace_event.cc
FILE: ../../../flutter/fml/trace_event.h
FILE: ../../../flutter/lib/ui/compositing/scene_host.cc
FILE: ../../../flutter/lib/ui/compositing/scene_host.h
FILE: ../../../flutter/lib/ui/painting/utils.cc
FILE: ../../../flutter/lib/ui/painting/vertices.cc
FILE: ../../../flutter/lib/ui/painting/vertices.h
......@@ -1503,6 +1505,44 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
====================================================================================================
====================================================================================================
LIBRARY: engine
ORIGIN: ../../../flutter/content_handler/vulkan_surface.cc + ../../../lib/ftl/LICENSE
TYPE: LicenseType.bsd
FILE: ../../../flutter/content_handler/vulkan_surface.cc
FILE: ../../../flutter/content_handler/vulkan_surface.h
FILE: ../../../flutter/content_handler/vulkan_surface_pool.cc
FILE: ../../../flutter/content_handler/vulkan_surface_pool.h
----------------------------------------------------------------------------------------------------
Copyright 2017 The Fuchsia Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
====================================================================================================
====================================================================================================
LIBRARY: engine
ORIGIN: ../../../flutter/flow/layers/clip_path_layer.cc + ../../../LICENSE
......@@ -9379,4 +9419,4 @@ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
====================================================================================================
Total license count: 208
Total license count: 209
......@@ -63,5 +63,8 @@ source_set("vulkan") {
"//third_party/skia:gpu",
]
public_configs = [ ":vulkan_config", "//third_party/skia:skia_private" ]
public_configs = [
":vulkan_config",
"//third_party/skia:skia_private",
]
}
......@@ -74,16 +74,16 @@ bool VulkanProcTable::SetupInstanceProcAddresses(
ACQUIRE_PROC(CreateDevice, handle);
ACQUIRE_PROC(DestroyDevice, handle);
ACQUIRE_PROC(DestroyInstance, handle);
ACQUIRE_PROC(DestroySurfaceKHR, handle);
ACQUIRE_PROC(EnumerateDeviceLayerProperties, handle);
ACQUIRE_PROC(EnumeratePhysicalDevices, handle);
ACQUIRE_PROC(GetDeviceProcAddr, handle);
ACQUIRE_PROC(GetPhysicalDeviceFeatures, handle);
ACQUIRE_PROC(GetPhysicalDeviceQueueFamilyProperties, handle);
ACQUIRE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR, handle);
ACQUIRE_PROC(GetPhysicalDeviceSurfaceFormatsKHR, handle);
ACQUIRE_PROC(GetPhysicalDeviceSurfacePresentModesKHR, handle);
ACQUIRE_PROC(GetPhysicalDeviceSurfaceSupportKHR, handle);
ACQUIRE_PROC(GetDeviceProcAddr, handle);
ACQUIRE_PROC(DestroySurfaceKHR, handle);
#if OS_ANDROID
ACQUIRE_PROC(CreateAndroidSurfaceKHR, handle);
......@@ -92,10 +92,10 @@ bool VulkanProcTable::SetupInstanceProcAddresses(
#if OS_FUCHSIA
[this, &handle]() -> bool {
ACQUIRE_PROC(CreateMagmaSurfaceKHR, handle);
ACQUIRE_PROC(ExportDeviceMemoryMAGMA, handle);
ACQUIRE_PROC(GetPhysicalDeviceMagmaPresentationSupportKHR, handle);
return true;
}();
#endif // OS_FUCHSIA
// The debug report functions are optional. We don't want proc acquisition to
......@@ -116,28 +116,37 @@ bool VulkanProcTable::SetupInstanceProcAddresses(
bool VulkanProcTable::SetupDeviceProcAddresses(
const VulkanHandle<VkDevice>& handle) {
ACQUIRE_PROC(AcquireNextImageKHR, handle);
ACQUIRE_PROC(CreateSwapchainKHR, handle);
ACQUIRE_PROC(DestroySwapchainKHR, handle);
ACQUIRE_PROC(GetSwapchainImagesKHR, handle);
ACQUIRE_PROC(QueuePresentKHR, handle);
ACQUIRE_PROC(AllocateCommandBuffers, handle);
ACQUIRE_PROC(AllocateMemory, handle);
ACQUIRE_PROC(BeginCommandBuffer, handle);
ACQUIRE_PROC(BindImageMemory, handle);
ACQUIRE_PROC(CmdPipelineBarrier, handle);
ACQUIRE_PROC(CreateCommandPool, handle);
ACQUIRE_PROC(CreateFence, handle);
ACQUIRE_PROC(CreateImage, handle);
ACQUIRE_PROC(CreateSemaphore, handle);
ACQUIRE_PROC(CreateSwapchainKHR, handle);
ACQUIRE_PROC(DestroyCommandPool, handle);
ACQUIRE_PROC(DestroyFence, handle);
ACQUIRE_PROC(DestroyImage, handle);
ACQUIRE_PROC(DestroySemaphore, handle);
ACQUIRE_PROC(DestroySwapchainKHR, handle);
ACQUIRE_PROC(DeviceWaitIdle, handle);
ACQUIRE_PROC(EndCommandBuffer, handle);
ACQUIRE_PROC(FreeCommandBuffers, handle);
ACQUIRE_PROC(FreeMemory, handle);
ACQUIRE_PROC(GetDeviceQueue, handle);
ACQUIRE_PROC(GetImageMemoryRequirements, handle);
ACQUIRE_PROC(GetSwapchainImagesKHR, handle);
ACQUIRE_PROC(QueuePresentKHR, handle);
ACQUIRE_PROC(QueueSubmit, handle);
ACQUIRE_PROC(QueueWaitIdle, handle);
ACQUIRE_PROC(ResetCommandBuffer, handle);
ACQUIRE_PROC(ResetFences, handle);
ACQUIRE_PROC(WaitForFences, handle);
#if OS_FUCHSIA
ACQUIRE_PROC(ExportDeviceMemoryMAGMA, handle);
#endif // OS_FUCHSIA
device_ = {handle, nullptr};
return true;
}
......
......@@ -65,12 +65,15 @@ class VulkanProcTable : public ftl::RefCountedThreadSafe<VulkanProcTable> {
DEFINE_PROC(AcquireNextImageKHR);
DEFINE_PROC(AllocateCommandBuffers);
DEFINE_PROC(AllocateMemory);
DEFINE_PROC(BeginCommandBuffer);
DEFINE_PROC(BindImageMemory);
DEFINE_PROC(CmdPipelineBarrier);
DEFINE_PROC(CreateCommandPool);
DEFINE_PROC(CreateDebugReportCallbackEXT);
DEFINE_PROC(CreateDevice);
DEFINE_PROC(CreateFence);
DEFINE_PROC(CreateImage);
DEFINE_PROC(CreateInstance);
DEFINE_PROC(CreateSemaphore);
DEFINE_PROC(CreateSwapchainKHR);
......@@ -78,6 +81,7 @@ class VulkanProcTable : public ftl::RefCountedThreadSafe<VulkanProcTable> {
DEFINE_PROC(DestroyDebugReportCallbackEXT);
DEFINE_PROC(DestroyDevice);
DEFINE_PROC(DestroyFence);
DEFINE_PROC(DestroyImage);
DEFINE_PROC(DestroyInstance);
DEFINE_PROC(DestroySemaphore);
DEFINE_PROC(DestroySurfaceKHR);
......@@ -89,26 +93,30 @@ class VulkanProcTable : public ftl::RefCountedThreadSafe<VulkanProcTable> {
DEFINE_PROC(EnumerateInstanceLayerProperties);
DEFINE_PROC(EnumeratePhysicalDevices);
DEFINE_PROC(FreeCommandBuffers);
DEFINE_PROC(FreeMemory);
DEFINE_PROC(GetDeviceProcAddr);
DEFINE_PROC(GetDeviceQueue);
DEFINE_PROC(GetImageMemoryRequirements);
DEFINE_PROC(GetInstanceProcAddr);
DEFINE_PROC(GetPhysicalDeviceFeatures);
DEFINE_PROC(GetPhysicalDeviceQueueFamilyProperties);
DEFINE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
DEFINE_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
DEFINE_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
DEFINE_PROC(GetPhysicalDeviceSurfaceSupportKHR);
DEFINE_PROC(GetSwapchainImagesKHR);
DEFINE_PROC(QueuePresentKHR);
DEFINE_PROC(QueueSubmit);
DEFINE_PROC(QueueWaitIdle);
DEFINE_PROC(ResetCommandBuffer);
DEFINE_PROC(ResetFences);
DEFINE_PROC(WaitForFences);
DEFINE_PROC(GetPhysicalDeviceSurfaceSupportKHR);
#if OS_ANDROID
DEFINE_PROC(CreateAndroidSurfaceKHR);
#endif // OS_ANDROID
#if OS_FUCHSIA
DEFINE_PROC(CreateMagmaSurfaceKHR);
DEFINE_PROC(ExportDeviceMemoryMAGMA);
DEFINE_PROC(GetPhysicalDeviceMagmaPresentationSupportKHR);
#endif // OS_FUCHSIA
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册