Flutter Engine
The Flutter Engine
vulkan_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/async/cpp/task.h>
8#include <lib/async/default.h>
9
10#include <memory>
11#include <string>
12#include <vector>
13
14#include "flutter/fml/trace_event.h"
15#include "flutter/vulkan/vulkan_skia_proc_table.h"
17
27
28namespace flutter_runner {
29
30namespace {
31
32// Tuning advice:
33// If you see the following 3 things happening simultaneously in a trace:
34// * Over budget ("flutter", "GPURasterizer::Draw") durations
35// * Many ("skia", "GrGpu::createTexture") events within the
36// "GPURasterizer::Draw"s
37// * The Skia GPU resource cache is full, as indicated by the
38// "SkiaCacheBytes" field in the ("flutter", "SurfacePool") trace counter
39// (compare it to the bytes value here)
40// then you should consider increasing the size of the GPU resource cache.
41constexpr size_t kGrCacheMaxByteSize = 1024 * 600 * 12 * 4;
42
43} // namespace
44
46 valid_ = Initialize();
47
48 if (!valid_) {
49 FML_LOG(FATAL) << "VulkanSurfaceProducer: Initialization failed";
50 }
51}
52
54 // Make sure queue is idle before we start destroying surfaces
55 if (valid_) {
56 VkResult wait_result = VK_CALL_LOG_ERROR(
57 vk_->QueueWaitIdle(logical_device_->GetQueueHandle()));
58 FML_DCHECK(wait_result == VK_SUCCESS);
59 }
60};
61
62bool VulkanSurfaceProducer::Initialize() {
63 vk_ = fml::MakeRefCounted<vulkan::VulkanProcTable>();
64
65 std::vector<std::string> extensions = {
67 };
68
69 // On Fuchsia, the validation layers need to be packaged as part of the
70 // flutter_runner in order to work. As a result, we can use the presence
71 // of the layers to mean that we want the layers enabled.
72 application_ = std::make_unique<vulkan::VulkanApplication>(
73 *vk_, "FlutterRunner", std::move(extensions), VK_MAKE_VERSION(1, 0, 0),
74 VK_MAKE_VERSION(1, 1, 0), true /* enable_validation_layers */);
75
76 if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) {
77 // Make certain the application instance was created and it set up the
78 // instance proc table entries.
79 FML_LOG(ERROR) << "VulkanSurfaceProducer: Instance proc addresses have not "
80 "been set up.";
81 return false;
82 }
83
84 // Create the device.
85
86 logical_device_ = application_->AcquireFirstCompatibleLogicalDevice();
87
88 if (logical_device_ == nullptr || !logical_device_->IsValid() ||
89 !vk_->AreDeviceProcsSetup()) {
90 // Make certain the device was created and it set up the device proc table
91 // entries.
93 << "VulkanSurfaceProducer: Device proc addresses have not been set up.";
94 return false;
95 }
96
99 << "VulkanSurfaceProducer: Failed to acquire mandatory proc addresses.";
100 return false;
101 }
102
103 if (!vk_->IsValid()) {
104 FML_LOG(ERROR) << "VulkanSurfaceProducer: VulkanProcTable invalid";
105 return false;
106 }
107
108 auto getProc = CreateSkiaGetProc(vk_);
109
110 if (getProc == nullptr) {
111 FML_LOG(ERROR) << "VulkanSurfaceProducer: Failed to create skia getProc.";
112 return false;
113 }
114
116 if (!logical_device_->GetPhysicalDeviceFeatures(&features)) {
118 << "VulkanSurfaceProducer: Failed to get physical device features.";
119
120 return false;
121 }
122
124 application_->GetAPIVersion(), application_->GetInstance(),
125 logical_device_->GetPhysicalDeviceHandle(), logical_device_->GetHandle(),
126 vk_, true);
127
128 GrVkBackendContext backend_context;
129 backend_context.fInstance = application_->GetInstance();
130 backend_context.fPhysicalDevice = logical_device_->GetPhysicalDeviceHandle();
131 backend_context.fDevice = logical_device_->GetHandle();
132 backend_context.fQueue = logical_device_->GetQueueHandle();
133 backend_context.fGraphicsQueueIndex =
134 logical_device_->GetGraphicsQueueIndex();
135 backend_context.fMaxAPIVersion = application_->GetAPIVersion();
136 backend_context.fDeviceFeatures = &features;
137 backend_context.fGetProc = std::move(getProc);
138 backend_context.fMemoryAllocator = memory_allocator_;
139
140 // The memory_requirements_2 extension is required on Fuchsia as the AMD
141 // memory allocator used by Skia benefit from it.
142 const char* device_extensions[] = {
144 };
145 const int device_extensions_count =
146 sizeof(device_extensions) / sizeof(device_extensions[0]);
147 skgpu::VulkanExtensions vk_extensions;
148 vk_extensions.init(backend_context.fGetProc, backend_context.fInstance,
149 backend_context.fPhysicalDevice, 0, nullptr,
150 device_extensions_count, device_extensions);
151 backend_context.fVkExtensions = &vk_extensions;
153 options.fReduceOpsTaskSplitting = GrContextOptions::Enable::kNo;
154
155 context_ = GrDirectContexts::MakeVulkan(backend_context, options);
156
157 if (context_ == nullptr) {
159 << "VulkanSurfaceProducer: Failed to create GrDirectContext.";
160 return false;
161 }
162
163 // Use local limits specified in this file above instead of flutter defaults.
165
166 surface_pool_ = std::make_unique<VulkanSurfacePool>(*this, context_);
167
168 return true;
169}
170
172 std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces) {
173 TRACE_EVENT0("flutter", "VulkanSurfaceProducer::SubmitSurfaces");
174
175 // Do a single flush for all canvases derived from the context.
176 {
177 TRACE_EVENT0("flutter", "GrDirectContext::flushAndSignalSemaphores");
178 context_->flushAndSubmit();
179 }
180
181 if (!TransitionSurfacesToExternal(surfaces))
182 FML_LOG(ERROR) << "TransitionSurfacesToExternal failed";
183
184 // Submit surface
185 for (auto& surface : surfaces) {
186 SubmitSurface(std::move(surface));
187 }
188
189 // Buffer management.
190 surface_pool_->AgeAndCollectOldBuffers();
191
192 // If no further surface production has taken place for 10 frames (TODO:
193 // Don't hardcode refresh rate here), then shrink our surface pool to fit.
194 constexpr auto kShouldShrinkThreshold = zx::msec(10 * 16.67);
195 async::PostDelayedTask(
196 async_get_default_dispatcher(),
197 [self = weak_factory_.GetWeakPtr(), kShouldShrinkThreshold] {
198 if (!self) {
199 return;
200 }
201 auto time_since_last_produce =
202 async::Now(async_get_default_dispatcher()) -
203 self->last_produce_time_;
204 if (time_since_last_produce >= kShouldShrinkThreshold) {
205 self->surface_pool_->ShrinkToFit();
206 }
207 },
208 kShouldShrinkThreshold);
209}
210
211bool VulkanSurfaceProducer::TransitionSurfacesToExternal(
212 const std::vector<std::unique_ptr<SurfaceProducerSurface>>& surfaces) {
213 for (auto& surface : surfaces) {
214 auto vk_surface = static_cast<VulkanSurface*>(surface.get());
215 if (!vk_surface) {
216 continue;
217 }
218
219 vulkan::VulkanCommandBuffer* command_buffer =
220 vk_surface->GetCommandBuffer(logical_device_->GetCommandPool());
221 if (!command_buffer->Begin())
222 return false;
223
225 vk_surface->GetSkiaSurface().get(),
227 if (!backendRT.isValid()) {
228 return false;
229 }
230 GrVkImageInfo imageInfo;
231 if (!GrBackendRenderTargets::GetVkImageInfo(backendRT, &imageInfo)) {
232 return false;
233 }
234
235 VkImageMemoryBarrier image_barrier = {
237 .pNext = nullptr,
239 .dstAccessMask = 0,
240 .oldLayout = imageInfo.fImageLayout,
241 // Understand why this is causing issues on Intel. TODO(fxb/53449)
242#if defined(__aarch64__)
243 .newLayout = imageInfo.fImageLayout,
244#else
245 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
246#endif
247 .srcQueueFamilyIndex = 0,
248 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR,
249 .image = vk_surface->GetVkImage(),
250 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
251
252 if (!command_buffer->InsertPipelineBarrier(
255 0, // dependencyFlags
256 0, nullptr, // memory barriers
257 0, nullptr, // buffer barriers
258 1, &image_barrier))
259 return false;
260
262 image_barrier.newLayout);
263
264 if (!command_buffer->End())
265 return false;
266
267 if (!logical_device_->QueueSubmit(
268 {}, {}, {vk_surface->GetAcquireVkSemaphore()},
269 {command_buffer->Handle()}, vk_surface->GetCommandBufferFence()))
270 return false;
271 }
272 return true;
273}
274
275std::unique_ptr<SurfaceProducerSurface> VulkanSurfaceProducer::ProduceSurface(
276 const SkISize& size) {
277 FML_CHECK(valid_);
278 last_produce_time_ = async::Now(async_get_default_dispatcher());
279 return surface_pool_->AcquireSurface(size);
280}
281
282void VulkanSurfaceProducer::SubmitSurface(
283 std::unique_ptr<SurfaceProducerSurface> surface) {
284 FML_CHECK(valid_);
285 surface_pool_->SubmitSurface(std::move(surface));
286}
287
288std::unique_ptr<SurfaceProducerSurface>
289VulkanSurfaceProducer::ProduceOffscreenSurface(const SkISize& size) {
290 return surface_pool_->CreateSurface(size);
291}
292
293} // namespace flutter_runner
const char * options
void flushAndSubmit(GrSyncCpu sync=GrSyncCpu::kNo)
void setResourceCacheLimit(size_t maxResourceBytes)
@ kFlushRead
back-end object is readable
static sk_sp< VulkanMemoryAllocator > Make(uint32_t vulkan_api_version, VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device, const fml::RefPtr< vulkan::VulkanProcTable > &vk, bool mustUseCoherentHostVisibleMemory)
void SubmitSurfaces(std::vector< std::unique_ptr< SurfaceProducerSurface > > surfaces) override
void init(VulkanGetProc, VkInstance, VkPhysicalDevice, uint32_t instanceExtensionCount, const char *const *instanceExtensions, uint32_t deviceExtensionCount, const char *const *deviceExtensions)
bool InsertPipelineBarrier(VkPipelineStageFlagBits src_stage_flags, VkPipelineStageFlagBits dest_stage_flags, uint32_t dependency_flags, uint32_t memory_barrier_count, const VkMemoryBarrier *memory_barriers, uint32_t buffer_memory_barrier_count, const VkBufferMemoryBarrier *buffer_memory_barriers, uint32_t image_memory_barrier_count, const VkImageMemoryBarrier *image_memory_barriers) const
bool HasAcquiredMandatoryProcAddresses() const
bool AreInstanceProcsSetup() const
VkSurfaceKHR surface
Definition: main.cc:49
#define FATAL(error)
if(end==-1)
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_CHECK(condition)
Definition: logging.h:85
#define FML_DCHECK(condition)
Definition: logging.h:103
SK_API bool GetVkImageInfo(const GrBackendRenderTarget &, GrVkImageInfo *)
SK_API void SetVkImageLayout(GrBackendRenderTarget *, VkImageLayout)
SK_API sk_sp< GrDirectContext > MakeVulkan(const skgpu::VulkanBackendContext &, const GrContextOptions &)
SK_API GrBackendRenderTarget GetBackendRenderTarget(SkSurface *, BackendHandleAccess)
static const size_t kGrCacheMaxByteSize
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
GrVkGetProc CreateSkiaGetProc(const fml::RefPtr< vulkan::VulkanProcTable > &vk)
VkImageLayout fImageLayout
Definition: GrVkTypes.h:29
Definition: SkSize.h:16
VkStructureType sType
Definition: vulkan_core.h:2936
VkImageLayout newLayout
Definition: vulkan_core.h:2941
sk_sp< VulkanMemoryAllocator > fMemoryAllocator
const VkPhysicalDeviceFeatures * fDeviceFeatures
const skgpu::VulkanExtensions * fVkExtensions
#define ERROR(message)
Definition: elf_loader.cc:260
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131
@ VK_IMAGE_LAYOUT_GENERAL
Definition: vulkan_core.h:1332
@ VK_IMAGE_ASPECT_COLOR_BIT
Definition: vulkan_core.h:2238
#define VK_MAKE_VERSION(major, minor, patch)
Definition: vulkan_core.h:78
#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME
Definition: vulkan_core.h:9396
VkResult
Definition: vulkan_core.h:140
@ VK_SUCCESS
Definition: vulkan_core.h:141
@ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
Definition: vulkan_core.h:2208
#define VK_QUEUE_FAMILY_EXTERNAL_KHR
Definition: vulkan_core.h:8709
#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME
Definition: vulkan_core.h:8762
@ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
Definition: vulkan_core.h:2445
@ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
Definition: vulkan_core.h:2448
@ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER
Definition: vulkan_core.h:247
#define VK_CALL_LOG_ERROR(expression)