7#include <fuchsia/sysmem/cpp/fidl.h>
8#include <lib/async/default.h>
15#include "third_party/skia/include/core/SkCanvas.h"
16#include "third_party/skia/include/core/SkColorSpace.h"
17#include "third_party/skia/include/core/SkSurfaceProps.h"
18#include "third_party/skia/include/gpu/ganesh/GrBackendSemaphore.h"
19#include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h"
20#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h"
21#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
22#include "third_party/skia/include/gpu/ganesh/vk/GrVkBackendSurface.h"
23#include "third_party/skia/include/gpu/ganesh/vk/GrVkTypes.h"
24#include "third_party/skia/include/gpu/vk/VulkanTypes.h"
25#include "vulkan/vulkan_core.h"
26#include "vulkan/vulkan_fuchsia.h"
28#define LOG_AND_RETURN(cond, msg) \
30 FML_LOG(ERROR) << msg; \
38constexpr SkColorType kSkiaColorType = kRGBA_8888_SkColorType;
39constexpr VkFormat kVulkanFormat = VK_FORMAT_R8G8B8A8_UNORM;
40constexpr VkImageCreateFlags kVulkanImageCreateFlags = 0;
42constexpr VkImageUsageFlags kVkImageUsage =
43 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
44 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
45const VkSysmemColorSpaceFUCHSIA kSrgbColorSpace = {
46 .sType = VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA,
48 .colorSpace =
static_cast<uint32_t
>(fuchsia::images2::ColorSpace::SRGB),
55 VulkanImage* out_vulkan_image) {
61 out_vulkan_image->vk_collection_image_create_info = {
62 .sType = VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA,
64 .collection = collection_,
68 out_vulkan_image->vk_image_create_info = {
69 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
70 .pNext = &out_vulkan_image->vk_collection_image_create_info,
71 .flags = kVulkanImageCreateFlags,
72 .imageType = VK_IMAGE_TYPE_2D,
73 .format = kVulkanFormat,
74 .extent = VkExtent3D{
static_cast<uint32_t
>(size.width()),
75 static_cast<uint32_t
>(size.height()), 1},
78 .samples = VK_SAMPLE_COUNT_1_BIT,
79 .tiling = VK_IMAGE_TILING_OPTIMAL,
80 .usage = kVkImageUsage,
81 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
82 .queueFamilyIndexCount = 0,
83 .pQueueFamilyIndices =
nullptr,
84 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
87 const VkImageFormatConstraintsInfoFUCHSIA format_constraints = {
88 .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA,
90 .imageCreateInfo = out_vulkan_image->vk_image_create_info,
91 .requiredFormatFeatures = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,
93 .sysmemPixelFormat = {},
95 .pColorSpaces = &kSrgbColorSpace,
98 const VkImageConstraintsInfoFUCHSIA image_constraints = {
99 .sType = VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA,
101 .formatConstraintsCount = 1,
102 .pFormatConstraints = &format_constraints,
103 .bufferCollectionConstraints =
106 VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA,
112 .minBufferCountForCamping = 0,
113 .minBufferCountForDedicatedSlack = 0,
114 .minBufferCountForSharedSlack = 0,
120 vulkan_provider.
vk().SetBufferCollectionImageConstraintsFUCHSIA(
121 vulkan_provider.
vk_device(), collection_, &image_constraints)) !=
127 VkImage vk_image = VK_NULL_HANDLE;
130 &out_vulkan_image->vk_image_create_info,
nullptr, &vk_image)) !=
136 vk_image, [&vulkan_provider = vulkan_provider](VkImage
image) {
137 vulkan_provider.vk().DestroyImage(vulkan_provider.vk_device(),
image,
142 vulkan_provider.
vk().GetImageMemoryRequirements(
143 vulkan_provider.
vk_device(), out_vulkan_image->vk_image,
144 &out_vulkan_image->vk_memory_requirements);
151 fuchsia::sysmem2::AllocatorSyncPtr& sysmem_allocator,
152 fuchsia::ui::composition::AllocatorPtr& flatland_allocator,
153 sk_sp<GrDirectContext> context,
155 : vulkan_provider_(vulkan_provider), wait_(this) {
156 FML_CHECK(flatland_allocator.is_bound());
159 if (!AllocateDeviceMemory(sysmem_allocator, flatland_allocator,
160 std::move(context), size)) {
161 FML_LOG(ERROR) <<
"VulkanSurface: Could not allocate device memory.";
165 if (!CreateFences()) {
166 FML_LOG(ERROR) <<
"VulkanSurface: Could not create signal fences.";
170 std::fill(size_history_.begin(), size_history_.end(), SkISize::MakeEmpty());
172 wait_.set_object(release_event_.get());
173 wait_.set_trigger(ZX_EVENT_SIGNALED);
180 if (release_image_callback_) {
181 release_image_callback_();
184 wait_.set_object(ZX_HANDLE_INVALID);
193 return SkISize::Make(0, 0);
196 return SkISize::Make(sk_surface_->width(), sk_surface_->height());
200 const zx::event& event)
const {
202 VkSemaphore semaphore;
204 zx::event semaphore_event;
205 zx_status_t status =
event.duplicate(ZX_RIGHT_SAME_RIGHTS, &semaphore_event);
206 if (status != ZX_OK) {
207 FML_LOG(ERROR) <<
"VulkanSurface: Failed to duplicate semaphore event";
211 VkSemaphoreCreateInfo create_info = {
212 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
218 vulkan_provider_.
vk_device(), &create_info,
nullptr, &semaphore));
219 if (result != VK_SUCCESS) {
223 VkImportSemaphoreZirconHandleInfoFUCHSIA import_info = {
224 .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA,
226 .semaphore = semaphore,
227 .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,
228 .zirconHandle =
static_cast<uint32_t
>(semaphore_event.release())};
231 vulkan_provider_.
vk().ImportSemaphoreZirconHandleFUCHSIA(
232 vulkan_provider_.
vk_device(), &import_info));
233 if (result != VK_SUCCESS) {
238 semaphore, [&vulkan_provider = vulkan_provider_](VkSemaphore semaphore) {
239 vulkan_provider.
vk().DestroySemaphore(vulkan_provider.
vk_device(),
244bool VulkanSurface::CreateFences() {
245 if (zx::event::create(0, &acquire_event_) != ZX_OK) {
246 FML_LOG(ERROR) <<
"VulkanSurface: Failed to create acquire event";
250 acquire_semaphore_ = SemaphoreFromEvent(acquire_event_);
251 if (!acquire_semaphore_) {
252 FML_LOG(ERROR) <<
"VulkanSurface: Failed to create acquire semaphore";
256 if (zx::event::create(0, &release_event_) != ZX_OK) {
257 FML_LOG(ERROR) <<
"VulkanSurface: Failed to create release event";
261 command_buffer_fence_ = vulkan_provider_.
CreateFence();
266bool VulkanSurface::AllocateDeviceMemory(
267 fuchsia::sysmem2::AllocatorSyncPtr& sysmem_allocator,
268 fuchsia::ui::composition::AllocatorPtr& flatland_allocator,
269 sk_sp<GrDirectContext> context,
270 const SkISize& size) {
271 if (
size.isEmpty()) {
273 <<
"VulkanSurface: Failed to allocate surface, size is empty";
277 fuchsia::sysmem2::BufferCollectionTokenSyncPtr vulkan_token;
278 zx_status_t status = sysmem_allocator->AllocateSharedCollection(
279 std::move(fuchsia::sysmem2::AllocatorAllocateSharedCollectionRequest{}
280 .set_token_request(vulkan_token.NewRequest())));
282 "VulkanSurface: Failed to allocate collection");
283 fuchsia::sysmem2::BufferCollectionTokenSyncPtr scenic_token;
284 status = vulkan_token->Duplicate(
285 std::move(fuchsia::sysmem2::BufferCollectionTokenDuplicateRequest{}
286 .set_rights_attenuation_mask(ZX_RIGHT_SAME_RIGHTS)
287 .set_token_request(scenic_token.NewRequest())));
289 "VulkanSurface: Failed to duplicate collection token");
290 fuchsia::sysmem2::Node_Sync_Result sync_result;
291 status = vulkan_token->Sync(&sync_result);
293 "VulkanSurface: Failed to sync collection token");
295 fuchsia::ui::composition::BufferCollectionExportToken export_token;
296 status = zx::eventpair::create(0, &export_token.value, &import_token_.value);
298 fuchsia::ui::composition::RegisterBufferCollectionArgs
args;
299 args.set_export_token(std::move(export_token));
300 args.set_buffer_collection_token2(std::move(scenic_token));
302 fuchsia::ui::composition::RegisterBufferCollectionUsage::DEFAULT);
303 flatland_allocator->RegisterBufferCollection(
305 [](fuchsia::ui::composition::Allocator_RegisterBufferCollection_Result
307 if (result.is_err()) {
309 <<
"RegisterBufferCollection call to Scenic Allocator failed";
313 VkBufferCollectionCreateInfoFUCHSIA import_info{
314 .sType = VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA,
316 .collectionToken = vulkan_token.Unbind().TakeChannel().release(),
318 VkBufferCollectionFUCHSIA collection;
320 vulkan_provider_.
vk_device(), &import_info,
nullptr, &collection)) !=
326 collection, [&vulkan_provider =
327 vulkan_provider_](VkBufferCollectionFUCHSIA collection) {
328 vulkan_provider.vk().DestroyBufferCollectionFUCHSIA(
329 vulkan_provider.vk_device(), collection,
nullptr);
332 VulkanImage vulkan_image;
333 LOG_AND_RETURN(!CreateVulkanImage(vulkan_provider_, size, &vulkan_image),
334 "VulkanSurface: Failed to create VkImage");
336 vulkan_image_ = std::move(vulkan_image);
337 const VkMemoryRequirements& memory_requirements =
341 VkBufferCollectionPropertiesFUCHSIA properties{
342 .sType = VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA};
344 vulkan_provider_.
vk().GetBufferCollectionPropertiesFUCHSIA(
345 vulkan_provider_.
vk_device(), collection_, &properties)) !=
350 VkImportMemoryBufferCollectionFUCHSIA import_memory_info = {
351 .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA,
353 .collection = collection_,
356 auto bits = memory_requirements.memoryTypeBits & properties.memoryTypeBits;
358 VkMemoryAllocateInfo allocation_info = {
359 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
360 .pNext = &import_memory_info,
361 .allocationSize = memory_requirements.size,
362 .memoryTypeIndex =
static_cast<uint32_t
>(__builtin_ctz(bits)),
366 TRACE_EVENT1(
"flutter",
"vkAllocateMemory",
"allocationSize",
367 allocation_info.allocationSize);
368 VkDeviceMemory vk_memory = VK_NULL_HANDLE;
370 vulkan_provider_.
vk_device(), &allocation_info, NULL,
371 &vk_memory)) != VK_SUCCESS) {
377 [&vulkan_provider = vulkan_provider_](VkDeviceMemory memory) {
378 vulkan_provider.vk().FreeMemory(vulkan_provider.vk_device(), memory,
382 vk_memory_info_ = allocation_info;
392 return SetupSkiaSurface(std::move(context), size, kSkiaColorType,
393 image_create_info, memory_requirements);
396bool VulkanSurface::SetupSkiaSurface(sk_sp<GrDirectContext> context,
399 const VkImageCreateInfo& image_create_info,
400 const VkMemoryRequirements& memory_reqs) {
403 skgpu::VulkanAlloc alloc;
404 alloc.fMemory = vk_memory_;
406 alloc.fSize = memory_reqs.size;
409 GrVkImageInfo image_info;
410 image_info.fImage = vulkan_image_.
vk_image;
411 image_info.fAlloc = alloc;
412 image_info.fImageTiling = image_create_info.tiling;
413 image_info.fImageLayout = image_create_info.initialLayout;
414 image_info.fFormat = image_create_info.format;
415 image_info.fImageUsageFlags = image_create_info.usage;
416 image_info.fSampleCount = 1;
417 image_info.fLevelCount = image_create_info.mipLevels;
419 auto sk_render_target =
420 GrBackendRenderTargets::MakeVk(
size.width(),
size.height(), image_info);
422 SkSurfaceProps sk_surface_props(0, kUnknown_SkPixelGeometry);
425 SkSurfaces::WrapBackendRenderTarget(context.get(),
427 kTopLeft_GrSurfaceOrigin,
429 SkColorSpace::MakeSRGB(),
433 if (!sk_surface || sk_surface->getCanvas() ==
nullptr) {
435 <<
"VulkanSurface: SkSurfaces::WrapBackendRenderTarget failed";
438 sk_surface_ = std::move(sk_surface);
445 image_id_ = image_id;
453 return valid_ ? sk_surface_ :
nullptr;
456fuchsia::ui::composition::BufferCollectionImportToken
458 fuchsia::ui::composition::BufferCollectionImportToken import_dup;
459 import_token_.value.duplicate(ZX_RIGHT_SAME_RIGHTS, &import_dup.value);
465 acquire_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence);
471 release_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence);
476 release_image_callback_ = release_image_callback;
480 size_history_[size_history_index_] =
GetSize();
481 size_history_index_ = (size_history_index_ + 1) % kSizeHistorySize;
492 const std::function<
void(
void)>& on_writes_committed) {
496 on_writes_committed();
500 FML_CHECK(pending_on_writes_committed_ ==
nullptr)
501 <<
"Attempted to signal a write on the surface when the "
502 "previous write has not yet been acknowledged by the "
505 pending_on_writes_committed_ = on_writes_committed;
508void VulkanSurface::Reset() {
509 if (acquire_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK ||
510 release_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK) {
512 FML_LOG(ERROR) <<
"Could not reset fences. The surface is no longer valid.";
515 VkFence fence = command_buffer_fence_;
517 if (command_buffer_) {
519 vulkan_provider_.
vk_device(), 1, &fence, VK_TRUE, UINT64_MAX));
520 command_buffer_.reset();
524 vulkan_provider_.
vk_device(), 1, &fence));
528 acquire_semaphore_.
Reset();
529 acquire_semaphore_ = SemaphoreFromEvent(acquire_event_);
530 if (!acquire_semaphore_) {
531 FML_LOG(ERROR) <<
"failed to create acquire semaphore";
534 wait_.Begin(async_get_default_dispatcher());
537 auto callback = pending_on_writes_committed_;
538 pending_on_writes_committed_ =
nullptr;
544void VulkanSurface::OnHandleReady(async_dispatcher_t* dispatcher,
545 async::WaitBase* wait,
547 const zx_packet_signal_t* signal) {
550 FML_DCHECK(signal->observed & ZX_EVENT_SIGNALED);
void SetReleaseImageCallback(ReleaseImageCallback release_image_callback) override
fuchsia::ui::composition::BufferCollectionImportToken GetBufferCollectionImportToken() override
bool IsValid() const override
zx::event GetAcquireFence() override
~VulkanSurface() override
void SignalWritesFinished(const std::function< void(void)> &on_writes_committed) override
SkISize GetSize() const override
bool FlushSessionAcquireAndReleaseEvents() override
uint32_t GetImageId() override
void SetImageId(uint32_t image_id) override
VulkanSurface(vulkan::VulkanProvider &vulkan_provider, fuchsia::sysmem2::AllocatorSyncPtr &sysmem_allocator, fuchsia::ui::composition::AllocatorPtr &flatland_allocator, sk_sp< GrDirectContext > context, const SkISize &size)
size_t AdvanceAndGetAge() override
sk_sp< SkSurface > GetSkiaSurface() const override
zx::event GetReleaseFence() override
vulkan::VulkanHandle< VkFence > CreateFence()
virtual const vulkan::VulkanProcTable & vk()=0
virtual const vulkan::VulkanHandle< VkDevice > & vk_device()=0
FlutterVulkanImage * image
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlutterDesktopBinaryReply callback
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define FML_DCHECK(condition)
std::function< void()> ReleaseImageCallback
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
VkImageCreateInfo vk_image_create_info
VkMemoryRequirements vk_memory_requirements
vulkan::VulkanHandle< VkImage > vk_image
#define TRACE_EVENT0(category_group, name)
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
#define VK_CALL_LOG_FATAL(expression)
#define VK_CALL_LOG_ERROR(expression)