forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvulkan_surface_pool.cc
180 lines (155 loc) · 6.31 KB
/
vulkan_surface_pool.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright 2017 The Fuchsia 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 <trace/event.h>
#include "flutter/content_handler/vulkan_surface_pool.h"
#include "flutter/glue/trace_event.h"
#include "third_party/skia/include/gpu/GrContext.h"
namespace flutter_runner {
VulkanSurfacePool::VulkanSurfacePool(vulkan::VulkanProvider& vulkan_provider,
sk_sp<GrContext> context,
sk_sp<GrVkBackendContext> backend_context,
scenic_lib::Session* mozart_session)
: vulkan_provider_(vulkan_provider),
context_(std::move(context)),
backend_context_(std::move(backend_context)),
mozart_session_(mozart_session) {}
VulkanSurfacePool::~VulkanSurfacePool() {}
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
VulkanSurfacePool::AcquireSurface(const SkISize& size) {
auto surface = GetCachedOrCreateSurface(size);
if (surface == nullptr) {
FXL_DLOG(ERROR) << "Could not acquire surface";
return nullptr;
}
if (!surface->FlushSessionAcquireAndReleaseEvents()) {
FXL_DLOG(ERROR) << "Could not flush acquire/release events for buffer.";
return nullptr;
}
return surface;
}
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
VulkanSurfacePool::GetCachedOrCreateSurface(const SkISize& size) {
auto found_in_available = available_surfaces_.find(size);
if (found_in_available == available_surfaces_.end()) {
return CreateSurface(size);
}
SurfacesSet& available_surfaces = found_in_available->second;
FXL_DCHECK(available_surfaces.size() > 0);
auto acquired_surface = std::move(available_surfaces.back());
available_surfaces.pop_back();
if (available_surfaces.size() == 0) {
available_surfaces_.erase(found_in_available);
}
if (acquired_surface->IsValid()) {
trace_surfaces_reused_++;
return acquired_surface;
}
// This is only likely to happen if the surface was invalidated between the
// time it was sent into the available buffers cache and accessed now.
// Extremely unlikely.
return CreateSurface(size);
}
void VulkanSurfacePool::SubmitSurface(
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
p_surface) {
TRACE_EVENT0("flutter", "VulkanSurfacePool::SubmitSurface");
if (!p_surface) {
return;
}
uintptr_t surface_key = reinterpret_cast<uintptr_t>(p_surface.get());
auto insert_iterator =
pending_surfaces_.insert(std::make_pair(surface_key, // key
std::move(p_surface) // value
));
if (insert_iterator.second) {
insert_iterator.first->second->SignalWritesFinished(
std::bind(&VulkanSurfacePool::RecycleSurface, this, surface_key));
}
}
std::unique_ptr<VulkanSurface> VulkanSurfacePool::CreateSurface(
const SkISize& size) {
auto surface = std::make_unique<VulkanSurface>(
vulkan_provider_, context_, backend_context_, mozart_session_, size);
if (!surface->IsValid()) {
return nullptr;
}
trace_surfaces_created_++;
return surface;
}
void VulkanSurfacePool::RecycleSurface(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()) {
return;
}
// Grab a hold of the surface to recycle and clear the entry in the pending
// surfaces collection.
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
surface_to_recycle = std::move(found_in_pending->second);
pending_surfaces_.erase(found_in_pending);
// The surface may have become invalid (for example it the fences could
// not be reset).
if (!surface_to_recycle->IsValid()) {
return;
}
// Recycle the buffer by putting it in the list of available surfaces if the
// maximum size of buffers in the collection is not already present.
auto& available_surfaces = available_surfaces_[surface_to_recycle->GetSize()];
if (available_surfaces.size() < kMaxSurfacesOfSameSize) {
available_surfaces.emplace_back(std::move(surface_to_recycle));
}
}
void VulkanSurfacePool::AgeAndCollectOldBuffers() {
std::vector<SkISize> sizes_to_erase;
for (auto& surface_iterator : available_surfaces_) {
SurfacesSet& old_surfaces = surface_iterator.second;
SurfacesSet new_surfaces;
for (auto& surface : old_surfaces) {
if (surface->AdvanceAndGetAge() < kMaxSurfaceAge) {
new_surfaces.emplace_back(std::move(surface));
}
}
if (new_surfaces.size() == 0) {
sizes_to_erase.emplace_back(surface_iterator.first);
}
old_surfaces.swap(new_surfaces);
}
for (const auto& size : sizes_to_erase) {
available_surfaces_.erase(size);
}
TraceStats();
}
void VulkanSurfacePool::TraceStats() {
// Resources held in cached buffers.
size_t cached_surfaces = 0;
size_t cached_surfaces_bytes = 0;
for (const auto& surfaces : available_surfaces_) {
const auto surface_count = surfaces.second.size();
cached_surfaces += surface_count;
// TODO(chinmaygarde): Assuming for now that all surfaces are 32bpp.
cached_surfaces_bytes +=
(surfaces.first.fWidth * surfaces.first.fHeight * 4 * surface_count);
}
// Resources held by Skia.
int skia_resources = 0;
size_t skia_bytes = 0;
context_->getResourceCacheUsage(&skia_resources, &skia_bytes);
const size_t skia_cache_purgeable =
context_->getResourceCachePurgeableBytes();
TRACE_COUNTER("flutter", "SurfacePool", 0u, //
"CachedCount", cached_surfaces, //
"CachedBytes", cached_surfaces_bytes, //
"Created", trace_surfaces_created_, //
"Reused", trace_surfaces_reused_, //
"PendingInCompositor", pending_surfaces_.size(), //
"SkiaCacheResources", skia_resources, //
"SkiaCacheBytes", skia_bytes, //
"SkiaCachePurgeable", skia_cache_purgeable //
);
// Reset per present/frame stats.
trace_surfaces_created_ = 0;
trace_surfaces_reused_ = 0;
}
} // namespace flutter_runner