Skip to content

Commit

Permalink
Add Views V2 support for Fuchsia (flutter#8115)
Browse files Browse the repository at this point in the history
  • Loading branch information
arbreng authored Apr 7, 2019
1 parent 0c393d6 commit ff1bcdc
Show file tree
Hide file tree
Showing 19 changed files with 709 additions and 298 deletions.
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ FILE: ../../../flutter/flow/skia_gpu_object.cc
FILE: ../../../flutter/flow/skia_gpu_object.h
FILE: ../../../flutter/flow/texture.cc
FILE: ../../../flutter/flow/texture.h
FILE: ../../../flutter/flow/view_holder.cc
FILE: ../../../flutter/flow/view_holder.h
FILE: ../../../flutter/flutter_kernel_transformers/lib/track_widget_constructor_locations.dart
FILE: ../../../flutter/fml/arraysize.h
FILE: ../../../flutter/fml/base32.cc
Expand Down
8 changes: 5 additions & 3 deletions flow/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,17 @@ source_set("flow") {
"layers/child_scene_layer.h",
"scene_update_context.cc",
"scene_update_context.h",
"view_holder.cc",
"view_holder.h",
]

public_deps += [
"//garnet/public/lib/ui/scenic/cpp",
"//sdk/fidl/fuchsia.ui.scenic",
"//sdk/fidl/fuchsia.ui.views",
"//sdk/lib/ui/scenic/cpp",
"//topaz/public/dart-pkg/zircon",
"//zircon/public/lib/zx",
]

public_deps += [ "//zircon/public/lib/zx" ]
}
}

Expand Down
115 changes: 58 additions & 57 deletions flow/export_node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,81 +4,82 @@

#include "flutter/flow/export_node.h"

#include "flutter/fml/make_copyable.h"
#include "flutter/fml/thread_local.h"

namespace {

using ExportNodeBindings =
std::unordered_map<zx_koid_t, std::unique_ptr<flow::ExportNode>>;

FML_THREAD_LOCAL fml::ThreadLocal tls_export_node_bindings([](intptr_t value) {
delete reinterpret_cast<ExportNodeBindings*>(value);
});

} // namespace

namespace flow {

ExportNodeHolder::ExportNodeHolder(
fml::RefPtr<fml::TaskRunner> gpu_task_runner,
fml::RefPtr<zircon::dart::Handle> export_token_handle)
: gpu_task_runner_(std::move(gpu_task_runner)),
export_node_(std::make_unique<ExportNode>(export_token_handle)) {
FML_DCHECK(gpu_task_runner_);
ExportNode::ExportNode(zx::eventpair export_token)
: pending_export_token_(std::move(export_token)) {
FML_DCHECK(pending_export_token_);
}

void ExportNodeHolder::Bind(SceneUpdateContext& context,
scenic::ContainerNode& container,
const SkPoint& offset,
bool hit_testable) {
export_node_->Bind(context, container, offset, hit_testable);
}
void ExportNode::Create(zx_koid_t id, zx::eventpair export_token) {
// This GPU thread contains at least 1 ViewHolder. Initialize the per-thread
// bindings.
if (tls_export_node_bindings.Get() == 0) {
tls_export_node_bindings.Set(
reinterpret_cast<intptr_t>(new ExportNodeBindings()));
}

ExportNodeHolder::~ExportNodeHolder() {
gpu_task_runner_->PostTask(
fml::MakeCopyable([export_node = std::move(export_node_)]() {
export_node->Dispose(true);
}));
auto* bindings =
reinterpret_cast<ExportNodeBindings*>(tls_export_node_bindings.Get());
FML_DCHECK(bindings);
FML_DCHECK(bindings->find(id) == bindings->end());

auto export_node =
std::unique_ptr<ExportNode>(new ExportNode(std::move(export_token)));
bindings->emplace(id, std::move(export_node));
}

ExportNode::ExportNode(fml::RefPtr<zircon::dart::Handle> export_token_handle)
: export_token_(export_token_handle->ReleaseHandle()) {}
void ExportNode::Destroy(zx_koid_t id) {
auto* bindings =
reinterpret_cast<ExportNodeBindings*>(tls_export_node_bindings.Get());
FML_DCHECK(bindings);

ExportNode::~ExportNode() {
// Ensure that we properly released the node.
FML_DCHECK(!node_);
FML_DCHECK(scene_update_context_ == nullptr);
bindings->erase(id);
}

void ExportNode::Bind(SceneUpdateContext& context,
scenic::ContainerNode& container,
const SkPoint& offset,
bool hit_testable) {
if (export_token_) {
// Happens first time we bind.
node_.reset(new scenic::EntityNode(container.session()));
node_->Export(std::move(export_token_));

// Add ourselves to the context so it can call Dispose() on us if the Scenic
// session is closed.
context.AddExportNode(this);
scene_update_context_ = &context;
ExportNode* ExportNode::FromId(zx_koid_t id) {
auto* bindings =
reinterpret_cast<ExportNodeBindings*>(tls_export_node_bindings.Get());
if (!bindings) {
return nullptr;
}

if (node_) {
container.AddChild(*node_);
node_->SetTranslation(offset.x(), offset.y(), 0.f);
node_->SetHitTestBehavior(
hit_testable ? fuchsia::ui::gfx::HitTestBehavior::kDefault
: fuchsia::ui::gfx::HitTestBehavior::kSuppress);
auto binding = bindings->find(id);
if (binding == bindings->end()) {
return nullptr;
}

return binding->second.get();
}

void ExportNode::Dispose(bool remove_from_scene_update_context) {
// If scene_update_context_ is set, then we should still have a node left to
// dereference.
// If scene_update_context_ is null, then either:
// 1. A node was never created, or
// 2. A node was created but was already dereferenced (i.e. Dispose has
// already been called).
FML_DCHECK(scene_update_context_ || !node_);

if (remove_from_scene_update_context && scene_update_context_) {
scene_update_context_->RemoveExportNode(this);
void ExportNode::UpdateScene(SceneUpdateContext& context,
const SkPoint& offset,
const SkSize& size,
bool hit_testable) {
if (pending_export_token_) {
export_node_ = std::make_unique<scenic::EntityNode>(context.session());
export_node_->Export(std::move(pending_export_token_));
}
FML_DCHECK(export_node_);

scene_update_context_ = nullptr;
export_token_.reset();
node_ = nullptr;
context.top_entity()->entity_node().AddChild(*export_node_);
export_node_->SetTranslation(offset.x(), offset.y(), -0.1f);
export_node_->SetHitTestBehavior(
hit_testable ? fuchsia::ui::gfx::HitTestBehavior::kDefault
: fuchsia::ui::gfx::HitTestBehavior::kSuppress);
}

} // namespace flow
79 changes: 23 additions & 56 deletions flow/export_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,75 +5,42 @@
#ifndef FLUTTER_FLOW_EXPORT_NODE_H_
#define FLUTTER_FLOW_EXPORT_NODE_H_

#include <memory>

#include <lib/ui/scenic/cpp/resources.h>
#include <lib/zx/eventpair.h>
#include <third_party/skia/include/core/SkMatrix.h>
#include <third_party/skia/include/core/SkPoint.h>
#include <third_party/skia/include/core/SkSize.h>
#include <zircon/types.h>

#include <memory>

#include "dart-pkg/zircon/sdk_ext/handle.h"
#include "flutter/flow/scene_update_context.h"
#include "flutter/fml/build_config.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/ref_counted.h"
#include "lib/ui/scenic/cpp/resources.h"
#include "third_party/flutter/fml/task_runner.h"
#include "third_party/skia/include/core/SkPoint.h"

namespace flow {

// Wrapper class for ExportNode to use on UI Thread. When ExportNodeHolder is
// destroyed, a task is posted on the Rasterizer thread to dispose the resources
// held by the ExportNode.
class ExportNodeHolder : public fml::RefCountedThreadSafe<ExportNodeHolder> {
public:
ExportNodeHolder(fml::RefPtr<fml::TaskRunner> gpu_task_runner,
fml::RefPtr<zircon::dart::Handle> export_token_handle);
~ExportNodeHolder();

// Calls Bind() on the wrapped ExportNode.
void Bind(SceneUpdateContext& context,
scenic::ContainerNode& container,
const SkPoint& offset,
bool hit_testable);

ExportNode* export_node() { return export_node_.get(); }

private:
fml::RefPtr<fml::TaskRunner> gpu_task_runner_;
std::unique_ptr<ExportNode> export_node_;

FML_FRIEND_MAKE_REF_COUNTED(ExportNodeHolder);
FML_FRIEND_REF_COUNTED_THREAD_SAFE(ExportNodeHolder);
FML_DISALLOW_COPY_AND_ASSIGN(ExportNodeHolder);
};

// 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.
// Represents a Scenic |ExportNode| resource that exports an |EntityNode| to
// another session.
//
// This object is created and destroyed on the |Rasterizer|'s' thread.
class ExportNode {
public:
ExportNode(fml::RefPtr<zircon::dart::Handle> export_token_handle);

~ExportNode();
static void Create(zx_koid_t id, zx::eventpair export_token);
static void Destroy(zx_koid_t id);
static ExportNode* FromId(zx_koid_t id);

// Binds the export token to the entity node and adds it as a child of
// the specified container. Must be called on the Rasterizer thread.
void Bind(SceneUpdateContext& context,
scenic::ContainerNode& container,
const SkPoint& offset,
bool hit_testable);
// Creates or updates the contained EntityNode resource using the specified
// |SceneUpdateContext|.
void UpdateScene(SceneUpdateContext& context,
const SkPoint& offset,
const SkSize& size,
bool hit_testable);

private:
friend class SceneUpdateContext;
friend class ExportNodeHolder;

// Cleans up resources held and removes this ExportNode from
// SceneUpdateContext. Must be called on the Rasterizer thread.
void Dispose(bool remove_from_scene_update_context);
ExportNode(zx::eventpair export_token);

// Member variables can only be read or modified on Rasterizer thread.
SceneUpdateContext* scene_update_context_ = nullptr;
zx::eventpair export_token_;
std::unique_ptr<scenic::EntityNode> node_;
zx::eventpair pending_export_token_;
std::unique_ptr<scenic::EntityNode> export_node_;

FML_DISALLOW_COPY_AND_ASSIGN(ExportNode);
};
Expand Down
36 changes: 24 additions & 12 deletions flow/layers/child_scene_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,43 @@

#include "flutter/flow/layers/child_scene_layer.h"

namespace flow {
#include "flutter/flow/export_node.h"
#include "flutter/flow/view_holder.h"

ChildSceneLayer::ChildSceneLayer() = default;
namespace flow {

ChildSceneLayer::~ChildSceneLayer() = default;
ChildSceneLayer::ChildSceneLayer(zx_koid_t layer_id,
bool use_view_holder,
const SkPoint& offset,
const SkSize& size,
bool hit_testable)
: layer_id_(layer_id),
offset_(offset),
size_(size),
hit_testable_(hit_testable),
use_view_holder_(use_view_holder) {}

void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
set_needs_system_composite(true);
}

void ChildSceneLayer::Paint(PaintContext& context) const {
FXL_NOTREACHED() << "This layer never needs painting.";
FML_NOTREACHED() << "This layer never needs painting.";
}

void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());

// 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.
if (export_node_holder_) {
context.AddChildScene(export_node_holder_->export_node(), offset_,
hit_testable_);
if (use_view_holder_) {
auto* view_holder = ViewHolder::FromId(layer_id_);
FML_DCHECK(view_holder);

view_holder->UpdateScene(context, offset_, size_, hit_testable_);
} else {
auto* export_node = ExportNode::FromId(layer_id_);
FML_DCHECK(export_node);

export_node->UpdateScene(context, offset_, size_, hit_testable_);
}
}

Expand Down
28 changes: 13 additions & 15 deletions flow/layers/child_scene_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,24 @@
#ifndef FLUTTER_FLOW_LAYERS_CHILD_SCENE_LAYER_H_
#define FLUTTER_FLOW_LAYERS_CHILD_SCENE_LAYER_H_

#include "flutter/flow/export_node.h"
#include <third_party/skia/include/core/SkMatrix.h>
#include <third_party/skia/include/core/SkPoint.h>
#include <third_party/skia/include/core/SkSize.h>

#include "flutter/flow/layers/layer.h"
#include "flutter/flow/scene_update_context.h"

namespace flow {

// Layer that represents an embedded child.
class ChildSceneLayer : public Layer {
public:
ChildSceneLayer();
~ChildSceneLayer() override;

void set_offset(const SkPoint& offset) { offset_ = offset; }

void set_size(const SkSize& size) { size_ = size; }

void set_export_node_holder(
fml::RefPtr<ExportNodeHolder> export_node_holder) {
export_node_holder_ = std::move(export_node_holder);
}

void set_hit_testable(bool hit_testable) { hit_testable_ = hit_testable; }
ChildSceneLayer(zx_koid_t layer_id,
bool use_view_holder,
const SkPoint& offset,
const SkSize& size,
bool hit_testable);
~ChildSceneLayer() override = default;

void Preroll(PrerollContext* context, const SkMatrix& matrix) override;

Expand All @@ -34,10 +31,11 @@ class ChildSceneLayer : public Layer {
void UpdateScene(SceneUpdateContext& context) override;

private:
zx_koid_t layer_id_ = ZX_KOID_INVALID;
SkPoint offset_;
SkSize size_;
fml::RefPtr<ExportNodeHolder> export_node_holder_;
bool hit_testable_ = true;
bool use_view_holder_ = true;

FML_DISALLOW_COPY_AND_ASSIGN(ChildSceneLayer);
};
Expand Down
Loading

0 comments on commit ff1bcdc

Please sign in to comment.