[roll] Fixes for the Flutter roll
Includes https://fuchsia-review.googlesource.com/c/topaz/+/241557
Change-Id: I96705121db9197d0dff91136464d24e4aa02b290
diff --git a/app/term/view_controller.cc b/app/term/view_controller.cc
index d6a664b..0173b85 100644
--- a/app/term/view_controller.cc
+++ b/app/term/view_controller.cc
@@ -13,6 +13,7 @@
#include "lib/fxl/strings/string_printf.h"
#include "lib/ui/input/cpp/formatting.h"
#include "third_party/skia/include/core/SkFont.h"
+#include "third_party/skia/include/core/SkFontMetrics.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "topaz/app/term/key_util.h"
#include "topaz/app/term/pty_server.h"
diff --git a/public/lib/settings/lib/audio.pb.dart b/public/lib/settings/lib/audio.pb.dart
index 9e63f73..c41a078 100644
--- a/public/lib/settings/lib/audio.pb.dart
+++ b/public/lib/settings/lib/audio.pb.dart
@@ -1,34 +1,34 @@
///
// Generated code. Do not modify.
+// source: audio.proto
///
-// ignore_for_file: non_constant_identifier_names,library_prefixes
+// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
// ignore: UNUSED_SHOWN_NAME
-import 'dart:core' show int, bool, double, String, List, override;
+import 'dart:core' show int, bool, double, String, List, Map, override;
-import 'package:protobuf/protobuf.dart';
+import 'package:protobuf/protobuf.dart' as $pb;
-class Audio extends GeneratedMessage {
- static final BuilderInfo _i = new BuilderInfo('Audio')
- ..a<double>(1, 'gain', PbFieldType.OD)
+class Audio extends $pb.GeneratedMessage {
+ static final $pb.BuilderInfo _i = new $pb.BuilderInfo('Audio')
+ ..a<double>(1, 'gain', $pb.PbFieldType.OD)
..aOB(2, 'muted')
..hasRequiredFields = false
;
Audio() : super();
- Audio.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
- Audio.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
+ Audio.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
+ Audio.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
Audio clone() => new Audio()..mergeFromMessage(this);
- BuilderInfo get info_ => _i;
+ Audio copyWith(void Function(Audio) updates) => super.copyWith((message) => updates(message as Audio));
+ $pb.BuilderInfo get info_ => _i;
static Audio create() => new Audio();
- static PbList<Audio> createRepeated() => new PbList<Audio>();
- static Audio getDefault() {
- if (_defaultInstance == null) _defaultInstance = new _ReadonlyAudio();
- return _defaultInstance;
- }
+ Audio createEmptyInstance() => create();
+ static $pb.PbList<Audio> createRepeated() => new $pb.PbList<Audio>();
+ static Audio getDefault() => _defaultInstance ??= create()..freeze();
static Audio _defaultInstance;
static void $checkItem(Audio v) {
- if (v is! Audio) checkItemFailed(v, 'Audio');
+ if (v is! Audio) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
double get gain => $_getN(0);
@@ -42,5 +42,3 @@
void clearMuted() => clearField(2);
}
-class _ReadonlyAudio extends Audio with ReadonlyMessageMixin {}
-
diff --git a/public/lib/settings/lib/audio.pbenum.dart b/public/lib/settings/lib/audio.pbenum.dart
index 325f725..4eac8b0 100644
--- a/public/lib/settings/lib/audio.pbenum.dart
+++ b/public/lib/settings/lib/audio.pbenum.dart
@@ -1,5 +1,6 @@
///
// Generated code. Do not modify.
+// source: audio.proto
///
-// ignore_for_file: non_constant_identifier_names,library_prefixes
+// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
diff --git a/public/lib/settings/lib/audio.pbjson.dart b/public/lib/settings/lib/audio.pbjson.dart
index c4fc531..b963c5c 100644
--- a/public/lib/settings/lib/audio.pbjson.dart
+++ b/public/lib/settings/lib/audio.pbjson.dart
@@ -1,7 +1,8 @@
///
// Generated code. Do not modify.
+// source: audio.proto
///
-// ignore_for_file: non_constant_identifier_names,library_prefixes
+// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
const Audio$json = const {
'1': 'Audio',
diff --git a/public/lib/settings/lib/audio.pbserver.dart b/public/lib/settings/lib/audio.pbserver.dart
index b57e4d2..a179994 100644
--- a/public/lib/settings/lib/audio.pbserver.dart
+++ b/public/lib/settings/lib/audio.pbserver.dart
@@ -1,7 +1,8 @@
///
// Generated code. Do not modify.
+// source: audio.proto
///
-// ignore_for_file: non_constant_identifier_names,library_prefixes
+// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
export 'audio.pb.dart';
diff --git a/runtime/flutter_runner/vulkan_surface.h b/runtime/flutter_runner/vulkan_surface.h
index 8222d3d..8604ab9 100644
--- a/runtime/flutter_runner/vulkan_surface.h
+++ b/runtime/flutter_runner/vulkan_surface.h
@@ -11,6 +11,7 @@
#include <array>
#include <memory>
+#include "flutter/flow/raster_cache_key.h"
#include "flutter/flow/scene_update_context.h"
#include "flutter/fml/macros.h"
#include "flutter/vulkan/vulkan_command_buffer.h"
@@ -115,6 +116,40 @@
// if the swap was not successful.
bool BindToImage(sk_sp<GrContext> context, VulkanImage vulkan_image);
+ // Flutter may retain a |VulkanSurface| for a |flow::Layer| subtree to improve
+ // the performance. The |retained_key_| identifies which layer subtree this
+ // |VulkanSurface| is retained for. The key has two parts. One is the pointer
+ // to the root of that layer subtree: |retained_key_.id()|. Another is the
+ // transformation matrix: |retained_key_.matrix()|. We need the matrix part
+ // because a different matrix would invalidate the pixels (raster cache) in
+ // this |VulkanSurface|.
+ const flow::LayerRasterCacheKey& GetRetainedKey() const {
+ return retained_key_;
+ }
+
+ // For better safety in retained rendering, Flutter uses a retained
+ // |EntityNode| associated with the retained surface instead of using the
+ // retained surface directly. Hence Flutter can't modify the surface during
+ // retained rendering.
+ const scenic::EntityNode& GetRetainedNode() {
+ used_in_retained_rendering_ = true;
+ return *retained_node_;
+ }
+
+ // Check whether the retained surface (and its associated |EntityNode|) is
+ // used in the current frame or not. If unused, the |VulkanSurfacePool| will
+ // try to recycle the surface. This flag is reset after each frame.
+ bool IsUsedInRetainedRendering() const { return used_in_retained_rendering_; }
+ void ResetIsUsedInRetainedRendering() { used_in_retained_rendering_ = false; }
+
+ // Let this surface own the retained EntityNode associated with it (see
+ // |GetRetainedNode|), and set the retained key (see |GetRetainedKey|).
+ void SetRetainedInfo(const flow::LayerRasterCacheKey& key,
+ std::unique_ptr<scenic::EntityNode> node) {
+ retained_key_ = key;
+ retained_node_ = std::move(node);
+ }
+
private:
static constexpr int kSizeHistorySize = 4;
@@ -159,6 +194,12 @@
size_t age_ = 0;
bool valid_ = false;
+ flow::LayerRasterCacheKey retained_key_ =
+ {nullptr, SkMatrix::MakeScale(1, 1)};
+ std::unique_ptr<scenic::EntityNode> retained_node_ = nullptr;
+
+ std::atomic<bool> used_in_retained_rendering_ = false;
+
FML_DISALLOW_COPY_AND_ASSIGN(VulkanSurface);
};
diff --git a/runtime/flutter_runner/vulkan_surface_pool.cc b/runtime/flutter_runner/vulkan_surface_pool.cc
index 589fe57..5a0795f 100644
--- a/runtime/flutter_runner/vulkan_surface_pool.cc
+++ b/runtime/flutter_runner/vulkan_surface_pool.cc
@@ -31,7 +31,7 @@
VulkanSurfacePool::~VulkanSurfacePool() {}
-std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
+std::unique_ptr<VulkanSurface>
VulkanSurfacePool::AcquireSurface(const SkISize& size) {
auto surface = GetCachedOrCreateSurface(size);
@@ -48,7 +48,7 @@
return surface;
}
-std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
+std::unique_ptr<VulkanSurface>
VulkanSurfacePool::GetCachedOrCreateSurface(const SkISize& size) {
// First try to find a surface that exactly matches |size|.
{
@@ -121,16 +121,42 @@
return;
}
- uintptr_t surface_key = reinterpret_cast<uintptr_t>(vulkan_surface.get());
- auto insert_iterator = pending_surfaces_.insert(std::make_pair(
- surface_key, // key
- std::move(vulkan_surface) // value
- ));
-
- if (insert_iterator.second) {
- insert_iterator.first->second->SignalWritesFinished(
- std::bind(&VulkanSurfacePool::RecycleSurface, this, surface_key));
+ const flow::LayerRasterCacheKey& retained_key =
+ vulkan_surface->GetRetainedKey();
+ if (retained_key.id() != nullptr) {
+ // Add the surface to |retained_surfaces_| if its retained key has a non-
+ // null layer (|retained_key.id()|).
+ //
+ // We have to add the entry to |retained_surfaces_| map early when it's
+ // still pending (|is_pending| = true). Otherwise (if we add the surface
+ // later when |SignalRetainedReady| is called), Flutter would fail to find
+ // the retained node before the painting is done (which could take multiple
+ // frames). Flutter would then create a new |VulkanSurface| for the layer
+ // upon the failed lookup. The new |VulkanSurface| would invalidate this
+ // surface, and before the new |VulkanSurface| is done painting, another
+ // newer |VulkanSurface| is likely to be created to replace the new
+ // |VulkanSurface|. That would make the retained rendering much less useful
+ // in improving the performance.
+ auto insert_iterator = retained_surfaces_.insert(std::make_pair(
+ retained_key,
+ RetainedSurface({true, std::move(vulkan_surface)})
+ ));
+ if (insert_iterator.second) {
+ insert_iterator.first->second.vk_surface->SignalWritesFinished(
+ std::bind(&VulkanSurfacePool::SignalRetainedReady, this, retained_key));
+ }
+ } else {
+ uintptr_t surface_key = reinterpret_cast<uintptr_t>(vulkan_surface.get());
+ auto insert_iterator = pending_surfaces_.insert(std::make_pair(
+ surface_key, // key
+ std::move(vulkan_surface) // value
+ ));
+ if (insert_iterator.second) {
+ insert_iterator.first->second->SignalWritesFinished(
+ std::bind(&VulkanSurfacePool::RecyclePendingSurface,
+ this, surface_key));
+ }
}
}
@@ -147,7 +173,7 @@
return surface;
}
-void VulkanSurfacePool::RecycleSurface(uintptr_t surface_key) {
+void VulkanSurfacePool::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);
@@ -160,19 +186,42 @@
auto surface_to_recycle = std::move(found_in_pending->second);
pending_surfaces_.erase(found_in_pending);
+ RecycleSurface(std::move(surface_to_recycle));
+}
+
+void VulkanSurfacePool::RecycleSurface(std::unique_ptr<VulkanSurface> surface) {
// The surface may have become invalid (for example it the fences could
// not be reset).
- if (!surface_to_recycle->IsValid()) {
+ if (!surface->IsValid()) {
return;
}
// 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_to_recycle));
+ available_surfaces_.push_back(std::move(surface));
}
}
+void VulkanSurfacePool::RecycleRetainedSurface(
+ const flow::LayerRasterCacheKey& key) {
+ auto it = retained_surfaces_.find(key);
+ if (it == retained_surfaces_.end()) {
+ return;
+ }
+
+ // The surface should not be pending.
+ FML_DCHECK(!it->second.is_pending);
+
+ auto surface_to_recycle = std::move(it->second.vk_surface);
+ retained_surfaces_.erase(it);
+ RecycleSurface(std::move(surface_to_recycle));
+}
+
+void VulkanSurfacePool::SignalRetainedReady(flow::LayerRasterCacheKey key) {
+ retained_surfaces_[key].is_pending = false;
+}
+
void VulkanSurfacePool::AgeAndCollectOldBuffers() {
TRACE_DURATION("flutter", "VulkanSurfacePool::AgeAndCollectOldBuffers");
@@ -205,6 +254,25 @@
}
}
+ // Recycle retained surfaces that are not used and not pending in this frame.
+ //
+ // It's safe to recycle any retained surfaces that are not pending no matter
+ // whether they're used or not. Hence if there's memory pressure, feel free to
+ // recycle all retained surfaces that are not pending.
+ std::vector<flow::LayerRasterCacheKey> recycle_keys;
+ for (auto&[key, retained_surface] : retained_surfaces_) {
+ if (retained_surface.is_pending ||
+ retained_surface.vk_surface->IsUsedInRetainedRendering()) {
+ // Reset the flag for the next frame
+ retained_surface.vk_surface->ResetIsUsedInRetainedRendering();
+ } else {
+ recycle_keys.push_back(key);
+ }
+ }
+ for (auto& key : recycle_keys) {
+ RecycleRetainedSurface(key);
+ }
+
TraceStats();
}
@@ -257,6 +325,7 @@
"Created", trace_surfaces_created_, //
"Reused", trace_surfaces_reused_, //
"PendingInCompositor", pending_surfaces_.size(), //
+ "Retained", retained_surfaces_.size(), //
"SkiaCacheResources", skia_resources, //
"SkiaCacheBytes", skia_bytes, //
"SkiaCachePurgeable", skia_cache_purgeable //
diff --git a/runtime/flutter_runner/vulkan_surface_pool.h b/runtime/flutter_runner/vulkan_surface_pool.h
index 452816d..b000963 100644
--- a/runtime/flutter_runner/vulkan_surface_pool.h
+++ b/runtime/flutter_runner/vulkan_surface_pool.h
@@ -25,8 +25,7 @@
~VulkanSurfacePool();
- std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
- AcquireSurface(const SkISize& size);
+ std::unique_ptr<VulkanSurface> AcquireSurface(const SkISize& size);
void SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
@@ -38,22 +37,56 @@
// small as they can be.
void ShrinkToFit();
+ // For |VulkanSurfaceProducer::HasRetainedNode|.
+ bool HasRetainedNode(const flow::LayerRasterCacheKey& key) const {
+ return retained_surfaces_.find(key) != retained_surfaces_.end();
+ }
+ // For |VulkanSurfaceProducer::GetRetainedNode|.
+ const scenic::EntityNode& GetRetainedNode(
+ const flow::LayerRasterCacheKey& key) {
+ FML_DCHECK(HasRetainedNode(key));
+ return retained_surfaces_[key].vk_surface->GetRetainedNode();
+ }
+
+
private:
+ // Struct for retained_surfaces_ map.
+ struct RetainedSurface {
+ // If |is_pending| is true, the |vk_surface| is still under painting
+ // (similar to those in |pending_surfaces_|) so we can't recycle the
+ // |vk_surface| yet.
+ bool is_pending;
+ std::unique_ptr<VulkanSurface> vk_surface;
+ };
+
vulkan::VulkanProvider& vulkan_provider_;
sk_sp<GrContext> context_;
scenic::Session* scenic_session_;
std::vector<std::unique_ptr<VulkanSurface>> available_surfaces_;
std::unordered_map<uintptr_t, std::unique_ptr<VulkanSurface>>
pending_surfaces_;
+
+ // Retained surfaces keyed by the layer that created and used the surface.
+ flow::LayerRasterCacheKey::Map<RetainedSurface>
+ retained_surfaces_;
+
size_t trace_surfaces_created_ = 0;
size_t trace_surfaces_reused_ = 0;
- std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
- GetCachedOrCreateSurface(const SkISize& size);
+ std::unique_ptr<VulkanSurface> GetCachedOrCreateSurface(const SkISize& size);
std::unique_ptr<VulkanSurface> CreateSurface(const SkISize& size);
- void RecycleSurface(uintptr_t surface_key);
+ void RecycleSurface(std::unique_ptr<VulkanSurface> surface);
+
+ void RecyclePendingSurface(uintptr_t surface_key);
+
+ // Clear the |is_pending| flag of the retained surface.
+ void SignalRetainedReady(flow::LayerRasterCacheKey key);
+
+ // Remove the corresponding surface from |retained_surfaces| and recycle it.
+ // The surface must not be pending.
+ void RecycleRetainedSurface(const flow::LayerRasterCacheKey& key);
void TraceStats();
diff --git a/runtime/flutter_runner/vulkan_surface_producer.cc b/runtime/flutter_runner/vulkan_surface_producer.cc
index d438a0f..633ca84 100644
--- a/runtime/flutter_runner/vulkan_surface_producer.cc
+++ b/runtime/flutter_runner/vulkan_surface_producer.cc
@@ -220,10 +220,15 @@
}
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
-VulkanSurfaceProducer::ProduceSurface(const SkISize& size) {
+VulkanSurfaceProducer::ProduceSurface(
+ const SkISize& size,
+ const flow::LayerRasterCacheKey& layer_key,
+ std::unique_ptr<scenic::EntityNode> entity_node) {
FML_DCHECK(valid_);
last_produce_time_ = fxl::TimePoint::Now();
- return surface_pool_->AcquireSurface(size);
+ auto surface = surface_pool_->AcquireSurface(size);
+ surface->SetRetainedInfo(layer_key, std::move(entity_node));
+ return surface;
}
void VulkanSurfaceProducer::SubmitSurface(
diff --git a/runtime/flutter_runner/vulkan_surface_producer.h b/runtime/flutter_runner/vulkan_surface_producer.h
index 00f82cb..6e4fd14 100644
--- a/runtime/flutter_runner/vulkan_surface_producer.h
+++ b/runtime/flutter_runner/vulkan_surface_producer.h
@@ -30,13 +30,26 @@
// |flow::SceneUpdateContext::SurfaceProducer|
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
- ProduceSurface(const SkISize& size) override;
+ ProduceSurface(const SkISize& size,
+ const flow::LayerRasterCacheKey& layer_key,
+ std::unique_ptr<scenic::EntityNode> entity_node) override;
// |flow::SceneUpdateContext::SurfaceProducer|
void SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface> surface)
override;
+ // |flow::SceneUpdateContext::HasRetainedNode|
+ bool HasRetainedNode(const flow::LayerRasterCacheKey& key) const override {
+ return surface_pool_->HasRetainedNode(key);
+ }
+
+ // |flow::SceneUpdateContext::GetRetainedNode|
+ const scenic::EntityNode& GetRetainedNode(
+ const flow::LayerRasterCacheKey& key) override {
+ return surface_pool_->GetRetainedNode(key);
+ }
+
void OnSurfacesPresented(
std::vector<
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>
diff --git a/tools/dart_dependencies.yaml b/tools/dart_dependencies.yaml
index cb42761..8f677eb 100644
--- a/tools/dart_dependencies.yaml
+++ b/tools/dart_dependencies.yaml
@@ -14,8 +14,8 @@
googleapis: ^0.52.0+1
html_unescape: ^1.0.1
markdown: ^2.0.2
- protobuf: ^0.10.4
- protoc_plugin: ^0.10.5
+ protobuf: ^0.13.2
+ protoc_plugin: ^15.0.3
strings: ^0.1.0
tuple: ^1.0.2
uuid: ^1.0.3