mirror of
https://github.com/encounter/engine.git
synced 2026-03-30 11:09:55 -07:00
Port Flutter to Mozart. (#3094)
Example: $ mojo:launcher mojo:spinning_square
This commit is contained in:
@@ -12,16 +12,18 @@ executable("content_handler") {
|
||||
"application_impl.h",
|
||||
"content_handler_impl.cc",
|
||||
"content_handler_impl.h",
|
||||
"framebuffer_skia.cc",
|
||||
"framebuffer_skia.h",
|
||||
"main.cc",
|
||||
"rasterizer.cc",
|
||||
"rasterizer.h",
|
||||
"runtime_holder.cc",
|
||||
"runtime_holder.h",
|
||||
"skia_surface_holder.cc",
|
||||
"skia_surface_holder.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//apps/mozart/services/composition/interfaces",
|
||||
"//apps/mozart/services/views/interfaces",
|
||||
"//dart/runtime:libdart",
|
||||
"//dart/runtime/vm:libdart_platform",
|
||||
"//flutter/assets",
|
||||
|
||||
@@ -27,9 +27,6 @@ ApplicationImpl::ApplicationImpl(
|
||||
FTL_LOG(ERROR) << "Failed to receive bundle.";
|
||||
return;
|
||||
}
|
||||
// TODO(abarth): In principle, we should call StartRuntimeIfReady() here but
|
||||
// because we're draining the data pipe synchronously, we know that we can't
|
||||
// possibly be ready yet because we haven't received the Initialize() message.
|
||||
}
|
||||
|
||||
ApplicationImpl::~ApplicationImpl() {}
|
||||
@@ -42,24 +39,36 @@ void ApplicationImpl::Initialize(mojo::InterfaceHandle<mojo::Shell> shell,
|
||||
mojo::ApplicationConnectorPtr connector;
|
||||
shell_->CreateApplicationConnector(mojo::GetProxy(&connector));
|
||||
runtime_holder_.reset(new RuntimeHolder());
|
||||
runtime_holder_->Init(std::move(connector));
|
||||
StartRuntimeIfReady();
|
||||
runtime_holder_->Init(std::move(connector), std::move(bundle_));
|
||||
}
|
||||
|
||||
void ApplicationImpl::AcceptConnection(
|
||||
const mojo::String& requestor_url,
|
||||
const mojo::String& resolved_url,
|
||||
mojo::InterfaceRequest<mojo::ServiceProvider> services) {}
|
||||
mojo::InterfaceRequest<mojo::ServiceProvider> services) {
|
||||
service_provider_bindings_.AddBinding(this, std::move(services));
|
||||
}
|
||||
|
||||
void ApplicationImpl::RequestQuit() {
|
||||
binding_.Close();
|
||||
delete this;
|
||||
}
|
||||
|
||||
void ApplicationImpl::StartRuntimeIfReady() {
|
||||
if (!runtime_holder_ || bundle_.empty())
|
||||
return;
|
||||
runtime_holder_->Run(url_, std::move(bundle_));
|
||||
void ApplicationImpl::ConnectToService(
|
||||
const mojo::String& service_name,
|
||||
mojo::ScopedMessagePipeHandle client_handle) {
|
||||
if (service_name == mozart::ViewProvider::Name_) {
|
||||
view_provider_bindings_.AddBinding(
|
||||
this,
|
||||
mojo::InterfaceRequest<mozart::ViewProvider>(std::move(client_handle)));
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationImpl::CreateView(
|
||||
mojo::InterfaceRequest<mozart::ViewOwner> view_owner_request,
|
||||
mojo::InterfaceRequest<mojo::ServiceProvider> services) {
|
||||
runtime_holder_->CreateView(url_, std::move(view_owner_request),
|
||||
std::move(services));
|
||||
}
|
||||
|
||||
} // namespace flutter_content_handler
|
||||
|
||||
@@ -7,17 +7,22 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "apps/mozart/services/views/interfaces/view_provider.mojom.h"
|
||||
#include "flutter/glue/drain_data_pipe_job.h"
|
||||
#include "lib/ftl/macros.h"
|
||||
#include "mojo/public/cpp/bindings/binding_set.h"
|
||||
#include "mojo/public/cpp/bindings/strong_binding.h"
|
||||
#include "mojo/public/interfaces/application/application.mojom.h"
|
||||
#include "mojo/public/interfaces/application/service_provider.mojom.h"
|
||||
#include "mojo/public/interfaces/application/shell.mojom.h"
|
||||
#include "mojo/services/content_handler/interfaces/content_handler.mojom.h"
|
||||
|
||||
namespace flutter_content_handler {
|
||||
class RuntimeHolder;
|
||||
|
||||
class ApplicationImpl : public mojo::Application {
|
||||
class ApplicationImpl : public mojo::Application,
|
||||
public mojo::ServiceProvider,
|
||||
public mozart::ViewProvider {
|
||||
public:
|
||||
ApplicationImpl(mojo::InterfaceRequest<mojo::Application> application,
|
||||
mojo::URLResponsePtr response);
|
||||
@@ -34,11 +39,23 @@ class ApplicationImpl : public mojo::Application {
|
||||
mojo::InterfaceRequest<mojo::ServiceProvider> services) override;
|
||||
void RequestQuit() override;
|
||||
|
||||
// mojo::ServiceProvider
|
||||
void ConnectToService(const mojo::String& service_name,
|
||||
mojo::ScopedMessagePipeHandle client_handle) override;
|
||||
|
||||
// mozart::ViewProvider
|
||||
void CreateView(
|
||||
mojo::InterfaceRequest<mozart::ViewOwner> view_owner_request,
|
||||
mojo::InterfaceRequest<mojo::ServiceProvider> services) override;
|
||||
|
||||
void StartRuntimeIfReady();
|
||||
|
||||
mojo::StrongBinding<mojo::Application> binding_;
|
||||
std::unique_ptr<glue::DrainDataPipeJob> drainer_;
|
||||
|
||||
mojo::BindingSet<mojo::ServiceProvider> service_provider_bindings_;
|
||||
mojo::BindingSet<mozart::ViewProvider> view_provider_bindings_;
|
||||
|
||||
std::vector<char> bundle_;
|
||||
mojo::ShellPtr shell_;
|
||||
std::string url_;
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
// 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/content_handler/framebuffer_skia.h"
|
||||
|
||||
#include <magenta/process.h>
|
||||
#include <magenta/syscalls.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "lib/ftl/logging.h"
|
||||
|
||||
namespace flutter_content_handler {
|
||||
namespace {
|
||||
|
||||
struct BackingStoreInfo {
|
||||
mx_handle_t vmo;
|
||||
uintptr_t buffer;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
void DidReleaseSurface(void* pixels, void* context) {
|
||||
BackingStoreInfo* info = static_cast<BackingStoreInfo*>(context);
|
||||
mx_process_unmap_vm(mx_process_self(), info->buffer, info->size);
|
||||
mx_handle_close(info->vmo);
|
||||
delete info;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
FramebufferSkia::FramebufferSkia() {}
|
||||
|
||||
FramebufferSkia::~FramebufferSkia() {}
|
||||
|
||||
void FramebufferSkia::Bind(mojo::InterfaceHandle<mojo::Framebuffer> framebuffer,
|
||||
mojo::FramebufferInfoPtr info) {
|
||||
if (!framebuffer) {
|
||||
FTL_LOG(ERROR) << "Failed to bind framebuffer";
|
||||
surface_ = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
framebuffer_.Bind(std::move(framebuffer));
|
||||
info_ = std::move(info);
|
||||
|
||||
uintptr_t buffer = 0;
|
||||
size_t row_bytes = info_->row_bytes;
|
||||
size_t size = row_bytes * info_->size->height;
|
||||
|
||||
mx_status_t status =
|
||||
mx_process_map_vm(mx_process_self(), info_->vmo.get().value(), 0, size,
|
||||
&buffer, MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE);
|
||||
|
||||
if (status < 0) {
|
||||
FTL_LOG(ERROR) << "Cannot map framebuffer (status=" << status << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
SkColorType sk_color_type;
|
||||
SkAlphaType sk_alpha_type;
|
||||
switch (info_->format) {
|
||||
case mojo::FramebufferFormat::RGB_565:
|
||||
sk_color_type = kRGB_565_SkColorType;
|
||||
sk_alpha_type = kOpaque_SkAlphaType;
|
||||
break;
|
||||
case mojo::FramebufferFormat::ARGB_8888:
|
||||
sk_color_type = kBGRA_8888_SkColorType;
|
||||
sk_alpha_type = kPremul_SkAlphaType;
|
||||
break;
|
||||
case mojo::FramebufferFormat::RGB_x888:
|
||||
sk_color_type = kBGRA_8888_SkColorType;
|
||||
sk_alpha_type = kOpaque_SkAlphaType;
|
||||
break;
|
||||
default:
|
||||
FTL_LOG(ERROR) << "Unknown color type " << info_->format;
|
||||
return;
|
||||
}
|
||||
|
||||
SkImageInfo image_info = SkImageInfo::Make(
|
||||
info_->size->width, info_->size->height, sk_color_type, sk_alpha_type);
|
||||
|
||||
BackingStoreInfo* backing_store_info = new BackingStoreInfo();
|
||||
backing_store_info->vmo = info_->vmo.release().value();
|
||||
backing_store_info->buffer = buffer;
|
||||
backing_store_info->size = size;
|
||||
|
||||
surface_ = SkSurface::MakeRasterDirectReleaseProc(
|
||||
image_info, reinterpret_cast<void*>(buffer), row_bytes, DidReleaseSurface,
|
||||
backing_store_info);
|
||||
}
|
||||
|
||||
void FramebufferSkia::Finish() {
|
||||
framebuffer_->Flush([] {});
|
||||
framebuffer_.WaitForIncomingResponse();
|
||||
}
|
||||
|
||||
} // namespace flutter_content_handler
|
||||
@@ -1,35 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef FLUTTER_CONTENT_HANDLER_FRAMEBUFFER_SKIA_H_
|
||||
#define FLUTTER_CONTENT_HANDLER_FRAMEBUFFER_SKIA_H_
|
||||
|
||||
#include "lib/ftl/macros.h"
|
||||
#include "mojo/services/framebuffer/interfaces/framebuffer.mojom.h"
|
||||
#include "third_party/skia/include/core/SkSurface.h"
|
||||
|
||||
namespace flutter_content_handler {
|
||||
|
||||
class FramebufferSkia {
|
||||
public:
|
||||
FramebufferSkia();
|
||||
~FramebufferSkia();
|
||||
|
||||
void Bind(mojo::InterfaceHandle<mojo::Framebuffer> framebuffer,
|
||||
mojo::FramebufferInfoPtr info);
|
||||
|
||||
void Finish();
|
||||
const sk_sp<SkSurface>& surface() { return surface_; }
|
||||
|
||||
private:
|
||||
mojo::FramebufferPtr framebuffer_;
|
||||
mojo::FramebufferInfoPtr info_;
|
||||
sk_sp<SkSurface> surface_;
|
||||
|
||||
FTL_DISALLOW_COPY_AND_ASSIGN(FramebufferSkia);
|
||||
};
|
||||
|
||||
} // namespace flutter_content_handler
|
||||
|
||||
#endif // FLUTTER_CONTENT_HANDLER_FRAMEBUFFER_SKIA_H_
|
||||
@@ -6,36 +6,76 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "lib/ftl/functional/make_runnable.h"
|
||||
#include "apps/mozart/services/composition/interfaces/image.mojom.h"
|
||||
#include "flutter/content_handler/skia_surface_holder.h"
|
||||
#include "lib/ftl/logging.h"
|
||||
#include "third_party/skia/include/core/SkCanvas.h"
|
||||
|
||||
namespace flutter_content_handler {
|
||||
|
||||
namespace {
|
||||
constexpr uint32_t kContentImageResourceId = 1;
|
||||
constexpr uint32_t kRootNodeId = mozart::kSceneRootNodeId;
|
||||
} // namespace
|
||||
|
||||
Rasterizer::Rasterizer() {}
|
||||
|
||||
Rasterizer::~Rasterizer() {}
|
||||
|
||||
void Rasterizer::SetFramebuffer(
|
||||
mojo::InterfaceHandle<mojo::Framebuffer> framebuffer,
|
||||
mojo::FramebufferInfoPtr info) {
|
||||
framebuffer_.Bind(std::move(framebuffer), std::move(info));
|
||||
void Rasterizer::SetScene(mojo::InterfaceHandle<mozart::Scene> scene) {
|
||||
scene_.Bind(std::move(scene));
|
||||
}
|
||||
|
||||
void Rasterizer::Draw(std::unique_ptr<flow::LayerTree> layer_tree,
|
||||
ftl::Closure callback) {
|
||||
if (!framebuffer_.surface()) {
|
||||
FTL_DCHECK(layer_tree);
|
||||
if (!scene_) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
SkCanvas* canvas = framebuffer_.surface()->getCanvas();
|
||||
flow::CompositorContext::ScopedFrame frame =
|
||||
compositor_context_.AcquireFrame(nullptr, *canvas);
|
||||
canvas->clear(SK_ColorBLACK);
|
||||
layer_tree->Raster(frame);
|
||||
canvas->flush();
|
||||
const SkISize& frame_size = layer_tree->frame_size();
|
||||
auto update = mozart::SceneUpdate::New();
|
||||
|
||||
if (!frame_size.isEmpty()) {
|
||||
// TODO(jeffbrown): Maintain a pool of images and recycle them.
|
||||
SkiaSurfaceHolder surface_holder(frame_size);
|
||||
|
||||
SkCanvas* canvas = surface_holder.surface()->getCanvas();
|
||||
flow::CompositorContext::ScopedFrame frame =
|
||||
compositor_context_.AcquireFrame(nullptr, *canvas);
|
||||
canvas->clear(SK_ColorBLACK);
|
||||
layer_tree->Raster(frame);
|
||||
canvas->flush();
|
||||
|
||||
mojo::RectF bounds;
|
||||
bounds.width = frame_size.width();
|
||||
bounds.height = frame_size.height();
|
||||
|
||||
auto content_resource = mozart::Resource::New();
|
||||
content_resource->set_image(mozart::ImageResource::New());
|
||||
content_resource->get_image()->image = surface_holder.TakeImage();
|
||||
update->resources.insert(kContentImageResourceId, content_resource.Pass());
|
||||
|
||||
auto root_node = mozart::Node::New();
|
||||
root_node->op = mozart::NodeOp::New();
|
||||
root_node->op->set_image(mozart::ImageNodeOp::New());
|
||||
root_node->op->get_image()->content_rect = bounds.Clone();
|
||||
root_node->op->get_image()->image_resource_id = kContentImageResourceId;
|
||||
update->nodes.insert(kRootNodeId, root_node.Pass());
|
||||
|
||||
layer_tree->UpdateScene(update.get(), root_node.get());
|
||||
} else {
|
||||
auto root_node = mozart::Node::New();
|
||||
update->nodes.insert(kRootNodeId, root_node.Pass());
|
||||
}
|
||||
|
||||
scene_->Update(std::move(update));
|
||||
|
||||
auto metadata = mozart::SceneMetadata::New();
|
||||
metadata->version = layer_tree->scene_version();
|
||||
scene_->Publish(std::move(metadata));
|
||||
|
||||
framebuffer_.Finish();
|
||||
callback();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,11 @@
|
||||
#ifndef FLUTTER_CONTENT_HANDLER_RASTERIZER_H_
|
||||
#define FLUTTER_CONTENT_HANDLER_RASTERIZER_H_
|
||||
|
||||
#include "flutter/content_handler/framebuffer_skia.h"
|
||||
#include "apps/mozart/services/composition/interfaces/scenes.mojom.h"
|
||||
#include "flutter/flow/compositor_context.h"
|
||||
#include "flutter/flow/layers/layer_tree.h"
|
||||
#include "lib/ftl/functional/closure.h"
|
||||
#include "lib/ftl/macros.h"
|
||||
#include "mojo/services/framebuffer/interfaces/framebuffer.mojom.h"
|
||||
#include "third_party/skia/include/core/SkSurface.h"
|
||||
|
||||
namespace flutter_content_handler {
|
||||
|
||||
@@ -20,14 +18,12 @@ class Rasterizer {
|
||||
Rasterizer();
|
||||
~Rasterizer();
|
||||
|
||||
void SetFramebuffer(mojo::InterfaceHandle<mojo::Framebuffer> framebuffer,
|
||||
mojo::FramebufferInfoPtr info);
|
||||
void SetScene(mojo::InterfaceHandle<mozart::Scene> scene);
|
||||
|
||||
void Draw(std::unique_ptr<flow::LayerTree> layer_tree, ftl::Closure callback);
|
||||
|
||||
private:
|
||||
FramebufferSkia framebuffer_;
|
||||
sk_sp<SkSurface> surface_;
|
||||
mozart::ScenePtr scene_;
|
||||
flow::CompositorContext compositor_context_;
|
||||
|
||||
FTL_DISALLOW_COPY_AND_ASSIGN(Rasterizer);
|
||||
|
||||
@@ -24,14 +24,20 @@ namespace flutter_content_handler {
|
||||
namespace {
|
||||
|
||||
constexpr char kSnapshotKey[] = "snapshot_blob.bin";
|
||||
constexpr int kPipelineDepth = 3;
|
||||
constexpr ftl::TimeDelta kTargetFrameInterval =
|
||||
ftl::TimeDelta::FromMilliseconds(16);
|
||||
|
||||
// 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;
|
||||
|
||||
} // namespace
|
||||
|
||||
RuntimeHolder::RuntimeHolder()
|
||||
: viewport_metrics_(sky::ViewportMetrics::New()), weak_factory_(this) {}
|
||||
: viewport_metrics_(sky::ViewportMetrics::New()),
|
||||
view_listener_binding_(this),
|
||||
weak_factory_(this) {}
|
||||
|
||||
RuntimeHolder::~RuntimeHolder() {
|
||||
blink::Threads::Gpu()->PostTask(
|
||||
@@ -40,22 +46,26 @@ RuntimeHolder::~RuntimeHolder() {
|
||||
}));
|
||||
}
|
||||
|
||||
void RuntimeHolder::Init(mojo::ApplicationConnectorPtr connector) {
|
||||
void RuntimeHolder::Init(mojo::ApplicationConnectorPtr connector,
|
||||
std::vector<char> bundle) {
|
||||
FTL_DCHECK(!rasterizer_);
|
||||
rasterizer_.reset(new Rasterizer());
|
||||
mojo::ConnectToService(connector.get(), "mojo:framebuffer",
|
||||
mojo::GetProxy(&framebuffer_provider_));
|
||||
framebuffer_provider_->Create(ftl::MakeRunnable([self = GetWeakPtr()](
|
||||
mojo::InterfaceHandle<mojo::Framebuffer> framebuffer,
|
||||
mojo::FramebufferInfoPtr info) {
|
||||
if (self)
|
||||
self->DidCreateFramebuffer(std::move(framebuffer), std::move(info));
|
||||
}));
|
||||
InitRootBundle(std::move(bundle));
|
||||
|
||||
mojo::ConnectToService(connector.get(), "mojo:view_manager_service",
|
||||
mojo::GetProxy(&view_manager_));
|
||||
}
|
||||
|
||||
void RuntimeHolder::Run(const std::string& script_uri,
|
||||
std::vector<char> bundle) {
|
||||
InitRootBundle(std::move(bundle));
|
||||
void RuntimeHolder::CreateView(
|
||||
const std::string& script_uri,
|
||||
mojo::InterfaceRequest<mozart::ViewOwner> view_owner_request,
|
||||
mojo::InterfaceRequest<mojo::ServiceProvider> services) {
|
||||
if (view_listener_binding_.is_bound()) {
|
||||
// TODO(jeffbrown): Refactor this to support multiple view instances
|
||||
// sharing the same underlying root bundle (but with different runtimes).
|
||||
FTL_LOG(ERROR) << "The view has already been created.";
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> snapshot;
|
||||
if (!asset_store_->GetAsBuffer(kSnapshotKey, &snapshot)) {
|
||||
@@ -63,6 +73,18 @@ void RuntimeHolder::Run(const std::string& script_uri,
|
||||
return;
|
||||
}
|
||||
|
||||
mozart::ViewListenerPtr view_listener;
|
||||
view_listener_binding_.Bind(mojo::GetProxy(&view_listener));
|
||||
view_manager_->CreateView(mojo::GetProxy(&view_),
|
||||
std::move(view_owner_request),
|
||||
std::move(view_listener), script_uri);
|
||||
|
||||
mozart::ScenePtr scene;
|
||||
view_->CreateScene(mojo::GetProxy(&scene));
|
||||
blink::Threads::Gpu()->PostTask(ftl::MakeCopyable([
|
||||
rasterizer = rasterizer_.get(), scene = std::move(scene)
|
||||
]() mutable { rasterizer->SetScene(std::move(scene)); }));
|
||||
|
||||
runtime_ = blink::RuntimeController::Create(this);
|
||||
runtime_->CreateDartController(script_uri);
|
||||
runtime_->SetViewportMetrics(viewport_metrics_);
|
||||
@@ -71,19 +93,10 @@ void RuntimeHolder::Run(const std::string& script_uri,
|
||||
}
|
||||
|
||||
void RuntimeHolder::ScheduleFrame() {
|
||||
if (runtime_requested_frame_)
|
||||
if (pending_invalidation_ || !deferred_invalidation_callback_.is_null())
|
||||
return;
|
||||
runtime_requested_frame_ = true;
|
||||
|
||||
FTL_DCHECK(!did_defer_frame_request_);
|
||||
++outstanding_requests_;
|
||||
|
||||
if (outstanding_requests_ >= kPipelineDepth) {
|
||||
did_defer_frame_request_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ScheduleDelayedFrame();
|
||||
pending_invalidation_ = true;
|
||||
view_->Invalidate();
|
||||
}
|
||||
|
||||
void RuntimeHolder::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
|
||||
@@ -91,6 +104,10 @@ void RuntimeHolder::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
|
||||
return; // Only draw once per frame.
|
||||
is_ready_to_draw_ = false;
|
||||
|
||||
layer_tree->set_frame_size(SkISize::Make(viewport_metrics_->physical_width,
|
||||
viewport_metrics_->physical_height));
|
||||
layer_tree->set_scene_version(scene_version_);
|
||||
|
||||
blink::Threads::Gpu()->PostTask(ftl::MakeCopyable([
|
||||
rasterizer = rasterizer_.get(), layer_tree = std::move(layer_tree),
|
||||
self = GetWeakPtr()
|
||||
@@ -129,42 +146,51 @@ blink::UnzipperProvider RuntimeHolder::GetUnzipperProviderForRootBundle() {
|
||||
};
|
||||
}
|
||||
|
||||
void RuntimeHolder::DidCreateFramebuffer(
|
||||
mojo::InterfaceHandle<mojo::Framebuffer> framebuffer,
|
||||
mojo::FramebufferInfoPtr info) {
|
||||
viewport_metrics_->physical_width = info->size->width;
|
||||
viewport_metrics_->physical_height = info->size->height;
|
||||
if (runtime_)
|
||||
runtime_->SetViewportMetrics(viewport_metrics_);
|
||||
void RuntimeHolder::OnInvalidation(mozart::ViewInvalidationPtr invalidation,
|
||||
const OnInvalidationCallback& callback) {
|
||||
FTL_DCHECK(invalidation);
|
||||
pending_invalidation_ = false;
|
||||
|
||||
blink::Threads::Gpu()->PostTask(ftl::MakeCopyable([
|
||||
rasterizer = rasterizer_.get(), framebuffer = std::move(framebuffer),
|
||||
info = std::move(info)
|
||||
]() mutable {
|
||||
rasterizer->SetFramebuffer(std::move(framebuffer), std::move(info));
|
||||
}));
|
||||
// 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 =
|
||||
view_properties_->display_metrics->device_pixel_ratio;
|
||||
runtime_->SetViewportMetrics(viewport_metrics_);
|
||||
}
|
||||
|
||||
// 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_.is_null());
|
||||
deferred_invalidation_callback_ = callback;
|
||||
return;
|
||||
}
|
||||
|
||||
++outstanding_requests_;
|
||||
BeginFrame();
|
||||
|
||||
// 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.Run();
|
||||
}
|
||||
|
||||
ftl::WeakPtr<RuntimeHolder> RuntimeHolder::GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
void RuntimeHolder::ScheduleDelayedFrame() {
|
||||
// TODO(abarth): We should align with vsync or with our own timer pulse.
|
||||
blink::Threads::UI()->PostDelayedTask(
|
||||
[self = GetWeakPtr()]() {
|
||||
if (self)
|
||||
self->BeginFrame();
|
||||
},
|
||||
kTargetFrameInterval);
|
||||
}
|
||||
|
||||
void RuntimeHolder::BeginFrame() {
|
||||
FTL_DCHECK(outstanding_requests_ > 0);
|
||||
FTL_DCHECK(outstanding_requests_ <= kPipelineDepth) << outstanding_requests_;
|
||||
|
||||
FTL_DCHECK(runtime_requested_frame_);
|
||||
runtime_requested_frame_ = false;
|
||||
FTL_DCHECK(outstanding_requests_ <= kMaxPipelineDepth)
|
||||
<< outstanding_requests_;
|
||||
|
||||
FTL_DCHECK(!is_ready_to_draw_);
|
||||
is_ready_to_draw_ = true;
|
||||
@@ -183,9 +209,15 @@ void RuntimeHolder::OnFrameComplete() {
|
||||
FTL_DCHECK(outstanding_requests_ > 0);
|
||||
--outstanding_requests_;
|
||||
|
||||
if (did_defer_frame_request_) {
|
||||
did_defer_frame_request_ = false;
|
||||
ScheduleDelayedFrame();
|
||||
if (!deferred_invalidation_callback_.is_null() &&
|
||||
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 = deferred_invalidation_callback_;
|
||||
deferred_invalidation_callback_.reset();
|
||||
ScheduleFrame();
|
||||
callback.Run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef FLUTTER_CONTENT_HANDLER_RUNTIME_HOLDER_H_
|
||||
#define FLUTTER_CONTENT_HANDLER_RUNTIME_HOLDER_H_
|
||||
|
||||
#include "apps/mozart/services/views/interfaces/view_manager.mojom.h"
|
||||
#include "flutter/assets/unzipper_provider.h"
|
||||
#include "flutter/assets/zip_asset_store.h"
|
||||
#include "flutter/flow/layers/layer_tree.h"
|
||||
@@ -14,20 +15,22 @@
|
||||
#include "lib/ftl/functional/closure.h"
|
||||
#include "lib/ftl/macros.h"
|
||||
#include "lib/ftl/memory/weak_ptr.h"
|
||||
#include "mojo/public/cpp/bindings/binding.h"
|
||||
#include "mojo/public/interfaces/application/application_connector.mojom.h"
|
||||
#include "mojo/services/asset_bundle/interfaces/asset_bundle.mojom.h"
|
||||
#include "mojo/services/framebuffer/interfaces/framebuffer.mojom.h"
|
||||
|
||||
namespace flutter_content_handler {
|
||||
class Rasterizer;
|
||||
|
||||
class RuntimeHolder : public blink::RuntimeDelegate {
|
||||
class RuntimeHolder : public blink::RuntimeDelegate, mozart::ViewListener {
|
||||
public:
|
||||
RuntimeHolder();
|
||||
~RuntimeHolder();
|
||||
|
||||
void Init(mojo::ApplicationConnectorPtr connector);
|
||||
void Run(const std::string& script_uri, std::vector<char> bundle);
|
||||
void Init(mojo::ApplicationConnectorPtr connector, std::vector<char> bundle);
|
||||
void CreateView(const std::string& script_uri,
|
||||
mojo::InterfaceRequest<mozart::ViewOwner> view_owner_request,
|
||||
mojo::InterfaceRequest<mojo::ServiceProvider> services);
|
||||
|
||||
private:
|
||||
// |blink::RuntimeDelegate| implementation:
|
||||
@@ -35,30 +38,35 @@ class RuntimeHolder : public blink::RuntimeDelegate {
|
||||
void Render(std::unique_ptr<flow::LayerTree> layer_tree) override;
|
||||
void DidCreateMainIsolate(Dart_Isolate isolate) override;
|
||||
|
||||
// |mozart::ViewListener| implementation:
|
||||
void OnInvalidation(mozart::ViewInvalidationPtr invalidation,
|
||||
const OnInvalidationCallback& callback) override;
|
||||
|
||||
ftl::WeakPtr<RuntimeHolder> GetWeakPtr();
|
||||
|
||||
void InitRootBundle(std::vector<char> bundle);
|
||||
blink::UnzipperProvider GetUnzipperProviderForRootBundle();
|
||||
|
||||
void DidCreateFramebuffer(
|
||||
mojo::InterfaceHandle<mojo::Framebuffer> framebuffer,
|
||||
mojo::FramebufferInfoPtr info);
|
||||
|
||||
void ScheduleDelayedFrame();
|
||||
void BeginFrame();
|
||||
void OnFrameComplete();
|
||||
void Invalidate();
|
||||
|
||||
std::vector<char> root_bundle_data_;
|
||||
ftl::RefPtr<blink::ZipAssetStore> asset_store_;
|
||||
mojo::asset_bundle::AssetBundlePtr root_bundle_;
|
||||
|
||||
mojo::FramebufferProviderPtr framebuffer_provider_;
|
||||
std::unique_ptr<Rasterizer> rasterizer_;
|
||||
std::unique_ptr<blink::RuntimeController> runtime_;
|
||||
sky::ViewportMetricsPtr viewport_metrics_;
|
||||
|
||||
bool runtime_requested_frame_ = false;
|
||||
bool did_defer_frame_request_ = false;
|
||||
mozart::ViewManagerPtr view_manager_;
|
||||
mojo::Binding<mozart::ViewListener> view_listener_binding_;
|
||||
mozart::ViewPtr view_;
|
||||
mozart::ViewPropertiesPtr view_properties_;
|
||||
uint32_t scene_version_ = mozart::kSceneVersionNone;
|
||||
|
||||
bool pending_invalidation_ = false;
|
||||
OnInvalidationCallback deferred_invalidation_callback_;
|
||||
bool is_ready_to_draw_ = false;
|
||||
int outstanding_requests_ = 0;
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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/content_handler/skia_surface_holder.h"
|
||||
|
||||
#include "lib/ftl/logging.h"
|
||||
#include "mojo/public/cpp/system/buffer.h"
|
||||
#include "third_party/skia/include/core/SkCanvas.h"
|
||||
|
||||
namespace flutter_content_handler {
|
||||
|
||||
SkiaSurfaceHolder::SkiaSurfaceHolder(const SkISize& size) {
|
||||
size_t row_bytes = size.width() * sizeof(uint32_t);
|
||||
size_t total_bytes = size.height() * row_bytes;
|
||||
|
||||
FTL_CHECK(MOJO_RESULT_OK ==
|
||||
mojo::CreateSharedBuffer(nullptr, total_bytes, &buffer_handle_));
|
||||
FTL_CHECK(MOJO_RESULT_OK == mojo::MapBuffer(buffer_handle_.get(), 0u,
|
||||
total_bytes, &buffer_,
|
||||
MOJO_MAP_BUFFER_FLAG_NONE));
|
||||
|
||||
surface_ = SkSurface::MakeRasterDirect(
|
||||
SkImageInfo::Make(size.width(), size.height(), kBGRA_8888_SkColorType,
|
||||
kPremul_SkAlphaType),
|
||||
buffer_, row_bytes);
|
||||
FTL_CHECK(surface_);
|
||||
}
|
||||
|
||||
SkiaSurfaceHolder::~SkiaSurfaceHolder() {
|
||||
FTL_CHECK(MOJO_RESULT_OK == mojo::UnmapBuffer(buffer_));
|
||||
}
|
||||
|
||||
mozart::ImagePtr SkiaSurfaceHolder::TakeImage() {
|
||||
FTL_DCHECK(buffer_handle_.get().value());
|
||||
|
||||
auto image = mozart::Image::New();
|
||||
image->size = mojo::Size::New();
|
||||
image->size->width = surface_->width();
|
||||
image->size->height = surface_->height();
|
||||
image->stride = image->size->width * sizeof(uint32_t);
|
||||
image->pixel_format = mozart::Image::PixelFormat::B8G8R8A8;
|
||||
image->alpha_format = mozart::Image::AlphaFormat::PREMULTIPLIED;
|
||||
image->buffer = std::move(buffer_handle_);
|
||||
return image;
|
||||
}
|
||||
|
||||
} // namespace flutter_content_handler
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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.
|
||||
|
||||
#ifndef FLUTTER_CONTENT_HANDLER_SKIA_SURFACE_HOLDER_H_
|
||||
#define FLUTTER_CONTENT_HANDLER_SKIA_SURFACE_HOLDER_H_
|
||||
|
||||
#include "apps/mozart/services/composition/interfaces/image.mojom.h"
|
||||
#include "lib/ftl/macros.h"
|
||||
#include "mojo/services/geometry/interfaces/geometry.mojom.h"
|
||||
#include "third_party/skia/include/core/SkSize.h"
|
||||
#include "third_party/skia/include/core/SkSurface.h"
|
||||
|
||||
namespace flutter_content_handler {
|
||||
|
||||
// Provides an |SkSurface| backed by a shared memory buffer for software
|
||||
// rendering which can then be passed to the Mozart compositor in the form
|
||||
// of an |Image|.
|
||||
class SkiaSurfaceHolder {
|
||||
public:
|
||||
SkiaSurfaceHolder(const SkISize& size);
|
||||
~SkiaSurfaceHolder();
|
||||
|
||||
// Gets the |SkSurface| backed by this buffer.
|
||||
const sk_sp<SkSurface>& surface() const { return surface_; }
|
||||
|
||||
// Gets an |Image| backed by this buffer, transferring ownership of the
|
||||
// underlying shared memory buffer to the image. The image can then be
|
||||
// sent to the Mozart compositor as an |ImageResource|.
|
||||
// This method must be called at most once.
|
||||
//
|
||||
// Note: The underlying shared memory buffer remains mapped in this process
|
||||
// (and the |SkSurface| remains usable) until the |SkiaSurfaceHolder|
|
||||
// itself is destroyed.
|
||||
mozart::ImagePtr TakeImage();
|
||||
|
||||
private:
|
||||
mojo::ScopedSharedBufferHandle buffer_handle_;
|
||||
void* buffer_;
|
||||
sk_sp<SkSurface> surface_;
|
||||
|
||||
FTL_DISALLOW_COPY_AND_ASSIGN(SkiaSurfaceHolder);
|
||||
};
|
||||
|
||||
} // namespace flutter_content_handler
|
||||
|
||||
#endif // FLUTTER_CONTENT_HANDLER_SKIA_SURFACE_HOLDER_H_
|
||||
+5
-3
@@ -10,8 +10,6 @@ source_set("flow") {
|
||||
"instrumentation.h",
|
||||
"layers/backdrop_filter_layer.cc",
|
||||
"layers/backdrop_filter_layer.h",
|
||||
"layers/child_scene_layer.cc",
|
||||
"layers/child_scene_layer.h",
|
||||
"layers/clip_path_layer.cc",
|
||||
"layers/clip_path_layer.h",
|
||||
"layers/clip_rect_layer.cc",
|
||||
@@ -48,13 +46,17 @@ source_set("flow") {
|
||||
"//flutter/skia",
|
||||
"//flutter/synchronization",
|
||||
"//lib/ftl",
|
||||
"//mojo/services/gfx/composition/interfaces",
|
||||
]
|
||||
|
||||
if (is_fuchsia) {
|
||||
sources += [
|
||||
"layers/child_scene_layer.cc",
|
||||
"layers/child_scene_layer.h",
|
||||
"texture_image_none.cc",
|
||||
]
|
||||
deps += [
|
||||
"//apps/mozart/services/composition/interfaces",
|
||||
]
|
||||
} else {
|
||||
sources += [
|
||||
"gl_connection.cc",
|
||||
|
||||
@@ -50,18 +50,19 @@ void ChildSceneLayer::Paint(PaintContext& context) {
|
||||
TRACE_EVENT0("flutter", "ChildSceneLayer::Paint");
|
||||
}
|
||||
|
||||
void ChildSceneLayer::UpdateScene(mojo::gfx::composition::SceneUpdate* update,
|
||||
mojo::gfx::composition::Node* container) {
|
||||
void ChildSceneLayer::UpdateScene(mozart::SceneUpdate* update,
|
||||
mozart::Node* container) {
|
||||
uint32_t id = next_id++;
|
||||
|
||||
auto child_resource = mojo::gfx::composition::Resource::New();
|
||||
child_resource->set_scene(mojo::gfx::composition::SceneResource::New());
|
||||
child_resource->get_scene()->scene_token = scene_token_.Clone();
|
||||
auto child_resource = mozart::Resource::New();
|
||||
child_resource->set_scene(mozart::SceneResource::New());
|
||||
child_resource->get_scene()->scene_token = mozart::SceneToken::New();
|
||||
child_resource->get_scene()->scene_token->value = scene_token_;
|
||||
update->resources.insert(id, child_resource.Pass());
|
||||
|
||||
auto child_node = mojo::gfx::composition::Node::New();
|
||||
child_node->op = mojo::gfx::composition::NodeOp::New();
|
||||
child_node->op->set_scene(mojo::gfx::composition::SceneNodeOp::New());
|
||||
auto child_node = mozart::Node::New();
|
||||
child_node->op = mozart::NodeOp::New();
|
||||
child_node->op->set_scene(mozart::SceneNodeOp::New());
|
||||
child_node->op->get_scene()->scene_resource_id = id;
|
||||
child_node->content_clip = mojo::RectF::New();
|
||||
child_node->content_clip->width = physical_size_.width();
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define FLUTTER_FLOW_LAYERS_CHILD_SCENE_LAYER_H_
|
||||
|
||||
#include "flutter/flow/layers/layer.h"
|
||||
#include "mojo/services/gfx/composition/interfaces/scenes.mojom.h"
|
||||
#include "apps/mozart/services/composition/interfaces/scenes.mojom.h"
|
||||
|
||||
namespace flow {
|
||||
|
||||
@@ -25,20 +25,18 @@ class ChildSceneLayer : public Layer {
|
||||
physical_size_ = physical_size;
|
||||
}
|
||||
|
||||
void set_scene_token(mojo::gfx::composition::SceneTokenPtr scene_token) {
|
||||
scene_token_ = scene_token.Pass();
|
||||
}
|
||||
void set_scene_token(uint32_t scene_token) { scene_token_ = scene_token; }
|
||||
|
||||
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
|
||||
void Paint(PaintContext& context) override;
|
||||
void UpdateScene(mojo::gfx::composition::SceneUpdate* update,
|
||||
mojo::gfx::composition::Node* container) override;
|
||||
void UpdateScene(mozart::SceneUpdate* update,
|
||||
mozart::Node* container) override;
|
||||
|
||||
private:
|
||||
SkPoint offset_;
|
||||
float device_pixel_ratio_;
|
||||
SkISize physical_size_;
|
||||
mojo::gfx::composition::SceneTokenPtr scene_token_;
|
||||
uint32_t scene_token_;
|
||||
SkMatrix transform_;
|
||||
|
||||
FTL_DISALLOW_COPY_AND_ASSIGN(ChildSceneLayer);
|
||||
|
||||
@@ -39,10 +39,12 @@ void ContainerLayer::PaintChildren(PaintContext& context) const {
|
||||
layer->Paint(context);
|
||||
}
|
||||
|
||||
void ContainerLayer::UpdateScene(mojo::gfx::composition::SceneUpdate* update,
|
||||
mojo::gfx::composition::Node* container) {
|
||||
#if defined(OS_FUCHSIA)
|
||||
void ContainerLayer::UpdateScene(mozart::SceneUpdate* update,
|
||||
mozart::Node* container) {
|
||||
for (auto& layer : layers_)
|
||||
layer->UpdateScene(update, container);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace flow
|
||||
|
||||
@@ -22,8 +22,10 @@ class ContainerLayer : public Layer {
|
||||
|
||||
void PaintChildren(PaintContext& context) const;
|
||||
|
||||
void UpdateScene(mojo::gfx::composition::SceneUpdate* update,
|
||||
mojo::gfx::composition::Node* container) override;
|
||||
#if defined(OS_FUCHSIA)
|
||||
void UpdateScene(mozart::SceneUpdate* update,
|
||||
mozart::Node* container) override;
|
||||
#endif
|
||||
|
||||
const std::vector<std::unique_ptr<Layer>>& layers() const { return layers_; }
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ Layer::~Layer() {}
|
||||
|
||||
void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {}
|
||||
|
||||
void Layer::UpdateScene(mojo::gfx::composition::SceneUpdate* update,
|
||||
mojo::gfx::composition::Node* container) {}
|
||||
#if defined(OS_FUCHSIA)
|
||||
void Layer::UpdateScene(mozart::SceneUpdate* update, mozart::Node* container) {}
|
||||
#endif
|
||||
|
||||
} // namespace flow
|
||||
|
||||
+10
-8
@@ -11,6 +11,7 @@
|
||||
#include "flutter/flow/instrumentation.h"
|
||||
#include "flutter/flow/raster_cache.h"
|
||||
#include "flutter/glue/trace_event.h"
|
||||
#include "lib/ftl/build_config.h"
|
||||
#include "lib/ftl/logging.h"
|
||||
#include "lib/ftl/macros.h"
|
||||
#include "third_party/skia/include/core/SkCanvas.h"
|
||||
@@ -23,14 +24,12 @@
|
||||
#include "third_party/skia/include/core/SkRRect.h"
|
||||
#include "third_party/skia/include/core/SkXfermode.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace gfx {
|
||||
namespace composition {
|
||||
#if defined(OS_FUCHSIA)
|
||||
namespace mozart {
|
||||
class SceneUpdate;
|
||||
class Node;
|
||||
} // composition
|
||||
} // namespace gfx
|
||||
} // namespace mojo
|
||||
} // namespace mozart
|
||||
#endif
|
||||
|
||||
namespace flow {
|
||||
|
||||
@@ -55,8 +54,11 @@ class Layer {
|
||||
};
|
||||
|
||||
virtual void Paint(PaintContext& context) = 0;
|
||||
virtual void UpdateScene(mojo::gfx::composition::SceneUpdate* update,
|
||||
mojo::gfx::composition::Node* container);
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
virtual void UpdateScene(mozart::SceneUpdate* update,
|
||||
mozart::Node* container);
|
||||
#endif
|
||||
|
||||
ContainerLayer* parent() const { return parent_; }
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
|
||||
namespace flow {
|
||||
|
||||
LayerTree::LayerTree() : scene_version_(0), rasterizer_tracing_threshold_(0) {}
|
||||
LayerTree::LayerTree()
|
||||
: frame_size_{}, scene_version_(0), rasterizer_tracing_threshold_(0) {}
|
||||
|
||||
LayerTree::~LayerTree() {}
|
||||
|
||||
@@ -32,10 +33,12 @@ void LayerTree::Raster(CompositorContext::ScopedFrame& frame,
|
||||
}
|
||||
}
|
||||
|
||||
void LayerTree::UpdateScene(mojo::gfx::composition::SceneUpdate* update,
|
||||
mojo::gfx::composition::Node* container) {
|
||||
#if defined(OS_FUCHSIA)
|
||||
void LayerTree::UpdateScene(mozart::SceneUpdate* update,
|
||||
mozart::Node* container) {
|
||||
TRACE_EVENT0("flutter", "LayerTree::UpdateScene");
|
||||
root_layer_->UpdateScene(update, container);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace flow
|
||||
|
||||
@@ -26,11 +26,12 @@ class LayerTree {
|
||||
void Raster(CompositorContext::ScopedFrame& frame,
|
||||
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(mojo::gfx::composition::SceneUpdate* update,
|
||||
mojo::gfx::composition::Node* container);
|
||||
void UpdateScene(mozart::SceneUpdate* update, mozart::Node* container);
|
||||
#endif
|
||||
|
||||
Layer* root_layer() const { return root_layer_.get(); }
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user