Flutter Engine
 
Loading...
Searching...
No Matches
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"
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.sysmem2.Allocator",
53 sysmem_allocator_.NewRequest().TakeChannel().release());
54 sysmem_allocator_->SetDebugClientInfo(
55 std::move(fuchsia::sysmem2::AllocatorSetDebugClientInfoRequest{}
56 .set_name(GetCurrentProcessName())
57 .set_id(GetCurrentProcessId())));
58 FML_DCHECK(status == ZX_OK);
59
60 status = fdio_service_connect(
61 "/svc/fuchsia.ui.composition.Allocator",
62 flatland_allocator_.NewRequest().TakeChannel().release());
63 FML_DCHECK(status == ZX_OK);
64
65 valid_ = true;
66}
67
69
70std::unique_ptr<SurfaceProducerSurface>
72 FML_CHECK(valid_);
73
74 return CreateSurface(size);
75}
76
77std::unique_ptr<SurfaceProducerSurface> SoftwareSurfaceProducer::ProduceSurface(
78 const SkISize& size) {
79 TRACE_EVENT2("flutter", "SoftwareSurfacePool::ProduceSurface", "width",
80 size.width(), "height", size.height());
81 FML_CHECK(valid_);
82
83 std::unique_ptr<SurfaceProducerSurface> surface;
84 auto exact_match_it =
85 std::find_if(available_surfaces_.begin(), available_surfaces_.end(),
86 [&size](const auto& surface) {
87 return surface->IsValid() && surface->GetSize() == size;
88 });
89 if (exact_match_it != available_surfaces_.end()) {
90 TRACE_EVENT_INSTANT0("flutter", "Exact match found");
91 surface = std::move(*exact_match_it);
92 available_surfaces_.erase(exact_match_it);
93 } else {
94 surface = CreateSurface(size);
95 }
96
97 if (surface == nullptr) {
98 FML_LOG(ERROR) << "Could not acquire surface.";
99 return nullptr;
100 }
101
102 if (!surface->FlushSessionAcquireAndReleaseEvents()) {
103 FML_LOG(ERROR) << "Could not flush acquire/release events for buffer.";
104 return nullptr;
105 }
106
107 return surface;
108}
109
111 std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces) {
112 TRACE_EVENT0("flutter", "SoftwareSurfaceProducer::SubmitSurfaces");
113
114 // Submit surface
115 for (auto& surface : surfaces) {
116 SubmitSurface(std::move(surface));
117 }
118
119 // Buffer management.
120 AgeAndCollectOldBuffers();
121}
122
123void SoftwareSurfaceProducer::SubmitSurface(
124 std::unique_ptr<SurfaceProducerSurface> surface) {
125 TRACE_EVENT0("flutter", "SoftwareSurfacePool::SubmitSurface");
126 FML_CHECK(valid_);
127
128 // This cast is safe because |SoftwareSurface| is the only implementation of
129 // |SurfaceProducerSurface| for Flutter on Fuchsia. Additionally, it is
130 // required, because we need to access |SoftwareSurface| specific information
131 // of the surface (such as the amount of memory it contains).
132 auto software_surface = std::unique_ptr<SoftwareSurface>(
133 static_cast<SoftwareSurface*>(surface.release()));
134 if (!software_surface) {
135 return;
136 }
137
138 uintptr_t surface_key = reinterpret_cast<uintptr_t>(software_surface.get());
139 auto insert_iterator = pending_surfaces_.insert(std::make_pair(
140 surface_key, // key
141 std::move(software_surface) // value
142 ));
143 if (insert_iterator.second) {
144 insert_iterator.first->second->SignalWritesFinished(std::bind(
145 &SoftwareSurfaceProducer::RecyclePendingSurface, this, surface_key));
146 }
147}
148
149std::unique_ptr<SoftwareSurface> SoftwareSurfaceProducer::CreateSurface(
150 const SkISize& size) {
151 TRACE_EVENT2("flutter", "SoftwareSurfacePool::CreateSurface", "width",
152 size.width(), "height", size.height());
153 auto surface = std::make_unique<SoftwareSurface>(sysmem_allocator_,
154 flatland_allocator_, size);
155 if (!surface->IsValid()) {
156 FML_LOG(ERROR) << "Created surface is invalid.";
157 return nullptr;
158 }
159 trace_surfaces_created_++;
160 return surface;
161}
162
163void SoftwareSurfaceProducer::RecycleSurface(
164 std::unique_ptr<SoftwareSurface> surface) {
165 // The surface may have become invalid (for example if the fences could
166 // not be reset).
167 if (!surface->IsValid()) {
168 FML_LOG(ERROR) << "Attempted to recycle invalid surface.";
169 return;
170 }
171
172 TRACE_EVENT0("flutter", "SoftwareSurfacePool::RecycleSurface");
173 // Recycle the buffer by putting it in the list of available surfaces if we
174 // have not reached the maximum amount of cached surfaces.
175 if (available_surfaces_.size() < kMaxSurfaces) {
176 available_surfaces_.push_back(std::move(surface));
177 } else {
178 TRACE_EVENT_INSTANT0("flutter", "Too many surfaces in pool, dropping");
179 }
180 TraceStats();
181}
182
183void SoftwareSurfaceProducer::RecyclePendingSurface(uintptr_t surface_key) {
184 // Before we do anything, we must clear the surface from the collection of
185 // pending surfaces.
186 auto found_in_pending = pending_surfaces_.find(surface_key);
187 if (found_in_pending == pending_surfaces_.end()) {
188 FML_LOG(ERROR) << "Attempted to recycle a surface that wasn't pending.";
189 return;
190 }
191
192 // Grab a hold of the surface to recycle and clear the entry in the pending
193 // surfaces collection.
194 auto surface_to_recycle = std::move(found_in_pending->second);
195 pending_surfaces_.erase(found_in_pending);
196
197 RecycleSurface(std::move(surface_to_recycle));
198}
199
200void SoftwareSurfaceProducer::AgeAndCollectOldBuffers() {
201 TRACE_EVENT0("flutter", "SoftwareSurfacePool::AgeAndCollectOldBuffers");
202
203 // Remove all surfaces that are no longer valid or are too old.
204 size_t size_before = available_surfaces_.size();
205 available_surfaces_.erase(
206 std::remove_if(available_surfaces_.begin(), available_surfaces_.end(),
207 [&](auto& surface) {
208 return !surface->IsValid() ||
209 surface->AdvanceAndGetAge() >= kMaxSurfaceAge;
210 }),
211 available_surfaces_.end());
212 TRACE_EVENT1("flutter", "AgeAndCollect", "aged surfaces",
213 (size_before - available_surfaces_.size()));
214
215 TraceStats();
216}
217
218void SoftwareSurfaceProducer::TraceStats() {
219 // Resources held in cached buffers.
220 size_t cached_surfaces_bytes = 0;
221 for (const auto& surface : available_surfaces_) {
222 cached_surfaces_bytes += surface->GetAllocationSize();
223 }
224
225 TRACE_COUNTER("flutter", "SurfacePoolCounts", 0u, "CachedCount",
226 available_surfaces_.size(), //
227 "Created", trace_surfaces_created_, //
228 "Reused", trace_surfaces_reused_, //
229 "PendingInCompositor", pending_surfaces_.size(), //
230 "Retained", 0 //
231 );
232
233 TRACE_COUNTER("flutter", "SurfacePoolBytes", 0u, //
234 "CachedBytes", cached_surfaces_bytes, //
235 "RetainedBytes", 0 //
236 );
237
238 // Reset per present/frame stats.
239 trace_surfaces_created_ = 0;
240 trace_surfaces_reused_ = 0;
241}
242
243} // namespace flutter_runner
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:65
#define FML_LOG(severity)
Definition logging.h:101
#define FML_CHECK(condition)
Definition logging.h:104
#define FML_DCHECK(condition)
Definition logging.h:122
const char * name
Definition fuchsia.cc:49
static zx_koid_t GetCurrentProcessId()
static std::string GetCurrentProcessName()
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all 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
#define TRACE_EVENT0(category_group, name)
#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
#define TRACE_EVENT_INSTANT0(category_group, name)
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)