fuchsia: Add a SoftwareSurfaceProducer for debug (flutter/engine#29657)

This commit is contained in:
David Worsham
2021-12-02 12:09:51 -08:00
committed by GitHub
parent 7a53b18378
commit c1e33b58a5
20 changed files with 1126 additions and 160 deletions

View File

@@ -1504,6 +1504,10 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/runner.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/runner.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/runner_tzdata_unittest.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/runner_unittest.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/software_surface.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/software_surface.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/software_surface_producer.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/software_surface_producer.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/surface.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/surface.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/surface_producer.h

View File

@@ -95,6 +95,10 @@ template("runner_sources") {
"program_metadata.h",
"runner.cc",
"runner.h",
"software_surface.cc",
"software_surface.h",
"software_surface_producer.cc",
"software_surface_producer.h",
"surface.cc",
"surface.h",
"surface_producer.h",

View File

@@ -31,8 +31,10 @@
#include "focus_delegate.h"
#include "fuchsia_intl.h"
#include "gfx_platform_view.h"
#include "software_surface_producer.h"
#include "surface.h"
#include "vsync_waiter.h"
#include "vulkan_surface_producer.h"
namespace flutter_runner {
namespace {
@@ -252,13 +254,22 @@ void Engine::Initialize(
request = parent_viewport_watcher.NewRequest(),
view_ref_pair = std::move(view_ref_pair),
max_frames_in_flight = product_config.get_max_frames_in_flight(),
vsync_offset = product_config.get_vsync_offset()]() mutable {
vsync_offset = product_config.get_vsync_offset(),
software_rendering = product_config.software_rendering()]() mutable {
if (use_flatland) {
if (software_rendering) {
surface_producer_ = std::make_shared<SoftwareSurfaceProducer>(
/*scenic_session=*/nullptr);
} else {
surface_producer_ = std::make_shared<VulkanSurfaceProducer>(
/*scenic_session=*/nullptr);
}
flatland_connection_ = std::make_shared<FlatlandConnection>(
thread_label_, std::move(flatland),
std::move(session_error_callback), [](auto) {},
max_frames_in_flight, vsync_offset);
surface_producer_.emplace(/*scenic_session=*/nullptr);
fuchsia::ui::views::ViewIdentityOnCreation view_identity = {
.view_ref = std::move(view_ref_pair.view_ref),
.view_ref_control = std::move(view_ref_pair.control_ref)};
@@ -266,18 +277,25 @@ void Engine::Initialize(
std::make_shared<FlatlandExternalViewEmbedder>(
std::move(view_creation_token), std::move(view_identity),
std::move(flatland_view_protocols), std::move(request),
*flatland_connection_.get(), surface_producer_.value(),
flatland_connection_, surface_producer_,
intercept_all_input_);
} else {
session_connection_ = std::make_shared<GfxSessionConnection>(
thread_label_, std::move(session_inspect_node),
std::move(session), std::move(session_error_callback),
[](auto) {}, max_frames_in_flight, vsync_offset);
surface_producer_.emplace(session_connection_->get());
if (software_rendering) {
surface_producer_ = std::make_shared<SoftwareSurfaceProducer>(
session_connection_->get());
} else {
surface_producer_ = std::make_shared<VulkanSurfaceProducer>(
session_connection_->get());
}
external_view_embedder_ = std::make_shared<GfxExternalViewEmbedder>(
thread_label_, std::move(view_token), std::move(view_ref_pair),
*session_connection_.get(), surface_producer_.value(),
intercept_all_input_);
session_connection_, surface_producer_, intercept_all_input_);
}
view_embedder_latch.Signal();
}));
@@ -432,7 +450,7 @@ void Engine::Initialize(
->GetTaskRunner()
.get(),
shell.GetTaskRunners().GetRasterTaskRunner().get(),
surface_producer_.value(), width, height,
surface_producer_, SkISize::Make(width, height),
flutter::PersistentCache::GetCacheForProcess()
->asset_manager(),
skp_names, completion_callback);
@@ -443,7 +461,7 @@ void Engine::Initialize(
->GetTaskRunner()
.get(),
shell.GetTaskRunners().GetRasterTaskRunner().get(),
surface_producer_.value(), 1024, 600,
surface_producer_, SkISize::Make(1024, 600),
flutter::PersistentCache::GetCacheForProcess()
->asset_manager(),
std::nullopt, std::nullopt);
@@ -658,12 +676,15 @@ Engine::~Engine() {
fml::AutoResetWaitableEvent view_embedder_latch;
thread_host_.raster_thread->GetTaskRunner()->PostTask(
fml::MakeCopyable([this, &view_embedder_latch]() mutable {
flatland_view_embedder_.reset();
external_view_embedder_.reset();
surface_producer_.reset();
flatland_connection_.reset();
session_connection_.reset();
if (flatland_view_embedder_ != nullptr) {
flatland_view_embedder_.reset();
flatland_connection_.reset();
surface_producer_.reset();
} else {
external_view_embedder_.reset();
surface_producer_.reset();
session_connection_.reset();
}
view_embedder_latch.Signal();
}));
view_embedder_latch.Wait();
@@ -835,19 +856,16 @@ void Engine::WriteProfileToTrace() const {
void Engine::WarmupSkps(
fml::BasicTaskRunner* concurrent_task_runner,
fml::BasicTaskRunner* raster_task_runner,
VulkanSurfaceProducer& surface_producer,
uint64_t width,
uint64_t height,
std::shared_ptr<SurfaceProducer> surface_producer,
SkISize size,
std::shared_ptr<flutter::AssetManager> asset_manager,
std::optional<const std::vector<std::string>> skp_names,
std::optional<std::function<void(uint32_t)>> completion_callback) {
SkISize size = SkISize::Make(width, height);
// We use a raw pointer here because we want to keep this alive until all gpu
// work is done and the callbacks skia takes for this are function pointers
// so we are unable to use a lambda that captures the smart pointer.
SurfaceProducerSurface* skp_warmup_surface =
surface_producer.ProduceOffscreenSurface(size).release();
surface_producer->ProduceOffscreenSurface(size).release();
if (!skp_warmup_surface) {
FML_LOG(ERROR) << "Failed to create offscreen warmup surface";
// Tell client that zero shaders were warmed up because warmup failed.
@@ -860,7 +878,7 @@ void Engine::WarmupSkps(
// tell concurrent task runner to deserialize all skps available from
// the asset manager
concurrent_task_runner->PostTask([raster_task_runner, skp_warmup_surface,
&surface_producer, asset_manager, skp_names,
surface_producer, asset_manager, skp_names,
completion_callback]() {
TRACE_DURATION("flutter", "DeserializeSkps");
std::vector<std::unique_ptr<fml::Mapping>> skp_mappings;
@@ -903,27 +921,13 @@ void Engine::WarmupSkps(
// Tell raster task runner to warmup have the compositor
// context warm up the newly deserialized picture
raster_task_runner->PostTask([skp_warmup_surface, picture,
&surface_producer, completion_callback, i,
surface_producer, completion_callback, i,
count = skp_mappings.size()] {
TRACE_DURATION("flutter", "WarmupSkp");
skp_warmup_surface->GetSkiaSurface()->getCanvas()->drawPicture(picture);
if (i < count - 1) {
// For all but the last skp we fire and forget
surface_producer.gr_context()->flushAndSubmit();
} else {
// For the last skp we provide a callback that frees the warmup
// surface and calls the completion callback
struct GrFlushInfo flush_info;
flush_info.fFinishedContext = skp_warmup_surface;
flush_info.fFinishedProc = [](void* skp_warmup_surface) {
delete static_cast<SurfaceProducerSurface*>(skp_warmup_surface);
};
surface_producer.gr_context()->flush(flush_info);
surface_producer.gr_context()->submit();
// We call this here instead of inside fFinishedProc above because
if (i == count - 1) {
// We call this here instead of inside fFinishedProc below because
// we want to unblock the dart animation code as soon as the raster
// thread is free to enque work, rather than waiting for the GPU work
// itself to finish.
@@ -931,6 +935,28 @@ void Engine::WarmupSkps(
completion_callback.value()(count);
}
}
if (surface_producer->gr_context()) {
if (i < count - 1) {
// For all but the last skp we fire and forget
surface_producer->gr_context()->flushAndSubmit();
} else {
// For the last skp we provide a callback that frees the warmup
// surface and calls the completion callback
struct GrFlushInfo flush_info;
flush_info.fFinishedContext = skp_warmup_surface;
flush_info.fFinishedProc = [](void* skp_warmup_surface) {
delete static_cast<SurfaceProducerSurface*>(skp_warmup_surface);
};
surface_producer->gr_context()->flush(flush_info);
surface_producer->gr_context()->submit();
}
} else {
if (i == count - 1) {
delete skp_warmup_surface;
}
}
});
i++;
}

View File

@@ -31,7 +31,7 @@
#include "gfx_external_view_embedder.h"
#include "gfx_session_connection.h"
#include "isolate_configurator.h"
#include "vulkan_surface_producer.h"
#include "surface_producer.h"
namespace flutter_runner {
@@ -104,9 +104,8 @@ class Engine final : public fuchsia::memorypressure::Watcher {
static void WarmupSkps(
fml::BasicTaskRunner* concurrent_task_runner,
fml::BasicTaskRunner* raster_task_runner,
VulkanSurfaceProducer& surface_producer,
uint64_t width,
uint64_t height,
std::shared_ptr<SurfaceProducer> surface_producer,
SkISize size,
std::shared_ptr<flutter::AssetManager> asset_manager,
std::optional<const std::vector<std::string>> skp_names,
std::optional<std::function<void(uint32_t)>> completion_callback);
@@ -157,7 +156,7 @@ class Engine final : public fuchsia::memorypressure::Watcher {
session_connection_; // Must come before surface_producer_
std::shared_ptr<FlatlandConnection>
flatland_connection_; // Must come before surface_producer_
std::optional<VulkanSurfaceProducer> surface_producer_;
std::shared_ptr<SurfaceProducer> surface_producer_;
std::shared_ptr<GfxExternalViewEmbedder> external_view_embedder_;
std::shared_ptr<FlatlandExternalViewEmbedder> flatland_view_embedder_;

View File

@@ -17,17 +17,17 @@ FlatlandExternalViewEmbedder::FlatlandExternalViewEmbedder(
fuchsia::ui::composition::ViewBoundProtocols view_protocols,
fidl::InterfaceRequest<fuchsia::ui::composition::ParentViewportWatcher>
parent_viewport_watcher_request,
FlatlandConnection& flatland,
SurfaceProducer& surface_producer,
std::shared_ptr<FlatlandConnection> flatland,
std::shared_ptr<SurfaceProducer> surface_producer,
bool intercept_all_input)
: flatland_(flatland), surface_producer_(surface_producer) {
flatland_.flatland()->CreateView2(
flatland_->flatland()->CreateView2(
std::move(view_creation_token), std::move(view_identity),
std::move(view_protocols), std::move(parent_viewport_watcher_request));
root_transform_id_ = flatland_.NextTransformId();
flatland_.flatland()->CreateTransform(root_transform_id_);
flatland_.flatland()->SetRootTransform(root_transform_id_);
root_transform_id_ = flatland_->NextTransformId();
flatland_->flatland()->CreateTransform(root_transform_id_);
flatland_->flatland()->SetRootTransform(root_transform_id_);
}
FlatlandExternalViewEmbedder::~FlatlandExternalViewEmbedder() = default;
@@ -122,7 +122,7 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
}
auto surface =
surface_producer_.ProduceSurface(layer.second.surface_size);
surface_producer_->ProduceSurface(layer.second.surface_size);
if (!surface) {
const std::string layer_id_str =
layer.first.has_value() ? std::to_string(layer.first.value())
@@ -137,24 +137,24 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
// If we receive an unitialized surface, we need to first create flatland
// resource.
if (surface->GetImageId() == 0) {
auto image_id = flatland_.NextContentId().value;
auto image_id = flatland_->NextContentId().value;
const auto& size = surface->GetSize();
fuchsia::ui::composition::ImageProperties image_properties;
image_properties.set_size({static_cast<uint32_t>(size.width()),
static_cast<uint32_t>(size.height())});
flatland_.flatland()->CreateImage(
flatland_->flatland()->CreateImage(
{image_id}, surface->GetBufferCollectionImportToken(), 0,
std::move(image_properties));
surface->SetImageId(image_id);
surface->SetReleaseImageCallback([flatland = &flatland_, image_id]() {
surface->SetReleaseImageCallback([flatland = flatland_, image_id]() {
flatland->flatland()->ReleaseImage({image_id});
});
}
// Enqueue fences for the next present.
flatland_.EnqueueAcquireFence(surface->GetAcquireFence());
flatland_.EnqueueReleaseFence(surface->GetReleaseFence());
flatland_->EnqueueAcquireFence(surface->GetAcquireFence());
flatland_->EnqueueReleaseFence(surface->GetReleaseFence());
frame_surface_indices.emplace(
std::make_pair(layer.first, frame_surfaces.size()));
@@ -193,7 +193,7 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
// Set transform for the viewport.
// TODO(fxbug.dev/64201): Handle scaling.
if (view_mutators.transform != viewport.mutators.transform) {
flatland_.flatland()->SetTranslation(
flatland_->flatland()->SetTranslation(
viewport.transform_id,
{static_cast<int32_t>(view_mutators.transform.getTranslateX()),
static_cast<int32_t>(view_mutators.transform.getTranslateY())});
@@ -210,14 +210,14 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
properties.set_logical_size(
{static_cast<uint32_t>(view_size.fWidth),
static_cast<uint32_t>(view_size.fHeight)});
flatland_.flatland()->SetViewportProperties(viewport.viewport_id,
std::move(properties));
flatland_->flatland()->SetViewportProperties(viewport.viewport_id,
std::move(properties));
viewport.size = view_size;
}
// Attach the FlatlandView to the main scene graph.
flatland_.flatland()->AddChild(root_transform_id_,
viewport.transform_id);
flatland_->flatland()->AddChild(root_transform_id_,
viewport.transform_id);
child_transforms_.emplace_back(viewport.transform_id);
}
@@ -244,22 +244,22 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
// Create a new layer if needed for the surface.
FML_CHECK(flatland_layer_index <= flatland_layers_.size());
if (flatland_layer_index == flatland_layers_.size()) {
FlatlandLayer new_layer{.transform_id = flatland_.NextTransformId()};
flatland_.flatland()->CreateTransform(new_layer.transform_id);
FlatlandLayer new_layer{.transform_id = flatland_->NextTransformId()};
flatland_->flatland()->CreateTransform(new_layer.transform_id);
flatland_layers_.emplace_back(std::move(new_layer));
}
// Update the image content and set size.
flatland_.flatland()->SetContent(
flatland_->flatland()->SetContent(
flatland_layers_[flatland_layer_index].transform_id,
{surface_for_layer->GetImageId()});
flatland_.flatland()->SetImageDestinationSize(
flatland_->flatland()->SetImageDestinationSize(
{surface_for_layer->GetImageId()},
{static_cast<uint32_t>(surface_for_layer->GetSize().width()),
static_cast<uint32_t>(surface_for_layer->GetSize().height())});
// Attach the FlatlandLayer to the main scene graph.
flatland_.flatland()->AddChild(
flatland_->flatland()->AddChild(
root_transform_id_,
flatland_layers_[flatland_layer_index].transform_id);
child_transforms_.emplace_back(
@@ -276,7 +276,7 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
{
TRACE_EVENT0("flutter", "SessionPresent");
flatland_.Present();
flatland_->Present();
}
// Render the recorded SkPictures into the surfaces.
@@ -315,7 +315,7 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
{
TRACE_EVENT0("flutter", "PresentSurfaces");
surface_producer_.SubmitSurfaces(std::move(frame_surfaces));
surface_producer_->SubmitSurfaces(std::move(frame_surfaces));
}
// Submit the underlying render-backend-specific frame for processing.
@@ -328,19 +328,20 @@ void FlatlandExternalViewEmbedder::CreateView(
FlatlandViewCreatedCallback on_view_bound) {
FML_CHECK(flatland_views_.find(view_id) == flatland_views_.end());
FlatlandView new_view = {.transform_id = flatland_.NextTransformId(),
.viewport_id = flatland_.NextContentId()};
flatland_.flatland()->CreateTransform(new_view.transform_id);
FlatlandView new_view = {.transform_id = flatland_->NextTransformId(),
.viewport_id = flatland_->NextContentId()};
flatland_->flatland()->CreateTransform(new_view.transform_id);
fuchsia::ui::composition::ViewportProperties properties;
// TODO(fxbug.dev/64201): Investigate if it is possible to avoid using a
// default size by finding the size before creation.
properties.set_logical_size(
{kFlatlandDefaultViewportSize, kFlatlandDefaultViewportSize});
fuchsia::ui::composition::ChildViewWatcherPtr child_view_watcher;
flatland_.flatland()->CreateViewport(
flatland_->flatland()->CreateViewport(
new_view.viewport_id, {zx::channel((zx_handle_t)view_id)},
std::move(properties), child_view_watcher.NewRequest());
flatland_.flatland()->SetContent(new_view.transform_id, new_view.viewport_id);
flatland_->flatland()->SetContent(new_view.transform_id,
new_view.viewport_id);
on_view_created();
on_view_bound(new_view.viewport_id, std::move(child_view_watcher));
@@ -355,17 +356,17 @@ void FlatlandExternalViewEmbedder::DestroyView(
auto viewport_id = flatland_view->second.viewport_id;
auto transform_id = flatland_view->second.transform_id;
flatland_.flatland()->ReleaseViewport(viewport_id, [](auto) {});
flatland_->flatland()->ReleaseViewport(viewport_id, [](auto) {});
auto itr =
std::find_if(child_transforms_.begin(), child_transforms_.end(),
[transform_id](fuchsia::ui::composition::TransformId id) {
return id.value == transform_id.value;
});
if (itr != child_transforms_.end()) {
flatland_.flatland()->RemoveChild(root_transform_id_, transform_id);
flatland_->flatland()->RemoveChild(root_transform_id_, transform_id);
child_transforms_.erase(itr);
}
flatland_.flatland()->ReleaseTransform(transform_id);
flatland_->flatland()->ReleaseTransform(transform_id);
flatland_views_.erase(flatland_view);
on_view_unbound(viewport_id);
@@ -389,13 +390,13 @@ void FlatlandExternalViewEmbedder::Reset() {
// Clear all children from root.
for (const auto& transform : child_transforms_) {
flatland_.flatland()->RemoveChild(root_transform_id_, transform);
flatland_->flatland()->RemoveChild(root_transform_id_, transform);
}
child_transforms_.clear();
// Clear images on all layers so they aren't cached unnecessarily.
for (const auto& layer : flatland_layers_) {
flatland_.flatland()->SetContent(layer.transform_id, {0});
flatland_->flatland()->SetContent(layer.transform_id, {0});
}
}

View File

@@ -52,8 +52,8 @@ class FlatlandExternalViewEmbedder final
fuchsia::ui::composition::ViewBoundProtocols endpoints,
fidl::InterfaceRequest<fuchsia::ui::composition::ParentViewportWatcher>
parent_viewport_watcher_request,
FlatlandConnection& flatland,
SurfaceProducer& surface_producer,
std::shared_ptr<FlatlandConnection> flatland,
std::shared_ptr<SurfaceProducer> surface_producer,
bool intercept_all_input = false);
~FlatlandExternalViewEmbedder();
@@ -168,8 +168,9 @@ class FlatlandExternalViewEmbedder final
fuchsia::ui::composition::TransformId transform_id;
};
FlatlandConnection& flatland_;
SurfaceProducer& surface_producer_;
std::shared_ptr<FlatlandConnection> flatland_;
std::shared_ptr<SurfaceProducer> surface_producer_;
fuchsia::ui::composition::ParentViewportWatcherPtr parent_viewport_watcher_;
fuchsia::ui::composition::TransformId root_transform_id_;

View File

@@ -25,28 +25,39 @@ FlutterRunnerProductConfiguration::FlutterRunnerProductConfiguration(
// Parse out all values we're expecting.
if (document.HasMember("vsync_offset_in_us")) {
auto& val = document["vsync_offset_in_us"];
if (val.IsInt())
if (val.IsInt()) {
vsync_offset_ = fml::TimeDelta::FromMicroseconds(val.GetInt());
}
}
if (document.HasMember("max_frames_in_flight")) {
auto& val = document["max_frames_in_flight"];
if (val.IsInt())
if (val.IsInt()) {
max_frames_in_flight_ = val.GetInt();
}
}
if (document.HasMember("intercept_all_input")) {
auto& val = document["intercept_all_input"];
if (val.IsBool())
if (val.IsBool()) {
intercept_all_input_ = val.GetBool();
}
}
if (document.HasMember("software_rendering")) {
auto& val = document["software_rendering"];
if (val.IsBool()) {
software_rendering_ = val.GetBool();
}
}
if (document.HasMember("enable_shader_warmup")) {
auto& val = document["enable_shader_warmup"];
if (val.IsBool())
if (val.IsBool()) {
enable_shader_warmup_ = val.GetBool();
}
}
if (document.HasMember("enable_shader_warmup_dart_hooks")) {
auto& val = document["enable_shader_warmup_dart_hooks"];
if (val.IsBool())
if (val.IsBool()) {
enable_shader_warmup_dart_hooks_ = val.GetBool();
}
}
}

View File

@@ -5,6 +5,8 @@
#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_RUNNER_PRODUCT_CONFIGURATION_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_RUNNER_PRODUCT_CONFIGURATION_H_
#include <string>
#include "flutter/fml/time/time_delta.h"
namespace flutter_runner {
@@ -12,11 +14,12 @@ namespace flutter_runner {
class FlutterRunnerProductConfiguration {
public:
FlutterRunnerProductConfiguration() {}
FlutterRunnerProductConfiguration(std::string path);
explicit FlutterRunnerProductConfiguration(std::string json_string);
fml::TimeDelta get_vsync_offset() { return vsync_offset_; }
uint64_t get_max_frames_in_flight() { return max_frames_in_flight_; }
bool get_intercept_all_input() { return intercept_all_input_; }
bool software_rendering() { return software_rendering_; }
bool enable_shader_warmup() { return enable_shader_warmup_; }
bool enable_shader_warmup_dart_hooks() {
return enable_shader_warmup_dart_hooks_;
@@ -26,6 +29,7 @@ class FlutterRunnerProductConfiguration {
fml::TimeDelta vsync_offset_ = fml::TimeDelta::Zero();
uint64_t max_frames_in_flight_ = 3;
bool intercept_all_input_ = false;
bool software_rendering_ = false;
bool enable_shader_warmup_ = false;
bool enable_shader_warmup_dart_hooks_ = true;
};

View File

@@ -103,18 +103,18 @@ GfxExternalViewEmbedder::GfxExternalViewEmbedder(
std::string debug_label,
fuchsia::ui::views::ViewToken view_token,
scenic::ViewRefPair view_ref_pair,
GfxSessionConnection& session,
SurfaceProducer& surface_producer,
std::shared_ptr<GfxSessionConnection> session,
std::shared_ptr<SurfaceProducer> surface_producer,
bool intercept_all_input)
: session_(session),
surface_producer_(surface_producer),
root_view_(session_.get(),
root_view_(session_->get(),
std::move(view_token),
std::move(view_ref_pair.control_ref),
std::move(view_ref_pair.view_ref),
debug_label),
metrics_node_(session_.get()),
layer_tree_node_(session_.get()) {
metrics_node_(session_->get()),
layer_tree_node_(session_->get()) {
layer_tree_node_.SetLabel("Flutter::LayerTree");
metrics_node_.SetLabel("Flutter::MetricsWatcher");
metrics_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
@@ -125,7 +125,7 @@ GfxExternalViewEmbedder::GfxExternalViewEmbedder(
// will capture all input, and any unwanted input will be reinjected into
// embedded views.
if (intercept_all_input) {
input_interceptor_node_.emplace(session_.get());
input_interceptor_node_.emplace(session_->get());
input_interceptor_node_->SetLabel("Flutter::InputInterceptor");
input_interceptor_node_->SetHitTestBehavior(
fuchsia::ui::gfx::HitTestBehavior::kDefault);
@@ -134,7 +134,7 @@ GfxExternalViewEmbedder::GfxExternalViewEmbedder(
metrics_node_.AddChild(input_interceptor_node_.value());
}
session_.Present();
session_->Present();
}
GfxExternalViewEmbedder::~GfxExternalViewEmbedder() = default;
@@ -215,7 +215,7 @@ void GfxExternalViewEmbedder::BeginFrame(
if (found_rect == scenic_interceptor_rects_.end()) {
auto [emplaced_rect, success] =
scenic_interceptor_rects_.emplace(std::make_pair(
rect_hash, scenic::Rectangle(session_.get(), frame_size_.width(),
rect_hash, scenic::Rectangle(session_->get(), frame_size_.width(),
frame_size_.height())));
FML_CHECK(success);
@@ -253,7 +253,7 @@ void GfxExternalViewEmbedder::SubmitFrame(
}
auto surface =
surface_producer_.ProduceSurface(layer.second.surface_size);
surface_producer_->ProduceSurface(layer.second.surface_size);
if (!surface) {
const std::string layer_id_str =
layer.first.has_value() ? std::to_string(layer.first.value())
@@ -313,7 +313,7 @@ void GfxExternalViewEmbedder::SubmitFrame(
// Expand the clip_nodes array to fit any new nodes.
while (view_holder.clip_nodes.size() < view_mutators.clips.size()) {
view_holder.clip_nodes.emplace_back(
scenic::EntityNode(session_.get()));
scenic::EntityNode(session_->get()));
}
FML_CHECK(view_holder.clip_nodes.size() >=
view_mutators.clips.size());
@@ -437,8 +437,8 @@ void GfxExternalViewEmbedder::SubmitFrame(
FML_CHECK(scenic_layer_index <= scenic_layers_.size());
if (scenic_layer_index == scenic_layers_.size()) {
ScenicLayer new_layer{
.shape_node = scenic::ShapeNode(session_.get()),
.material = scenic::Material(session_.get()),
.shape_node = scenic::ShapeNode(session_->get()),
.material = scenic::Material(session_->get()),
};
new_layer.shape_node.SetMaterial(new_layer.material);
scenic_layers_.emplace_back(std::move(new_layer));
@@ -469,7 +469,7 @@ void GfxExternalViewEmbedder::SubmitFrame(
FML_CHECK(rect_index <= found_rects->second.size());
if (rect_index == found_rects->second.size()) {
found_rects->second.emplace_back(scenic::Rectangle(
session_.get(), layer->second.surface_size.width(),
session_->get(), layer->second.surface_size.width(),
layer->second.surface_size.height()));
}
@@ -524,7 +524,7 @@ void GfxExternalViewEmbedder::SubmitFrame(
{
TRACE_EVENT0("flutter", "SessionPresent");
session_.Present();
session_->Present();
}
// Render the recorded SkPictures into the surfaces.
@@ -563,7 +563,7 @@ void GfxExternalViewEmbedder::SubmitFrame(
{
TRACE_EVENT0("flutter", "PresentSurfaces");
surface_producer_.SubmitSurfaces(std::move(frame_surfaces));
surface_producer_->SubmitSurfaces(std::move(frame_surfaces));
}
// Submit the underlying render-backend-specific frame for processing.
@@ -571,9 +571,9 @@ void GfxExternalViewEmbedder::SubmitFrame(
}
void GfxExternalViewEmbedder::EnableWireframe(bool enable) {
session_.get()->Enqueue(
session_->get()->Enqueue(
scenic::NewSetEnableDebugViewBoundsCmd(root_view_.id(), enable));
session_.Present();
session_->Present();
}
void GfxExternalViewEmbedder::CreateView(int64_t view_id,
@@ -582,10 +582,10 @@ void GfxExternalViewEmbedder::CreateView(int64_t view_id,
FML_CHECK(scenic_views_.find(view_id) == scenic_views_.end());
ScenicView new_view = {
.opacity_node = scenic::OpacityNodeHACK(session_.get()),
.transform_node = scenic::EntityNode(session_.get()),
.opacity_node = scenic::OpacityNodeHACK(session_->get()),
.transform_node = scenic::EntityNode(session_->get()),
.view_holder = scenic::ViewHolder(
session_.get(),
session_->get(),
scenic::ToViewHolderToken(zx::eventpair((zx_handle_t)view_id)),
"Flutter::PlatformView"),
};

View File

@@ -75,8 +75,8 @@ class GfxExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
GfxExternalViewEmbedder(std::string debug_label,
fuchsia::ui::views::ViewToken view_token,
scenic::ViewRefPair view_ref_pair,
GfxSessionConnection& session,
SurfaceProducer& surface_producer,
std::shared_ptr<GfxSessionConnection> session,
std::shared_ptr<SurfaceProducer> surface_producer,
bool intercept_all_input = false);
~GfxExternalViewEmbedder();
@@ -177,8 +177,8 @@ class GfxExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
scenic::Material material;
};
GfxSessionConnection& session_;
SurfaceProducer& surface_producer_;
std::shared_ptr<GfxSessionConnection> session_;
std::shared_ptr<SurfaceProducer> surface_producer_;
scenic::View root_view_;
scenic::EntityNode metrics_node_;

View File

@@ -0,0 +1,428 @@
// Copyright 2013 The Flutter 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 "software_surface.h"
#include <lib/async/default.h>
#include <lib/ui/scenic/cpp/commands.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <cmath>
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
#include "fuchsia/sysmem/cpp/fidl.h"
#include "include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "../runtime/dart/utils/inlines.h"
#include "zx/cpp/fidl.h"
namespace flutter_runner {
namespace {
constexpr SkColorType kSkiaColorType = kRGBA_8888_SkColorType;
uint32_t BytesPerRow(const fuchsia::sysmem::SingleBufferSettings& settings,
uint32_t bytes_per_pixel,
uint32_t image_width) {
const uint32_t bytes_per_row_divisor =
settings.image_format_constraints.bytes_per_row_divisor;
const uint32_t min_bytes_per_row =
settings.image_format_constraints.min_bytes_per_row;
const uint32_t unrounded_bytes_per_row =
std::max(image_width * bytes_per_pixel, min_bytes_per_row);
const uint32_t roundup_bytes =
unrounded_bytes_per_row % bytes_per_row_divisor;
return unrounded_bytes_per_row + roundup_bytes;
}
} // namespace
uint32_t SoftwareSurface::sNextBufferId = 1; // 0 is invalid; start at 1.
SoftwareSurface::SoftwareSurface(
fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
fuchsia::ui::composition::AllocatorPtr& flatland_allocator,
scenic::Session* session,
const SkISize& size)
: session_(session), wait_for_surface_read_finished_(this) {
FML_CHECK((session_ || flatland_allocator.is_bound()) &&
!(session_ && flatland_allocator.is_bound()));
if (!SetupSkiaSurface(sysmem_allocator, flatland_allocator, size)) {
FML_LOG(ERROR) << "Could not create render surface.";
return;
}
if (!CreateFences()) {
FML_LOG(ERROR) << "Could not create signal fences.";
return;
}
if (session) {
if (image_id_ == 0) {
image_id_ = session->AllocResourceId();
}
session->Enqueue(scenic::NewCreateImage2Cmd(
image_id_, sk_surface_->width(), sk_surface_->height(), buffer_id_, 0));
}
wait_for_surface_read_finished_.set_object(release_event_.get());
wait_for_surface_read_finished_.set_trigger(ZX_EVENT_SIGNALED);
Reset();
valid_ = true;
}
SoftwareSurface::~SoftwareSurface() {
if (session_) {
if (image_id_) {
session_->Enqueue(scenic::NewReleaseResourceCmd(image_id_));
}
if (buffer_id_) {
session_->DeregisterBufferCollection(buffer_id_);
}
} else {
release_image_callback_();
}
wait_for_surface_read_finished_.Cancel();
wait_for_surface_read_finished_.set_object(ZX_HANDLE_INVALID);
}
bool SoftwareSurface::IsValid() const {
return valid_;
}
SkISize SoftwareSurface::GetSize() const {
if (!valid_) {
return SkISize::Make(0, 0);
}
return SkISize::Make(sk_surface_->width(), sk_surface_->height());
}
bool SoftwareSurface::CreateFences() {
if (zx::event::create(0, &acquire_event_) != ZX_OK) {
FML_LOG(ERROR) << "Failed to create acquire event.";
return false;
}
if (zx::event::create(0, &release_event_) != ZX_OK) {
FML_LOG(ERROR) << "Failed to create release event.";
return false;
}
return true;
}
bool SoftwareSurface::SetupSkiaSurface(
fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
fuchsia::ui::composition::AllocatorPtr& flatland_allocator,
const SkISize& size) {
if (size.isEmpty()) {
FML_LOG(ERROR) << "Failed to allocate surface, size is empty.";
return false;
}
// Allocate a "local" sysmem token to represent flutter's handle to the
// sysmem buffer.
fuchsia::sysmem::BufferCollectionTokenSyncPtr local_token;
zx_status_t allocate_status =
sysmem_allocator->AllocateSharedCollection(local_token.NewRequest());
if (allocate_status != ZX_OK) {
FML_LOG(ERROR) << "Failed to allocate collection: "
<< zx_status_get_string(allocate_status);
return false;
}
// Create a single Duplicate of the token and Sync it; the single duplicate
// token represents scenic's handle to the sysmem buffer.
std::vector<fuchsia::sysmem::BufferCollectionTokenHandle> duplicate_tokens;
zx_status_t duplicate_status = local_token->DuplicateSync(
std::vector<zx::rights>{zx::rights::SAME_RIGHTS}, &duplicate_tokens);
if (duplicate_status != ZX_OK) {
FML_LOG(ERROR) << "Failed to duplicate collection token: "
<< zx_status_get_string(duplicate_status);
return false;
}
if (duplicate_tokens.size() != 1u) {
FML_LOG(ERROR) << "Failed to duplicate collection token: Incorrect number "
"of tokens returned.";
return false;
}
auto scenic_token = std::move(duplicate_tokens[0]);
// Register the sysmem token with flatland (or scenic's legacy gfx interface).
//
// This binds the sysmem token to a composition token, which is used later
// to associate the rendering surface with a specific flatland Image.
//
// Under gfx, scenic uses an integral `buffer_id` instead of the composition
// token.
if (session_) {
buffer_id_ = sNextBufferId++;
session_->RegisterBufferCollection(buffer_id_, std::move(scenic_token));
} else {
fuchsia::ui::composition::BufferCollectionExportToken export_token;
zx_status_t token_create_status =
zx::eventpair::create(0, &export_token.value, &import_token_.value);
if (token_create_status != ZX_OK) {
FML_LOG(ERROR) << "Failed to create flatland export token: "
<< zx_status_get_string(token_create_status);
return false;
}
fuchsia::ui::composition::RegisterBufferCollectionArgs args;
args.set_export_token(std::move(export_token));
args.set_buffer_collection_token(std::move(scenic_token));
args.set_usage(
fuchsia::ui::composition::RegisterBufferCollectionUsage::DEFAULT);
flatland_allocator->RegisterBufferCollection(
std::move(args),
[](fuchsia::ui::composition::Allocator_RegisterBufferCollection_Result
result) {
if (result.is_err()) {
FML_LOG(ERROR)
<< "RegisterBufferCollection call to Scenic Allocator failed.";
}
});
}
// Acquire flutter's local handle to the sysmem buffer.
fuchsia::sysmem::BufferCollectionSyncPtr buffer_collection;
zx_status_t bind_status = sysmem_allocator->BindSharedCollection(
std::move(local_token), buffer_collection.NewRequest());
if (bind_status != ZX_OK) {
FML_LOG(ERROR) << "Failed to bind collection token: "
<< zx_status_get_string(bind_status);
return false;
}
// Set flutter's constraints on the sysmem buffer. Software rendering only
// requires CPU access to the surface and a basic R8G8B8A8 pixel format.
fuchsia::sysmem::BufferCollectionConstraints constraints;
constraints.min_buffer_count = 1;
constraints.usage.cpu =
fuchsia::sysmem::cpuUsageWrite | fuchsia::sysmem::cpuUsageWriteOften;
constraints.has_buffer_memory_constraints = true;
constraints.buffer_memory_constraints.physically_contiguous_required = false;
constraints.buffer_memory_constraints.secure_required = false;
constraints.buffer_memory_constraints.ram_domain_supported = true;
constraints.buffer_memory_constraints.cpu_domain_supported = true;
constraints.buffer_memory_constraints.inaccessible_domain_supported = false;
constraints.image_format_constraints_count = 1;
fuchsia::sysmem::ImageFormatConstraints& image_constraints =
constraints.image_format_constraints[0];
image_constraints = fuchsia::sysmem::ImageFormatConstraints();
image_constraints.min_coded_width = static_cast<uint32_t>(size.fWidth);
image_constraints.min_coded_height = static_cast<uint32_t>(size.fHeight);
image_constraints.min_bytes_per_row = static_cast<uint32_t>(size.fWidth) * 4;
image_constraints.pixel_format.type =
fuchsia::sysmem::PixelFormatType::R8G8B8A8;
image_constraints.color_spaces_count = 1;
image_constraints.color_space[0].type = fuchsia::sysmem::ColorSpaceType::SRGB;
image_constraints.pixel_format.has_format_modifier = true;
image_constraints.pixel_format.format_modifier.value =
fuchsia::sysmem::FORMAT_MODIFIER_LINEAR;
zx_status_t set_constraints_status =
buffer_collection->SetConstraints(true, constraints);
if (set_constraints_status != ZX_OK) {
FML_LOG(ERROR) << "Failed to set constraints: "
<< zx_status_get_string(set_constraints_status);
return false;
}
// Wait for sysmem to allocate, now that constraints are set.
fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info;
zx_status_t allocation_status = ZX_OK;
zx_status_t wait_for_allocated_status =
buffer_collection->WaitForBuffersAllocated(&allocation_status,
&buffer_collection_info);
if (allocation_status != ZX_OK) {
FML_LOG(ERROR) << "Failed to allocate: "
<< zx_status_get_string(allocation_status);
return false;
}
if (wait_for_allocated_status != ZX_OK) {
FML_LOG(ERROR) << "Failed to wait for allocate: "
<< zx_status_get_string(wait_for_allocated_status);
return false;
}
// Cache the allocated surface VMO and metadata.
FML_CHECK(buffer_collection_info.settings.buffer_settings.size_bytes != 0);
FML_CHECK(buffer_collection_info.buffers[0].vmo != ZX_HANDLE_INVALID);
surface_vmo_ = std::move(buffer_collection_info.buffers[0].vmo);
surface_size_bytes_ =
buffer_collection_info.settings.buffer_settings.size_bytes;
if (buffer_collection_info.settings.buffer_settings.coherency_domain ==
fuchsia::sysmem::CoherencyDomain::RAM) {
// RAM coherency domain requires a cache clean when writes are finished.
needs_cache_clean_ = true;
}
// Map the allocated buffer to the CPU.
uint8_t* vmo_base = nullptr;
zx_status_t buffer_map_status = zx::vmar::root_self()->map(
ZX_VM_PERM_WRITE | ZX_VM_PERM_READ, 0, surface_vmo_, 0,
surface_size_bytes_, reinterpret_cast<uintptr_t*>(&vmo_base));
if (buffer_map_status != ZX_OK) {
FML_LOG(ERROR) << "Failed to map buffer memory: "
<< zx_status_get_string(buffer_map_status);
return false;
}
// Now that the buffer is CPU-readable, it's safe to discard flutter's
// connection to sysmem.
zx_status_t close_status = buffer_collection->Close();
if (close_status != ZX_OK) {
FML_LOG(ERROR) << "Failed to close buffer: "
<< zx_status_get_string(close_status);
return false;
}
// Wrap the buffer in a software-rendered Skia surface.
const uint64_t vmo_offset =
buffer_collection_info.buffers[0].vmo_usable_start;
const size_t vmo_stride =
BytesPerRow(buffer_collection_info.settings, 4u, size.width());
SkSurfaceProps sk_surface_props(0, kUnknown_SkPixelGeometry);
sk_surface_ = SkSurface::MakeRasterDirect(
SkImageInfo::Make(size, kSkiaColorType, kPremul_SkAlphaType,
SkColorSpace::MakeSRGB()),
vmo_base + vmo_offset, vmo_stride, &sk_surface_props);
if (!sk_surface_ || sk_surface_->getCanvas() == nullptr) {
FML_LOG(ERROR) << "SkSurface::MakeRasterDirect failed.";
return false;
}
return true;
}
void SoftwareSurface::SetImageId(uint32_t image_id) {
FML_CHECK(image_id_ == 0);
FML_CHECK(!session_);
image_id_ = image_id;
}
uint32_t SoftwareSurface::GetImageId() {
return image_id_;
}
sk_sp<SkSurface> SoftwareSurface::GetSkiaSurface() const {
return valid_ ? sk_surface_ : nullptr;
}
fuchsia::ui::composition::BufferCollectionImportToken
SoftwareSurface::GetBufferCollectionImportToken() {
FML_CHECK(!session_);
fuchsia::ui::composition::BufferCollectionImportToken import_dup;
import_token_.value.duplicate(ZX_RIGHT_SAME_RIGHTS, &import_dup.value);
return import_dup;
}
zx::event SoftwareSurface::GetAcquireFence() {
FML_CHECK(!session_);
zx::event fence;
acquire_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence);
return fence;
}
zx::event SoftwareSurface::GetReleaseFence() {
FML_CHECK(!session_);
zx::event fence;
release_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence);
return fence;
}
void SoftwareSurface::SetReleaseImageCallback(
ReleaseImageCallback release_image_callback) {
FML_CHECK(!session_);
release_image_callback_ = release_image_callback;
}
size_t SoftwareSurface::AdvanceAndGetAge() {
return ++age_;
}
bool SoftwareSurface::FlushSessionAcquireAndReleaseEvents() {
if (session_) {
zx::event acquire, release;
if (acquire_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &acquire) != ZX_OK ||
release_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &release) != ZX_OK) {
return false;
}
session_->EnqueueAcquireFence(std::move(acquire));
session_->EnqueueReleaseFence(std::move(release));
}
age_ = 0;
return true;
}
void SoftwareSurface::SignalWritesFinished(
const std::function<void(void)>& on_surface_read_finished) {
FML_CHECK(on_surface_read_finished);
if (!valid_) {
on_surface_read_finished();
return;
}
dart_utils::Check(surface_read_finished_callback_ == nullptr,
"Attempted to signal a write on the surface when the "
"previous write has not yet been acknowledged by the "
"compositor.");
surface_read_finished_callback_ = on_surface_read_finished;
// Sysmem *may* require the cache to be cleared after writes to the surface
// are complete.
if (needs_cache_clean_) {
surface_vmo_.op_range(ZX_VMO_OP_CACHE_CLEAN, 0, surface_size_bytes_,
/*buffer*/ nullptr,
/*buffer_size*/ 0);
}
// Inform scenic that flutter is finished writing to the surface.
zx_status_t signal_status = acquire_event_.signal(0u, ZX_EVENT_SIGNALED);
if (signal_status != ZX_OK) {
FML_LOG(ERROR) << "Failed to signal acquire event; "
<< zx_status_get_string(signal_status);
}
}
void SoftwareSurface::Reset() {
if (acquire_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK ||
release_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK) {
valid_ = false;
FML_LOG(ERROR) << "Could not reset fences. The surface is no longer valid.";
}
wait_for_surface_read_finished_.Begin(async_get_default_dispatcher());
// It is safe for the caller to collect the surface in the callback.
auto callback = surface_read_finished_callback_;
surface_read_finished_callback_ = nullptr;
if (callback) {
callback();
}
}
void SoftwareSurface::OnSurfaceReadFinished(async_dispatcher_t* dispatcher,
async::WaitBase* wait,
zx_status_t status,
const zx_packet_signal_t* signal) {
if (status != ZX_OK) {
return;
}
FML_DCHECK(signal->observed & ZX_EVENT_SIGNALED);
Reset();
}
} // namespace flutter_runner

View File

@@ -0,0 +1,127 @@
// Copyright 2013 The Flutter 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 <fuchsia/sysmem/cpp/fidl.h>
#include <fuchsia/ui/composition/cpp/fidl.h>
#include <lib/async/cpp/wait.h>
#include <lib/ui/scenic/cpp/id.h>
#include <lib/ui/scenic/cpp/resources.h>
#include <lib/zx/event.h>
#include <lib/zx/vmo.h>
#include <array>
#include <cstdint>
#include <memory>
#include "flutter/fml/macros.h"
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "surface_producer.h"
namespace flutter_runner {
class SoftwareSurface final : public SurfaceProducerSurface {
public:
SoftwareSurface(fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
fuchsia::ui::composition::AllocatorPtr& flatland_allocator,
scenic::Session* session,
const SkISize& size);
~SoftwareSurface() override;
size_t GetAllocationSize() const { return surface_size_bytes_; }
// |SurfaceProducerSurface|
size_t AdvanceAndGetAge() override;
// |SurfaceProducerSurface|
bool FlushSessionAcquireAndReleaseEvents() override;
// |SurfaceProducerSurface|
bool IsValid() const override;
// |SurfaceProducerSurface|
SkISize GetSize() const override;
// |SurfaceProducerSurface|
void SignalWritesFinished(
const std::function<void(void)>& on_surface_read_finished) override;
// |SurfaceProducerSurface|
void SetImageId(uint32_t image_id) override;
// |SurfaceProducerSurface|
uint32_t GetImageId() override;
// |SurfaceProducerSurface|
sk_sp<SkSurface> GetSkiaSurface() const override;
// |SurfaceProducerSurface|
fuchsia::ui::composition::BufferCollectionImportToken
GetBufferCollectionImportToken() override;
// |SurfaceProducerSurface|
zx::event GetAcquireFence() override;
// |SurfaceProducerSurface|
zx::event GetReleaseFence() override;
// |SurfaceProducerSurface|
void SetReleaseImageCallback(
ReleaseImageCallback release_image_callback) override;
private:
void OnSurfaceReadFinished(async_dispatcher_t* dispatcher,
async::WaitBase* wait,
zx_status_t status,
const zx_packet_signal_t* signal);
bool SetupSkiaSurface(
fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
fuchsia::ui::composition::AllocatorPtr& flatland_allocator,
const SkISize& size);
bool CreateFences();
void Reset();
static uint32_t sNextBufferId; // For legacy gfx; counter for `buffer_id_`.
scenic::Session* session_; // Legacy gfx API endpoint.
scenic::ResourceId image_id_{0}; // Legacy gfx image ID.
sk_sp<SkSurface> sk_surface_;
// This is associated with `release_event_` and allows detection of when
// scenic has finished reading from the surface (and thus it is safe to re-use
// for writing).
async::WaitMethod<SoftwareSurface, &SoftwareSurface::OnSurfaceReadFinished>
wait_for_surface_read_finished_;
// Called when scenic has finished reading from the surface, to allow
// `SoftwareSurfaceProducer` to re-use the surface.
std::function<void()> surface_read_finished_callback_;
// Called when the surface is destroyed, to allow
// `FlatlandExternalViewEmbedder` to release the associated Flatland image.
ReleaseImageCallback release_image_callback_;
// Allows Flatland to associate this surface with a Flatland Image.
fuchsia::ui::composition::BufferCollectionImportToken import_token_;
uint32_t buffer_id_{0}; // Legacy gfx version of the import_token_.
zx::event acquire_event_; // Signals to scenic that writing is finished.
zx::event release_event_; // Signalled by scenic that reading is finished.
zx::vmo surface_vmo_; // VMO that is backing the surface memory.
uint32_t surface_size_bytes_; // Size of the surface memory, in bytes.
size_t age_{0}; // Number of frames since surface was last written to.
bool needs_cache_clean_{false};
bool valid_{false};
FML_DISALLOW_COPY_AND_ASSIGN(SoftwareSurface);
};
} // namespace flutter_runner

View File

@@ -0,0 +1,245 @@
// Copyright 2013 The Flutter 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 "software_surface_producer.h"
#include <lib/fdio/directory.h>
#include <lib/zx/process.h>
#include <algorithm> // Foor std::remove_if
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
namespace flutter_runner {
namespace {
std::string GetCurrentProcessName() {
char name[ZX_MAX_NAME_LEN];
zx_status_t status =
zx::process::self()->get_property(ZX_PROP_NAME, name, sizeof(name));
if (status != ZX_OK) {
FML_LOG(ERROR) << "Failed to get process name for sysmem; using \"\".";
return std::string();
}
return std::string(name);
}
zx_koid_t GetCurrentProcessId() {
zx_info_handle_basic_t info;
zx_status_t status = zx::process::self()->get_info(
ZX_INFO_HANDLE_BASIC, &info, sizeof(info), /*actual_count*/ nullptr,
/*avail_count*/ nullptr);
if (status != ZX_OK) {
FML_LOG(ERROR) << "Failed to get process ID for sysmem; using 0.";
return ZX_KOID_INVALID;
}
return info.koid;
}
} // namespace
SoftwareSurfaceProducer::SoftwareSurfaceProducer(
scenic::Session* scenic_session)
: scenic_session_(scenic_session) {
zx_status_t status = fdio_service_connect(
"/svc/fuchsia.sysmem.Allocator",
sysmem_allocator_.NewRequest().TakeChannel().release());
sysmem_allocator_->SetDebugClientInfo(GetCurrentProcessName(),
GetCurrentProcessId());
FML_DCHECK(status != ZX_OK);
if (!scenic_session_) {
status = fdio_service_connect(
"/svc/fuchsia.ui.composition.Allocator",
flatland_allocator_.NewRequest().TakeChannel().release());
FML_DCHECK(status != ZX_OK);
}
valid_ = true;
}
SoftwareSurfaceProducer::~SoftwareSurfaceProducer() = default;
std::unique_ptr<SurfaceProducerSurface>
SoftwareSurfaceProducer::ProduceOffscreenSurface(const SkISize& size) {
FML_CHECK(valid_);
return CreateSurface(size);
}
std::unique_ptr<SurfaceProducerSurface> SoftwareSurfaceProducer::ProduceSurface(
const SkISize& size) {
TRACE_EVENT2("flutter", "SoftwareSurfacePool::ProduceSurface", "width",
size.width(), "height", size.height());
FML_CHECK(valid_);
std::unique_ptr<SurfaceProducerSurface> surface;
auto exact_match_it =
std::find_if(available_surfaces_.begin(), available_surfaces_.end(),
[&size](const auto& surface) {
return surface->IsValid() && surface->GetSize() == size;
});
if (exact_match_it != available_surfaces_.end()) {
TRACE_EVENT_INSTANT0("flutter", "Exact match found");
surface = std::move(*exact_match_it);
available_surfaces_.erase(exact_match_it);
} else {
surface = CreateSurface(size);
}
if (surface == nullptr) {
FML_LOG(ERROR) << "Could not acquire surface.";
return nullptr;
}
if (!surface->FlushSessionAcquireAndReleaseEvents()) {
FML_LOG(ERROR) << "Could not flush acquire/release events for buffer.";
return nullptr;
}
return surface;
}
void SoftwareSurfaceProducer::SubmitSurfaces(
std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces) {
TRACE_EVENT0("flutter", "SoftwareSurfaceProducer::SubmitSurfaces");
// Submit surface
for (auto& surface : surfaces) {
SubmitSurface(std::move(surface));
}
// Buffer management.
AgeAndCollectOldBuffers();
}
void SoftwareSurfaceProducer::SubmitSurface(
std::unique_ptr<SurfaceProducerSurface> surface) {
TRACE_EVENT0("flutter", "SoftwareSurfacePool::SubmitSurface");
FML_CHECK(valid_);
// This cast is safe because |SoftwareSurface| is the only implementation of
// |SurfaceProducerSurface| for Flutter on Fuchsia. Additionally, it is
// required, because we need to access |SoftwareSurface| specific information
// of the surface (such as the amount of memory it contains).
auto software_surface = std::unique_ptr<SoftwareSurface>(
static_cast<SoftwareSurface*>(surface.release()));
if (!software_surface) {
return;
}
uintptr_t surface_key = reinterpret_cast<uintptr_t>(software_surface.get());
auto insert_iterator = pending_surfaces_.insert(std::make_pair(
surface_key, // key
std::move(software_surface) // value
));
if (insert_iterator.second) {
insert_iterator.first->second->SignalWritesFinished(std::bind(
&SoftwareSurfaceProducer::RecyclePendingSurface, this, surface_key));
}
}
std::unique_ptr<SoftwareSurface> SoftwareSurfaceProducer::CreateSurface(
const SkISize& size) {
TRACE_EVENT2("flutter", "SoftwareSurfacePool::CreateSurface", "width",
size.width(), "height", size.height());
auto surface = std::make_unique<SoftwareSurface>(
sysmem_allocator_, flatland_allocator_, scenic_session_, size);
if (!surface->IsValid()) {
FML_LOG(ERROR) << "Created surface is invalid.";
return nullptr;
}
trace_surfaces_created_++;
return surface;
}
void SoftwareSurfaceProducer::RecycleSurface(
std::unique_ptr<SoftwareSurface> surface) {
// The surface may have become invalid (for example if the fences could
// not be reset).
if (!surface->IsValid()) {
FML_LOG(ERROR) << "Attempted to recycle invalid surface.";
return;
}
TRACE_EVENT0("flutter", "SoftwareSurfacePool::RecycleSurface");
// Recycle the buffer by putting it in the list of available surfaces if we
// have not reached the maximum amount of cached surfaces.
if (available_surfaces_.size() < kMaxSurfaces) {
available_surfaces_.push_back(std::move(surface));
} else {
TRACE_EVENT_INSTANT0("flutter", "Too many surfaces in pool, dropping");
}
TraceStats();
}
void SoftwareSurfaceProducer::RecyclePendingSurface(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()) {
FML_LOG(ERROR) << "Attempted to recycle a surface that wasn't pending.";
return;
}
// Grab a hold of the surface to recycle and clear the entry in the pending
// surfaces collection.
auto surface_to_recycle = std::move(found_in_pending->second);
pending_surfaces_.erase(found_in_pending);
RecycleSurface(std::move(surface_to_recycle));
}
void SoftwareSurfaceProducer::AgeAndCollectOldBuffers() {
TRACE_EVENT0("flutter", "SoftwareSurfacePool::AgeAndCollectOldBuffers");
// Remove all surfaces that are no longer valid or are too old.
size_t size_before = available_surfaces_.size();
available_surfaces_.erase(
std::remove_if(available_surfaces_.begin(), available_surfaces_.end(),
[&](auto& surface) {
return !surface->IsValid() ||
surface->AdvanceAndGetAge() >= kMaxSurfaceAge;
}),
available_surfaces_.end());
TRACE_EVENT1("flutter", "AgeAndCollect", "aged surfaces",
(size_before - available_surfaces_.size()));
TraceStats();
}
void SoftwareSurfaceProducer::TraceStats() {
// Resources held in cached buffers.
size_t cached_surfaces_bytes = 0;
for (const auto& surface : available_surfaces_) {
cached_surfaces_bytes += surface->GetAllocationSize();
}
TRACE_COUNTER("flutter", "SurfacePoolCounts", 0u, "CachedCount",
available_surfaces_.size(), //
"Created", trace_surfaces_created_, //
"Reused", trace_surfaces_reused_, //
"PendingInCompositor", pending_surfaces_.size(), //
"Retained", 0 //
);
TRACE_COUNTER("flutter", "SurfacePoolBytes", 0u, //
"CachedBytes", cached_surfaces_bytes, //
"RetainedBytes", 0 //
);
// Reset per present/frame stats.
trace_surfaces_created_ = 0;
trace_surfaces_reused_ = 0;
}
} // namespace flutter_runner

View File

@@ -0,0 +1,77 @@
// Copyright 2013 The Flutter 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 <fuchsia/sysmem/cpp/fidl.h>
#include <fuchsia/ui/composition/cpp/fidl.h>
#include <lib/ui/scenic/cpp/resources.h>
#include <lib/ui/scenic/cpp/session.h>
#include <unordered_map>
#include "flutter/fml/macros.h"
#include "software_surface.h"
namespace flutter_runner {
class SoftwareSurfaceProducer final : public SurfaceProducer {
public:
// Only keep 12 surfaces at a time.
static constexpr int kMaxSurfaces = 12;
// If a surface doesn't get used for 3 or more generations, we discard it.
static constexpr int kMaxSurfaceAge = 3;
explicit SoftwareSurfaceProducer(scenic::Session* scenic_session);
~SoftwareSurfaceProducer() override;
bool IsValid() const { return valid_; }
// |SurfaceProducer|
GrDirectContext* gr_context() const override { return nullptr; }
// |SurfaceProducer|
std::unique_ptr<SurfaceProducerSurface> ProduceOffscreenSurface(
const SkISize& size) override;
// |SurfaceProducer|
std::unique_ptr<SurfaceProducerSurface> ProduceSurface(
const SkISize& size) override;
// |SurfaceProducer|
void SubmitSurfaces(
std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces) override;
private:
void SubmitSurface(std::unique_ptr<SurfaceProducerSurface> surface);
std::unique_ptr<SoftwareSurface> CreateSurface(const SkISize& size);
void RecycleSurface(std::unique_ptr<SoftwareSurface> surface);
void RecyclePendingSurface(uintptr_t surface_key);
void AgeAndCollectOldBuffers();
void TraceStats();
scenic::Session* scenic_session_; // Legacy gfx API endpoint.
fuchsia::sysmem::AllocatorSyncPtr sysmem_allocator_;
fuchsia::ui::composition::AllocatorPtr flatland_allocator_;
// These surfaces are available for re-use.
std::vector<std::unique_ptr<SoftwareSurface>> available_surfaces_;
// These surfaces have been written to, but scenic is not finished reading
// from them yet.
std::unordered_map<uintptr_t, std::unique_ptr<SoftwareSurface>>
pending_surfaces_;
size_t trace_surfaces_created_ = 0;
size_t trace_surfaces_reused_ = 0;
bool valid_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(SoftwareSurfaceProducer);
};
} // namespace flutter_runner

View File

@@ -14,6 +14,7 @@
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
namespace flutter_runner {
@@ -66,6 +67,10 @@ class SurfaceProducer {
public:
virtual ~SurfaceProducer() = default;
virtual GrDirectContext* gr_context() const = 0;
virtual std::unique_ptr<SurfaceProducerSurface> ProduceOffscreenSurface(
const SkISize& size) = 0;
virtual std::unique_ptr<SurfaceProducerSurface> ProduceSurface(
const SkISize& size) = 0;

View File

@@ -6,22 +6,23 @@
#include <lib/async-loop/default.h>
#include <lib/sys/cpp/component_context.h>
#include "assets/directory_asset_bundle.h"
#include "flutter/assets/directory_asset_bundle.h"
#include "flutter/common/graphics/persistent_cache.h"
#include "flutter/fml/memory/ref_ptr.h"
#include "flutter/fml/message_loop_impl.h"
#include "flutter/fml/task_runner.h"
#include "flutter/shell/common/serialization_callbacks.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/shell/platform/fuchsia/flutter/gfx_session_connection.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkSerialProcs.h"
#include "flutter/shell/platform/fuchsia/flutter/logging.h"
#include "flutter/shell/platform/fuchsia/flutter/runner.h"
#include "gtest/gtest.h"
#include "include/core/SkPicture.h"
#include "include/core/SkPictureRecorder.h"
#include "include/core/SkSerialProcs.h"
#include "flutter/shell/platform/fuchsia/flutter/vulkan_surface_producer.h"
#include "gtest/gtest.h"
using namespace flutter_runner;
using namespace flutter;
namespace flutter_runner {
@@ -74,17 +75,17 @@ class EngineTest : public ::testing::Test {
scenic_ = context_->svc()->Connect<fuchsia::ui::scenic::Scenic>();
session_.emplace(scenic_.get());
surface_producer_ =
std::make_unique<VulkanSurfaceProducer>(&session_.value());
std::make_shared<VulkanSurfaceProducer>(&session_.value());
Engine::WarmupSkps(&concurrent_task_runner_, &raster_task_runner_,
*surface_producer_, width, height, asset_manager,
std::nullopt, std::nullopt);
surface_producer_, SkISize::Make(width, height),
asset_manager, std::nullopt, std::nullopt);
}
protected:
MockTaskRunner concurrent_task_runner_;
MockTaskRunner raster_task_runner_;
std::unique_ptr<VulkanSurfaceProducer> surface_producer_;
std::shared_ptr<VulkanSurfaceProducer> surface_producer_;
std::unique_ptr<sys::ComponentContext> context_;
fuchsia::ui::scenic::ScenicPtr scenic_;

View File

@@ -128,6 +128,16 @@ class FakeSurfaceProducer : public SurfaceProducer {
: flatland_allocator_(flatland_allocator.Bind()) {}
~FakeSurfaceProducer() override = default;
// |SurfaceProducer|
GrDirectContext* gr_context() const override { return nullptr; }
// |SurfaceProducer|
std::unique_ptr<SurfaceProducerSurface> ProduceOffscreenSurface(
const SkISize& size) override {
return nullptr;
}
// |SurfaceProducer|
std::unique_ptr<SurfaceProducerSurface> ProduceSurface(
const SkISize& size) override {
auto [buffer_export_token, buffer_import_token] =
@@ -156,6 +166,7 @@ class FakeSurfaceProducer : public SurfaceProducer {
std::move(sysmem_token_request), std::move(buffer_import_token), size);
}
// |SurfaceProducer|
void SubmitSurfaces(
std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces) override {}
@@ -305,19 +316,22 @@ class FlatlandExternalViewEmbedderTest : public ::testing::Test {
protected:
FlatlandExternalViewEmbedderTest()
: session_subloop_(loop_.StartNewLoop()),
fake_surface_producer_(CreateFlatlandAllocator()),
flatland_connection_(CreateFlatlandConnection()) {}
flatland_connection_(CreateFlatlandConnection()),
fake_surface_producer_(
std::make_shared<FakeSurfaceProducer>(CreateFlatlandAllocator())) {}
~FlatlandExternalViewEmbedderTest() override = default;
async::TestLoop& loop() { return loop_; }
FakeSurfaceProducer& fake_surface_producer() {
std::shared_ptr<FakeSurfaceProducer> fake_surface_producer() {
return fake_surface_producer_;
}
FakeFlatland& fake_flatland() { return fake_flatland_; }
FlatlandConnection& flatland_connection() { return flatland_connection_; }
std::shared_ptr<FlatlandConnection> flatland_connection() {
return flatland_connection_;
}
private:
fuchsia::ui::composition::AllocatorHandle CreateFlatlandAllocator() {
@@ -328,14 +342,14 @@ class FlatlandExternalViewEmbedderTest : public ::testing::Test {
return flatland_allocator;
}
FlatlandConnection CreateFlatlandConnection() {
std::shared_ptr<FlatlandConnection> CreateFlatlandConnection() {
FML_CHECK(!fake_flatland_.is_flatland_connected());
fuchsia::ui::composition::FlatlandHandle flatland =
fake_flatland_.ConnectFlatland(session_subloop_->dispatcher());
auto test_name =
::testing::UnitTest::GetInstance()->current_test_info()->name();
return FlatlandConnection(
return std::make_shared<FlatlandConnection>(
std::move(test_name), std::move(flatland), []() { FAIL(); },
[](auto...) {}, 1, fml::TimeDelta::Zero());
}
@@ -349,9 +363,9 @@ class FlatlandExternalViewEmbedderTest : public ::testing::Test {
std::unique_ptr<async::LoopInterface> session_subloop_;
FakeFlatland fake_flatland_;
FakeSurfaceProducer fake_surface_producer_;
FlatlandConnection flatland_connection_;
std::shared_ptr<FlatlandConnection> flatland_connection_;
std::shared_ptr<FakeSurfaceProducer> fake_surface_producer_;
};
TEST_F(FlatlandExternalViewEmbedderTest, RootScene) {
@@ -382,7 +396,7 @@ TEST_F(FlatlandExternalViewEmbedderTest, RootScene) {
EXPECT_THAT(fake_flatland().graph(), IsEmptyGraph());
// Pump the loop; the contents of the initial `Present` should be processed.
flatland_connection().Present();
flatland_connection()->Present();
loop().RunUntilIdle();
EXPECT_THAT(fake_flatland().graph(),
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
@@ -411,7 +425,7 @@ TEST_F(FlatlandExternalViewEmbedderTest, SimpleScene) {
fuchsia::ui::composition::ViewBoundProtocols{},
parent_viewport_watcher.NewRequest(), flatland_connection(),
fake_surface_producer());
flatland_connection().Present();
flatland_connection()->Present();
loop().RunUntilIdle();
fake_flatland().FireOnNextFrameBeginEvent(WithPresentCredits(1u));
loop().RunUntilIdle();
@@ -471,7 +485,7 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) {
fuchsia::ui::composition::ViewBoundProtocols{},
parent_viewport_watcher.NewRequest(), flatland_connection(),
fake_surface_producer());
flatland_connection().Present();
flatland_connection()->Present();
loop().RunUntilIdle();
fake_flatland().FireOnNextFrameBeginEvent(WithPresentCredits(1u));
loop().RunUntilIdle();

View File

@@ -57,25 +57,26 @@ namespace {
class FakeSurfaceProducerSurface : public SurfaceProducerSurface {
public:
explicit FakeSurfaceProducerSurface(scenic::Session& session,
explicit FakeSurfaceProducerSurface(scenic::Session* session,
const SkISize& size,
uint32_t buffer_id)
: session_(session),
surface_(SkSurface::MakeNull(size.width(), size.height())),
image_id_(session_.AllocResourceId()),
buffer_id_(buffer_id) {
FML_CHECK(session_);
FML_CHECK(buffer_id_ != 0);
fuchsia::sysmem::BufferCollectionTokenSyncPtr token;
buffer_binding_ = token.NewRequest();
session_.RegisterBufferCollection(buffer_id_, std::move(token));
session_.Enqueue(scenic::NewCreateImage2Cmd(
image_id_ = session_->AllocResourceId();
session_->RegisterBufferCollection(buffer_id_, std::move(token));
session_->Enqueue(scenic::NewCreateImage2Cmd(
image_id_, surface_->width(), surface_->height(), buffer_id_, 0));
}
~FakeSurfaceProducerSurface() override {
session_.DeregisterBufferCollection(buffer_id_);
session_.Enqueue(scenic::NewReleaseResourceCmd(image_id_));
session_->DeregisterBufferCollection(buffer_id_);
session_->Enqueue(scenic::NewReleaseResourceCmd(image_id_));
}
bool IsValid() const override { return true; }
@@ -107,7 +108,7 @@ class FakeSurfaceProducerSurface : public SurfaceProducerSurface {
const std::function<void(void)>& on_writes_committed) override {}
private:
scenic::Session& session_;
scenic::Session* session_;
sk_sp<SkSurface> surface_;
@@ -119,20 +120,31 @@ class FakeSurfaceProducerSurface : public SurfaceProducerSurface {
class FakeSurfaceProducer : public SurfaceProducer {
public:
explicit FakeSurfaceProducer(scenic::Session& session) : session_(session) {}
explicit FakeSurfaceProducer(scenic::Session* session) : session_(session) {}
~FakeSurfaceProducer() override = default;
// |SurfaceProducer|
GrDirectContext* gr_context() const override { return nullptr; }
// |SurfaceProducer|
std::unique_ptr<SurfaceProducerSurface> ProduceOffscreenSurface(
const SkISize& size) override {
return nullptr;
}
// |SurfaceProducer|
std::unique_ptr<SurfaceProducerSurface> ProduceSurface(
const SkISize& size) override {
return std::make_unique<FakeSurfaceProducerSurface>(session_, size,
buffer_id_++);
}
// |SurfaceProducer|
void SubmitSurfaces(
std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces) override {}
private:
scenic::Session& session_;
scenic::Session* session_;
uint32_t buffer_id_{1};
};
@@ -458,21 +470,25 @@ class GfxExternalViewEmbedderTest
public fuchsia::ui::scenic::SessionListener {
protected:
GfxExternalViewEmbedderTest()
: session_listener_(this),
session_subloop_(loop_.StartNewLoop()),
: session_subloop_(loop_.StartNewLoop()),
session_listener_(this),
session_connection_(CreateSessionConnection()),
fake_surface_producer_(*session_connection_.get()) {}
fake_surface_producer_(
std::make_shared<FakeSurfaceProducer>(session_connection_->get())) {
}
~GfxExternalViewEmbedderTest() override = default;
async::TestLoop& loop() { return loop_; }
FakeSession& fake_session() { return fake_session_; }
FakeSurfaceProducer& fake_surface_producer() {
std::shared_ptr<FakeSurfaceProducer> fake_surface_producer() {
return fake_surface_producer_;
}
GfxSessionConnection& session_connection() { return session_connection_; }
std::shared_ptr<GfxSessionConnection> session_connection() {
return session_connection_;
}
private:
// |fuchsia::ui::scenic::SessionListener|
@@ -483,7 +499,7 @@ class GfxExternalViewEmbedderTest
FAIL();
}
GfxSessionConnection CreateSessionConnection() {
std::shared_ptr<GfxSessionConnection> CreateSessionConnection() {
FML_CHECK(!fake_session_.is_bound());
FML_CHECK(!session_listener_.is_bound());
@@ -494,22 +510,22 @@ class GfxExternalViewEmbedderTest
fake_session_.Bind(session_subloop_->dispatcher());
session_listener_.Bind(std::move(session_listener));
return GfxSessionConnection(
return std::make_shared<GfxSessionConnection>(
GetCurrentTestName(), std::move(inspect_node), std::move(session),
[]() { FAIL(); }, [](auto...) {}, 1, fml::TimeDelta::Zero());
}
async::TestLoop loop_; // Must come before FIDL bindings.
inspect::Inspector inspector_;
std::unique_ptr<async::LoopInterface> session_subloop_;
fidl::Binding<fuchsia::ui::scenic::SessionListener> session_listener_;
std::unique_ptr<async::LoopInterface> session_subloop_;
FakeSession fake_session_;
GfxSessionConnection session_connection_;
inspect::Inspector inspector_;
FakeSurfaceProducer fake_surface_producer_;
FakeSession fake_session_;
std::shared_ptr<GfxSessionConnection> session_connection_;
std::shared_ptr<FakeSurfaceProducer> fake_surface_producer_;
};
TEST_F(GfxExternalViewEmbedderTest, RootScene) {

View File

@@ -14,7 +14,6 @@
#include "flutter/fml/trace_event.h"
#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
#include "third_party/skia/include/gpu/vk/GrVkExtensions.h"
#include "third_party/skia/include/gpu/vk/GrVkTypes.h"

View File

@@ -7,6 +7,8 @@
#include <lib/async/cpp/time.h>
#include <lib/async/default.h>
#include <lib/syslog/global.h>
#include <lib/ui/scenic/cpp/resources.h>
#include <lib/ui/scenic/cpp/session.h>
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
@@ -14,8 +16,8 @@
#include "flutter/vulkan/vulkan_device.h"
#include "flutter/vulkan/vulkan_proc_table.h"
#include "flutter/vulkan/vulkan_provider.h"
#include "lib/ui/scenic/cpp/resources.h"
#include "lib/ui/scenic/cpp/session.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "logging.h"
#include "vulkan_surface.h"
#include "vulkan_surface_pool.h"
@@ -30,10 +32,12 @@ class VulkanSurfaceProducer final : public SurfaceProducer,
bool IsValid() const { return valid_; }
GrDirectContext* gr_context() const { return context_.get(); }
// |SurfaceProducer|
GrDirectContext* gr_context() const override { return context_.get(); }
// |SurfaceProducer|
std::unique_ptr<SurfaceProducerSurface> ProduceOffscreenSurface(
const SkISize& size);
const SkISize& size) override;
// |SurfaceProducer|
std::unique_ptr<SurfaceProducerSurface> ProduceSurface(