提交 2c5a71e7 编写于 作者: A Adam Barth 提交者: GitHub

//flutter/content_handler code complete (#2925)

This patch should contain all the code we need to run Flutter on
Fuchsia's software framebuffer (without text). I haven't actually tried
running the code, so I'm sure it doesn't work yet.
上级 b2058f8b
......@@ -12,14 +12,24 @@ 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",
]
deps = [
"//dart/runtime:libdart",
"//dart/runtime/vm:libdart_platform",
"//flutter/common",
"//flutter/flow",
"//flutter/glue",
"//flutter/runtime",
"//flutter/services/engine:interfaces",
"//flutter/services/pointer:interfaces",
"//lib/ftl",
"//lib/mtl",
"//mojo/public/cpp/application",
......@@ -28,7 +38,12 @@ executable("content_handler") {
"//mojo/public/cpp/utility",
"//mojo/public/interfaces/application",
"//mojo/services/content_handler/interfaces",
"//mojo/services/framebuffer/interfaces",
"//mojo/system",
"//third_party/skia",
# TODO(abarth): Move this zip library more sensible for re-use.
"//apps/dart_content_handler/zip",
# TODO(abarth): We shouldn't need to depend on libdart_builtin but we fail
# to link otherwise.
......
......@@ -6,25 +6,46 @@
#include <utility>
#include "apps/dart_content_handler/zip/unzipper.h"
#include "flutter/content_handler/runtime_holder.h"
#include "lib/ftl/logging.h"
#include "mojo/public/cpp/application/connect.h"
namespace flutter_content_handler {
namespace {
constexpr char kSnapshotKey[] = "snapshot_blob.bin";
std::vector<char> ExtractSnapshot(std::vector<char> bundle) {
zip::Unzipper unzipper(std::move(bundle));
return unzipper.Extract(kSnapshotKey);
}
} // namespace
ApplicationImpl::ApplicationImpl(
mojo::InterfaceRequest<mojo::Application> application,
mojo::URLResponsePtr response)
: binding_(this, std::move(application)),
initial_response_(std::move(response)) {}
: binding_(this, std::move(application)) {
drainer_.reset(new glue::DrainDataPipeJob(
std::move(response->body), [this](std::vector<char> bundle) {
snapshot_ = ExtractSnapshot(std::move(bundle));
StartRuntimeIfReady();
}));
}
ApplicationImpl::~ApplicationImpl() {}
void ApplicationImpl::Initialize(mojo::InterfaceHandle<mojo::Shell> shell,
mojo::Array<mojo::String> args,
const mojo::String& url) {
FTL_DCHECK(initial_response_);
shell_ = mojo::ShellPtr::Create(shell.Pass());
url_ = url;
mojo::ApplicationConnectorPtr connector;
shell_->CreateApplicationConnector(mojo::GetProxy(&connector));
runtime_holder_.reset(new RuntimeHolder());
runtime_holder_->Init(std::move(connector));
StartRuntimeIfReady();
}
void ApplicationImpl::AcceptConnection(
......@@ -37,4 +58,10 @@ void ApplicationImpl::RequestQuit() {
delete this;
}
void ApplicationImpl::StartRuntimeIfReady() {
if (!runtime_holder_ || snapshot_.empty())
return;
runtime_holder_->Run(url_, std::move(snapshot_));
}
} // namespace flutter_content_handler
......@@ -5,12 +5,17 @@
#ifndef FLUTTER_CONTENT_HANDLER_APPLICATION_IMPL_H_
#define FLUTTER_CONTENT_HANDLER_APPLICATION_IMPL_H_
#include <memory>
#include "flutter/glue/drain_data_pipe_job.h"
#include "lib/ftl/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/interfaces/application/application.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 {
public:
......@@ -29,10 +34,18 @@ class ApplicationImpl : public mojo::Application {
mojo::InterfaceRequest<mojo::ServiceProvider> services) override;
void RequestQuit() override;
void StartRuntimeIfReady();
mojo::StrongBinding<mojo::Application> binding_;
mojo::URLResponsePtr initial_response_;
std::string url_;
std::unique_ptr<glue::DrainDataPipeJob> drainer_;
std::vector<char> snapshot_;
mojo::ShellPtr shell_;
std::string url_;
std::unique_ptr<RuntimeHolder> runtime_holder_;
FTL_DISALLOW_COPY_AND_ASSIGN(ApplicationImpl);
};
} // namespace flutter_content_handler
......
// 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/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_vm_unmap(0, 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_vm_map(0, 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 = kRGBA_8888_SkColorType;
sk_alpha_type = kPremul_SkAlphaType;
break;
default:
FTL_LOG(WARNING) << "Unknown color type " << info_->format;
sk_color_type = kRGB_565_SkColorType;
sk_alpha_type = kOpaque_SkAlphaType;
break;
}
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);
}
} // namespace flutter_content_handler
// 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);
mojo::Framebuffer* get() const { return framebuffer_.get(); }
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_
......@@ -39,8 +39,8 @@ class App : public mojo::ApplicationImplBase {
ftl::RefPtr<ftl::TaskRunner> gpu_task_runner;
gpu_thread_ = mtl::CreateThread(&gpu_task_runner);
ftl::RefPtr<ftl::TaskRunner> ui_task_runner;
ui_thread_ = mtl::CreateThread(&ui_task_runner);
ftl::RefPtr<ftl::TaskRunner> ui_task_runner(
mtl::MessageLoop::GetCurrent()->task_runner());
ftl::RefPtr<ftl::TaskRunner> io_task_runner;
io_thread_ = mtl::CreateThread(&io_task_runner);
......
// 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/rasterizer.h"
#include <utility>
#include "lib/ftl/functional/make_runnable.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace flutter_content_handler {
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::Draw(std::unique_ptr<flow::LayerTree> layer_tree,
ftl::Closure callback) {
if (!framebuffer_.surface()) {
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();
framebuffer_.get()->Flush(ftl::MakeRunnable(std::move(callback)));
}
} // namespace flutter_content_handler
// 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_RASTERIZER_H_
#define FLUTTER_CONTENT_HANDLER_RASTERIZER_H_
#include "flutter/content_handler/framebuffer_skia.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 {
class Rasterizer {
public:
Rasterizer();
~Rasterizer();
void SetFramebuffer(mojo::InterfaceHandle<mojo::Framebuffer> framebuffer,
mojo::FramebufferInfoPtr info);
void Draw(std::unique_ptr<flow::LayerTree> layer_tree, ftl::Closure callback);
private:
FramebufferSkia framebuffer_;
sk_sp<SkSurface> surface_;
flow::CompositorContext compositor_context_;
FTL_DISALLOW_COPY_AND_ASSIGN(Rasterizer);
};
} // namespace flutter_content_handler
#endif // FLUTTER_CONTENT_HANDLER_RASTERIZER_H_
// 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/runtime_holder.h"
#include <utility>
#include "flutter/common/threads.h"
#include "flutter/content_handler/rasterizer.h"
#include "flutter/runtime/dart_controller.h"
#include "flutter/services/engine/sky_engine.mojom.h"
#include "lib/ftl/functional/make_copyable.h"
#include "lib/ftl/functional/make_runnable.h"
#include "lib/ftl/logging.h"
#include "lib/ftl/time/time_delta.h"
#include "mojo/public/cpp/application/connect.h"
namespace flutter_content_handler {
namespace {
constexpr int kPipelineDepth = 3;
constexpr ftl::TimeDelta kTargetFrameInterval =
ftl::TimeDelta::FromMilliseconds(16);
} // namespace
RuntimeHolder::RuntimeHolder() : weak_factory_(this) {}
RuntimeHolder::~RuntimeHolder() {
blink::Threads::Gpu()->PostTask(
ftl::MakeCopyable([rasterizer = std::move(rasterizer_)](){
// Deletes rasterizer.
}));
}
void RuntimeHolder::Init(mojo::ApplicationConnectorPtr connector) {
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));
}));
runtime_ = blink::RuntimeController::Create(this);
}
void RuntimeHolder::Run(const std::string& script_uri,
std::vector<char> snapshot) {
runtime_->CreateDartController(script_uri);
runtime_->dart_controller()->RunFromSnapshot(
reinterpret_cast<const uint8_t*>(snapshot.data()), snapshot.size());
}
void RuntimeHolder::ScheduleFrame() {
if (runtime_requested_frame_)
return;
runtime_requested_frame_ = true;
FTL_DCHECK(!did_defer_frame_request_);
++outstanding_requests_;
if (outstanding_requests_ >= kPipelineDepth) {
did_defer_frame_request_ = true;
return;
}
ScheduleDelayedFrame();
}
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;
blink::Threads::Gpu()->PostTask(ftl::MakeCopyable([
rasterizer = rasterizer_.get(), layer_tree = std::move(layer_tree),
self = GetWeakPtr()
]() mutable {
rasterizer->Draw(std::move(layer_tree), [self]() {
if (self)
self->OnFrameComplete();
});
}));
}
void RuntimeHolder::DidCreateFramebuffer(
mojo::InterfaceHandle<mojo::Framebuffer> framebuffer,
mojo::FramebufferInfoPtr info) {
auto viewport_metrics = sky::ViewportMetrics::New();
viewport_metrics->physical_width = info->size->width;
viewport_metrics->physical_height = info->size->height;
runtime_->SetViewportMetrics(viewport_metrics);
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));
}));
}
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(!is_ready_to_draw_);
is_ready_to_draw_ = true;
runtime_->BeginFrame(ftl::TimePoint::Now());
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 (did_defer_frame_request_) {
did_defer_frame_request_ = false;
ScheduleDelayedFrame();
}
}
} // namespace flutter_content_handler
// 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_RUNTIME_HOLDER_H_
#define FLUTTER_CONTENT_HANDLER_RUNTIME_HOLDER_H_
#include "flutter/flow/layers/layer_tree.h"
#include "flutter/runtime/runtime_controller.h"
#include "flutter/runtime/runtime_delegate.h"
#include "lib/ftl/functional/closure.h"
#include "lib/ftl/macros.h"
#include "lib/ftl/memory/weak_ptr.h"
#include "mojo/public/interfaces/application/application_connector.mojom.h"
#include "mojo/services/framebuffer/interfaces/framebuffer.mojom.h"
namespace flutter_content_handler {
class Rasterizer;
class RuntimeHolder : public blink::RuntimeDelegate {
public:
RuntimeHolder();
~RuntimeHolder();
void Init(mojo::ApplicationConnectorPtr connector);
void Run(const std::string& script_uri, std::vector<char> snapshot);
private:
// |blink::RuntimeDelegate| implementation:
void ScheduleFrame() override;
void Render(std::unique_ptr<flow::LayerTree> layer_tree) override;
ftl::WeakPtr<RuntimeHolder> GetWeakPtr();
void DidCreateFramebuffer(
mojo::InterfaceHandle<mojo::Framebuffer> framebuffer,
mojo::FramebufferInfoPtr info);
void ScheduleDelayedFrame();
void BeginFrame();
void OnFrameComplete();
mojo::FramebufferProviderPtr framebuffer_provider_;
std::unique_ptr<Rasterizer> rasterizer_;
std::unique_ptr<blink::RuntimeController> runtime_;
bool runtime_requested_frame_ = false;
bool did_defer_frame_request_ = false;
bool is_ready_to_draw_ = false;
int outstanding_requests_ = 0;
ftl::WeakPtrFactory<RuntimeHolder> weak_factory_;
FTL_DISALLOW_COPY_AND_ASSIGN(RuntimeHolder);
};
} // namespace flutter_content_handler
#endif // FLUTTER_CONTENT_HANDLER_RUNTIME_HOLDER_H_
......@@ -18,8 +18,6 @@ class DartController {
DartController();
~DartController();
static void InitVM();
void RunFromPrecompiledSnapshot();
void RunFromSnapshot(const uint8_t* buffer, size_t size);
void RunFromSource(const std::string& main, const std::string& packages);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册