Flutter Engine
The Flutter Engine
software_surface_producer.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <lib/fdio/directory.h>
8#include <lib/zx/process.h>
9
10#include <algorithm> // For std::remove_if
11#include <memory>
12#include <string>
13#include <utility>
14#include <vector>
15
16#include "flutter/fml/logging.h"
17#include "flutter/fml/trace_event.h"
18
19namespace flutter_runner {
20
21namespace {
22
23std::string GetCurrentProcessName() {
24 char name[ZX_MAX_NAME_LEN];
25 zx_status_t status =
26 zx::process::self()->get_property(ZX_PROP_NAME, name, sizeof(name));
27 if (status != ZX_OK) {
28 FML_LOG(ERROR) << "Failed to get process name for sysmem; using \"\".";
29 return std::string();
30 }
31
32 return std::string(name);
33}
34
35zx_koid_t GetCurrentProcessId() {
36 zx_info_handle_basic_t info;
37 zx_status_t status = zx::process::self()->get_info(
38 ZX_INFO_HANDLE_BASIC, &info, sizeof(info), /*actual_count*/ nullptr,
39 /*avail_count*/ nullptr);
40 if (status != ZX_OK) {
41 FML_LOG(ERROR) << "Failed to get process ID for sysmem; using 0.";
42 return ZX_KOID_INVALID;
43 }
44
45 return info.koid;
46}
47
48} // namespace
49
51 zx_status_t status = fdio_service_connect(
52 "/svc/fuchsia.sysmem.Allocator",
53 sysmem_allocator_.NewRequest().TakeChannel().release());
54 sysmem_allocator_->SetDebugClientInfo(GetCurrentProcessName(),
56 FML_DCHECK(status == ZX_OK);
57
58 status = fdio_service_connect(
59 "/svc/fuchsia.ui.composition.Allocator",
60 flatland_allocator_.NewRequest().TakeChannel().release());
61 FML_DCHECK(status == ZX_OK);
62
63 valid_ = true;
64}
65
67
68std::unique_ptr<SurfaceProducerSurface>
70 FML_CHECK(valid_);
71
72 return CreateSurface(size);
73}
74
75std::unique_ptr<SurfaceProducerSurface> SoftwareSurfaceProducer::ProduceSurface(
76 const SkISize& size) {
77 TRACE_EVENT2("flutter", "SoftwareSurfacePool::ProduceSurface", "width",
78 size.width(), "height", size.height());
79 FML_CHECK(valid_);
80
81 std::unique_ptr<SurfaceProducerSurface> surface;
82 auto exact_match_it =
83 std::find_if(available_surfaces_.begin(), available_surfaces_.end(),
84 [&size](const auto& surface) {
85 return surface->IsValid() && surface->GetSize() == size;
86 });
87 if (exact_match_it != available_surfaces_.end()) {
88 TRACE_EVENT_INSTANT0("flutter", "Exact match found");
89 surface = std::move(*exact_match_it);
90 available_surfaces_.erase(exact_match_it);
91 } else {
92 surface = CreateSurface(size);
93 }
94
95 if (surface == nullptr) {
96 FML_LOG(ERROR) << "Could not acquire surface.";
97 return nullptr;
98 }
99
100 if (!surface->FlushSessionAcquireAndReleaseEvents()) {
101 FML_LOG(ERROR) << "Could not flush acquire/release events for buffer.";
102 return nullptr;
103 }
104
105 return surface;
106}
107
109 std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces) {
110 TRACE_EVENT0("flutter", "SoftwareSurfaceProducer::SubmitSurfaces");
111
112 // Submit surface
113 for (auto& surface : surfaces) {
114 SubmitSurface(std::move(surface));
115 }
116
117 // Buffer management.
118 AgeAndCollectOldBuffers();
119}
120
121void SoftwareSurfaceProducer::SubmitSurface(
122 std::unique_ptr<SurfaceProducerSurface> surface) {
123 TRACE_EVENT0("flutter", "SoftwareSurfacePool::SubmitSurface");
124 FML_CHECK(valid_);
125
126 // This cast is safe because |SoftwareSurface| is the only implementation of
127 // |SurfaceProducerSurface| for Flutter on Fuchsia. Additionally, it is
128 // required, because we need to access |SoftwareSurface| specific information
129 // of the surface (such as the amount of memory it contains).
130 auto software_surface = std::unique_ptr<SoftwareSurface>(
131 static_cast<SoftwareSurface*>(surface.release()));
132 if (!software_surface) {
133 return;
134 }
135
136 uintptr_t surface_key = reinterpret_cast<uintptr_t>(software_surface.get());
137 auto insert_iterator = pending_surfaces_.insert(std::make_pair(
138 surface_key, // key
139 std::move(software_surface) // value
140 ));
141 if (insert_iterator.second) {
142 insert_iterator.first->second->SignalWritesFinished(std::bind(
143 &SoftwareSurfaceProducer::RecyclePendingSurface, this, surface_key));
144 }
145}
146
147std::unique_ptr<SoftwareSurface> SoftwareSurfaceProducer::CreateSurface(
148 const SkISize& size) {
149 TRACE_EVENT2("flutter", "SoftwareSurfacePool::CreateSurface", "width",
150 size.width(), "height", size.height());
151 auto surface = std::make_unique<SoftwareSurface>(sysmem_allocator_,
152 flatland_allocator_, size);
153 if (!surface->IsValid()) {
154 FML_LOG(ERROR) << "Created surface is invalid.";
155 return nullptr;
156 }
157 trace_surfaces_created_++;
158 return surface;
159}
160
161void SoftwareSurfaceProducer::RecycleSurface(
162 std::unique_ptr<SoftwareSurface> surface) {
163 // The surface may have become invalid (for example if the fences could
164 // not be reset).
165 if (!surface->IsValid()) {
166 FML_LOG(ERROR) << "Attempted to recycle invalid surface.";
167 return;
168 }
169
170 TRACE_EVENT0("flutter", "SoftwareSurfacePool::RecycleSurface");
171 // Recycle the buffer by putting it in the list of available surfaces if we
172 // have not reached the maximum amount of cached surfaces.
173 if (available_surfaces_.size() < kMaxSurfaces) {
174 available_surfaces_.push_back(std::move(surface));
175 } else {
176 TRACE_EVENT_INSTANT0("flutter", "Too many surfaces in pool, dropping");
177 }
178 TraceStats();
179}
180
181void SoftwareSurfaceProducer::RecyclePendingSurface(uintptr_t surface_key) {
182 // Before we do anything, we must clear the surface from the collection of
183 // pending surfaces.
184 auto found_in_pending = pending_surfaces_.find(surface_key);
185 if (found_in_pending == pending_surfaces_.end()) {
186 FML_LOG(ERROR) << "Attempted to recycle a surface that wasn't pending.";
187 return;
188 }
189
190 // Grab a hold of the surface to recycle and clear the entry in the pending
191 // surfaces collection.
192 auto surface_to_recycle = std::move(found_in_pending->second);
193 pending_surfaces_.erase(found_in_pending);
194
195 RecycleSurface(std::move(surface_to_recycle));
196}
197
198void SoftwareSurfaceProducer::AgeAndCollectOldBuffers() {
199 TRACE_EVENT0("flutter", "SoftwareSurfacePool::AgeAndCollectOldBuffers");
200
201 // Remove all surfaces that are no longer valid or are too old.
202 size_t size_before = available_surfaces_.size();
203 available_surfaces_.erase(
204 std::remove_if(available_surfaces_.begin(), available_surfaces_.end(),
205 [&](auto& surface) {
206 return !surface->IsValid() ||
207 surface->AdvanceAndGetAge() >= kMaxSurfaceAge;
208 }),
209 available_surfaces_.end());
210 TRACE_EVENT1("flutter", "AgeAndCollect", "aged surfaces",
211 (size_before - available_surfaces_.size()));
212
213 TraceStats();
214}
215
216void SoftwareSurfaceProducer::TraceStats() {
217 // Resources held in cached buffers.
218 size_t cached_surfaces_bytes = 0;
219 for (const auto& surface : available_surfaces_) {
220 cached_surfaces_bytes += surface->GetAllocationSize();
221 }
222
223 TRACE_COUNTER("flutter", "SurfacePoolCounts", 0u, "CachedCount",
224 available_surfaces_.size(), //
225 "Created", trace_surfaces_created_, //
226 "Reused", trace_surfaces_reused_, //
227 "PendingInCompositor", pending_surfaces_.size(), //
228 "Retained", 0 //
229 );
230
231 TRACE_COUNTER("flutter", "SurfacePoolBytes", 0u, //
232 "CachedBytes", cached_surfaces_bytes, //
233 "RetainedBytes", 0 //
234 );
235
236 // Reset per present/frame stats.
237 trace_surfaces_created_ = 0;
238 trace_surfaces_reused_ = 0;
239}
240
241} // namespace flutter_runner
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
void SubmitSurfaces(std::vector< std::unique_ptr< SurfaceProducerSurface > > surfaces) override
std::unique_ptr< SurfaceProducerSurface > ProduceOffscreenSurface(const SkISize &size) override
std::unique_ptr< SurfaceProducerSurface > ProduceSurface(const SkISize &size) override
VkSurfaceKHR surface
Definition: main.cc:49
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_CHECK(condition)
Definition: logging.h:85
#define FML_DCHECK(condition)
Definition: logging.h:103
static zx_koid_t GetCurrentProcessId()
static std::string GetCurrentProcessName()
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: SkSize.h:16
#define ERROR(message)
Definition: elf_loader.cc:260
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131
#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
Definition: trace_event.h:145
#define TRACE_EVENT_INSTANT0(category_group, name)
Definition: trace_event.h:175
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
Definition: trace_event.h:141