Flutter Engine
The Flutter Engine
vulkan_surface.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
5#include "vulkan_surface.h"
6
7#include <fuchsia/sysmem/cpp/fidl.h>
8#include <lib/async/default.h>
9
10#include <algorithm>
11
12#include "flutter/fml/logging.h"
13#include "flutter/fml/trace_event.h"
24#include "vulkan/vulkan_core.h"
25#include "vulkan/vulkan_fuchsia.h"
26
27#define LOG_AND_RETURN(cond, msg) \
28 if (cond) { \
29 FML_LOG(ERROR) << msg; \
30 return false; \
31 }
32
33namespace flutter_runner {
34
35namespace {
36
37constexpr SkColorType kSkiaColorType = kRGBA_8888_SkColorType;
38constexpr VkFormat kVulkanFormat = VK_FORMAT_R8G8B8A8_UNORM;
39constexpr VkImageCreateFlags kVulkanImageCreateFlags = 0;
40// TODO: We should only keep usages that are actually required by Skia.
41constexpr VkImageUsageFlags kVkImageUsage =
44const VkSysmemColorSpaceFUCHSIA kSrgbColorSpace = {
46 .pNext = nullptr,
47 .colorSpace = static_cast<uint32_t>(fuchsia::sysmem::ColorSpaceType::SRGB),
48};
49
50} // namespace
51
52bool VulkanSurface::CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider,
53 const SkISize& size,
54 VulkanImage* out_vulkan_image) {
55 TRACE_EVENT0("flutter", "CreateVulkanImage");
56
57 FML_CHECK(!size.isEmpty());
58 FML_CHECK(out_vulkan_image != nullptr);
59
60 out_vulkan_image->vk_collection_image_create_info = {
62 .pNext = nullptr,
63 .collection = collection_,
64 .index = 0,
65 };
66
67 out_vulkan_image->vk_image_create_info = {
69 .pNext = &out_vulkan_image->vk_collection_image_create_info,
70 .flags = kVulkanImageCreateFlags,
71 .imageType = VK_IMAGE_TYPE_2D,
72 .format = kVulkanFormat,
73 .extent = VkExtent3D{static_cast<uint32_t>(size.width()),
74 static_cast<uint32_t>(size.height()), 1},
75 .mipLevels = 1,
76 .arrayLayers = 1,
77 .samples = VK_SAMPLE_COUNT_1_BIT,
79 .usage = kVkImageUsage,
80 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
81 .queueFamilyIndexCount = 0,
82 .pQueueFamilyIndices = nullptr,
83 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
84 };
85
86 const VkImageFormatConstraintsInfoFUCHSIA format_constraints = {
88 .pNext = nullptr,
89 .imageCreateInfo = out_vulkan_image->vk_image_create_info,
90 .requiredFormatFeatures = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,
91 .flags = {},
92 .sysmemPixelFormat = {},
93 .colorSpaceCount = 1,
94 .pColorSpaces = &kSrgbColorSpace,
95 };
96
97 const VkImageConstraintsInfoFUCHSIA image_constraints = {
99 .pNext = nullptr,
100 .formatConstraintsCount = 1,
101 .pFormatConstraints = &format_constraints,
102 .bufferCollectionConstraints =
103 {
104 .sType =
106 .pNext = nullptr,
107 .minBufferCount = 1,
108 // Using the default value 0 means that we don't have any other
109 // constraints except for the minimum buffer count.
110 .maxBufferCount = 0,
111 .minBufferCountForCamping = 0,
112 .minBufferCountForDedicatedSlack = 0,
113 .minBufferCountForSharedSlack = 0,
114 },
115 .flags = {},
116 };
117
119 vulkan_provider.vk().SetBufferCollectionImageConstraintsFUCHSIA(
120 vulkan_provider.vk_device(), collection_, &image_constraints)) !=
121 VK_SUCCESS) {
122 return false;
123 }
124
125 {
126 VkImage vk_image = VK_NULL_HANDLE;
127 if (VK_CALL_LOG_ERROR(vulkan_provider.vk().CreateImage(
128 vulkan_provider.vk_device(),
129 &out_vulkan_image->vk_image_create_info, nullptr, &vk_image)) !=
130 VK_SUCCESS) {
131 return false;
132 }
133
134 out_vulkan_image->vk_image = vulkan::VulkanHandle<VkImage_T*>{
135 vk_image, [&vulkan_provider = vulkan_provider](VkImage image) {
136 vulkan_provider.vk().DestroyImage(vulkan_provider.vk_device(), image,
137 NULL);
138 }};
139 }
140
141 vulkan_provider.vk().GetImageMemoryRequirements(
142 vulkan_provider.vk_device(), out_vulkan_image->vk_image,
143 &out_vulkan_image->vk_memory_requirements);
144
145 return true;
146}
147
149 vulkan::VulkanProvider& vulkan_provider,
150 fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
151 fuchsia::ui::composition::AllocatorPtr& flatland_allocator,
153 const SkISize& size)
154 : vulkan_provider_(vulkan_provider), wait_(this) {
155 FML_CHECK(flatland_allocator.is_bound());
156 FML_CHECK(context != nullptr);
157
158 if (!AllocateDeviceMemory(sysmem_allocator, flatland_allocator,
159 std::move(context), size)) {
160 FML_LOG(ERROR) << "VulkanSurface: Could not allocate device memory.";
161 return;
162 }
163
164 if (!CreateFences()) {
165 FML_LOG(ERROR) << "VulkanSurface: Could not create signal fences.";
166 return;
167 }
168
169 std::fill(size_history_.begin(), size_history_.end(), SkISize::MakeEmpty());
170
171 wait_.set_object(release_event_.get());
172 wait_.set_trigger(ZX_EVENT_SIGNALED);
173 Reset();
174
175 valid_ = true;
176}
177
179 if (release_image_callback_) {
180 release_image_callback_();
181 }
182 wait_.Cancel();
183 wait_.set_object(ZX_HANDLE_INVALID);
184}
185
187 return valid_;
188}
189
191 if (!valid_) {
192 return SkISize::Make(0, 0);
193 }
194
195 return SkISize::Make(sk_surface_->width(), sk_surface_->height());
196}
197
198vulkan::VulkanHandle<VkSemaphore> VulkanSurface::SemaphoreFromEvent(
199 const zx::event& event) const {
201 VkSemaphore semaphore;
202
203 zx::event semaphore_event;
204 zx_status_t status = event.duplicate(ZX_RIGHT_SAME_RIGHTS, &semaphore_event);
205 if (status != ZX_OK) {
206 FML_LOG(ERROR) << "VulkanSurface: Failed to duplicate semaphore event";
208 }
209
210 VkSemaphoreCreateInfo create_info = {
212 .pNext = nullptr,
213 .flags = 0,
214 };
215
216 result = VK_CALL_LOG_ERROR(vulkan_provider_.vk().CreateSemaphore(
217 vulkan_provider_.vk_device(), &create_info, nullptr, &semaphore));
218 if (result != VK_SUCCESS) {
220 }
221
222 VkImportSemaphoreZirconHandleInfoFUCHSIA import_info = {
224 .pNext = nullptr,
225 .semaphore = semaphore,
227 .zirconHandle = static_cast<uint32_t>(semaphore_event.release())};
228
230 vulkan_provider_.vk().ImportSemaphoreZirconHandleFUCHSIA(
231 vulkan_provider_.vk_device(), &import_info));
232 if (result != VK_SUCCESS) {
234 }
235
237 semaphore, [&vulkan_provider = vulkan_provider_](VkSemaphore semaphore) {
238 vulkan_provider.vk().DestroySemaphore(vulkan_provider.vk_device(),
239 semaphore, nullptr);
240 });
241}
242
243bool VulkanSurface::CreateFences() {
244 if (zx::event::create(0, &acquire_event_) != ZX_OK) {
245 FML_LOG(ERROR) << "VulkanSurface: Failed to create acquire event";
246 return false;
247 }
248
249 acquire_semaphore_ = SemaphoreFromEvent(acquire_event_);
250 if (!acquire_semaphore_) {
251 FML_LOG(ERROR) << "VulkanSurface: Failed to create acquire semaphore";
252 return false;
253 }
254
255 if (zx::event::create(0, &release_event_) != ZX_OK) {
256 FML_LOG(ERROR) << "VulkanSurface: Failed to create release event";
257 return false;
258 }
259
260 command_buffer_fence_ = vulkan_provider_.CreateFence();
261
262 return true;
263}
264
265bool VulkanSurface::AllocateDeviceMemory(
266 fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
267 fuchsia::ui::composition::AllocatorPtr& flatland_allocator,
269 const SkISize& size) {
270 if (size.isEmpty()) {
272 << "VulkanSurface: Failed to allocate surface, size is empty";
273 return false;
274 }
275
276 fuchsia::sysmem::BufferCollectionTokenSyncPtr vulkan_token;
277 zx_status_t status =
278 sysmem_allocator->AllocateSharedCollection(vulkan_token.NewRequest());
279 LOG_AND_RETURN(status != ZX_OK,
280 "VulkanSurface: Failed to allocate collection");
281 fuchsia::sysmem::BufferCollectionTokenSyncPtr scenic_token;
282 status = vulkan_token->Duplicate(std::numeric_limits<uint32_t>::max(),
283 scenic_token.NewRequest());
284 LOG_AND_RETURN(status != ZX_OK,
285 "VulkanSurface: Failed to duplicate collection token");
286 status = vulkan_token->Sync();
287 LOG_AND_RETURN(status != ZX_OK,
288 "VulkanSurface: Failed to sync collection token");
289
290 fuchsia::ui::composition::BufferCollectionExportToken export_token;
291 status = zx::eventpair::create(0, &export_token.value, &import_token_.value);
292
293 fuchsia::ui::composition::RegisterBufferCollectionArgs args;
294 args.set_export_token(std::move(export_token));
295 args.set_buffer_collection_token(std::move(scenic_token));
296 args.set_usage(
297 fuchsia::ui::composition::RegisterBufferCollectionUsage::DEFAULT);
298 flatland_allocator->RegisterBufferCollection(
299 std::move(args),
300 [](fuchsia::ui::composition::Allocator_RegisterBufferCollection_Result
301 result) {
302 if (result.is_err()) {
303 FML_LOG(ERROR)
304 << "RegisterBufferCollection call to Scenic Allocator failed";
305 }
306 });
307
308 VkBufferCollectionCreateInfoFUCHSIA import_info{
310 .pNext = nullptr,
311 .collectionToken = vulkan_token.Unbind().TakeChannel().release(),
312 };
313 VkBufferCollectionFUCHSIA collection;
314 if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().CreateBufferCollectionFUCHSIA(
315 vulkan_provider_.vk_device(), &import_info, nullptr, &collection)) !=
316 VK_SUCCESS) {
317 return false;
318 }
319
321 collection, [&vulkan_provider =
322 vulkan_provider_](VkBufferCollectionFUCHSIA collection) {
323 vulkan_provider.vk().DestroyBufferCollectionFUCHSIA(
324 vulkan_provider.vk_device(), collection, nullptr);
325 }};
326
327 VulkanImage vulkan_image;
328 LOG_AND_RETURN(!CreateVulkanImage(vulkan_provider_, size, &vulkan_image),
329 "VulkanSurface: Failed to create VkImage");
330
331 vulkan_image_ = std::move(vulkan_image);
332 const VkMemoryRequirements& memory_requirements =
333 vulkan_image_.vk_memory_requirements;
334 VkImageCreateInfo& image_create_info = vulkan_image_.vk_image_create_info;
335
336 VkBufferCollectionPropertiesFUCHSIA properties{
339 vulkan_provider_.vk().GetBufferCollectionPropertiesFUCHSIA(
340 vulkan_provider_.vk_device(), collection_, &properties)) !=
341 VK_SUCCESS) {
342 return false;
343 }
344
345 VkImportMemoryBufferCollectionFUCHSIA import_memory_info = {
347 .pNext = nullptr,
348 .collection = collection_,
349 .index = 0,
350 };
351 auto bits = memory_requirements.memoryTypeBits & properties.memoryTypeBits;
352 FML_DCHECK(bits != 0);
353 VkMemoryAllocateInfo allocation_info = {
355 .pNext = &import_memory_info,
356 .allocationSize = memory_requirements.size,
357 .memoryTypeIndex = static_cast<uint32_t>(__builtin_ctz(bits)),
358 };
359
360 {
361 TRACE_EVENT1("flutter", "vkAllocateMemory", "allocationSize",
362 allocation_info.allocationSize);
363 VkDeviceMemory vk_memory = VK_NULL_HANDLE;
364 if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().AllocateMemory(
365 vulkan_provider_.vk_device(), &allocation_info, NULL,
366 &vk_memory)) != VK_SUCCESS) {
367 return false;
368 }
369
371 vk_memory,
372 [&vulkan_provider = vulkan_provider_](VkDeviceMemory memory) {
373 vulkan_provider.vk().FreeMemory(vulkan_provider.vk_device(), memory,
374 NULL);
375 }};
376
377 vk_memory_info_ = allocation_info;
378 }
379
380 // Bind image memory.
381 if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().BindImageMemory(
382 vulkan_provider_.vk_device(), vulkan_image_.vk_image, vk_memory_,
383 0)) != VK_SUCCESS) {
384 return false;
385 }
386
387 return SetupSkiaSurface(std::move(context), size, kSkiaColorType,
388 image_create_info, memory_requirements);
389}
390
391bool VulkanSurface::SetupSkiaSurface(sk_sp<GrDirectContext> context,
392 const SkISize& size,
394 const VkImageCreateInfo& image_create_info,
395 const VkMemoryRequirements& memory_reqs) {
396 FML_CHECK(context != nullptr);
397
398 skgpu::VulkanAlloc alloc;
399 alloc.fMemory = vk_memory_;
400 alloc.fOffset = 0;
401 alloc.fSize = memory_reqs.size;
402 alloc.fFlags = 0;
403
404 GrVkImageInfo image_info;
405 image_info.fImage = vulkan_image_.vk_image;
406 image_info.fAlloc = alloc;
407 image_info.fImageTiling = image_create_info.tiling;
408 image_info.fImageLayout = image_create_info.initialLayout;
409 image_info.fFormat = image_create_info.format;
410 image_info.fImageUsageFlags = image_create_info.usage;
411 image_info.fSampleCount = 1;
412 image_info.fLevelCount = image_create_info.mipLevels;
413
414 auto sk_render_target =
415 GrBackendRenderTargets::MakeVk(size.width(), size.height(), image_info);
416
417 SkSurfaceProps sk_surface_props(0, kUnknown_SkPixelGeometry);
418
419 auto sk_surface =
421 sk_render_target, //
423 color_type, //
425 &sk_surface_props //
426 );
427
428 if (!sk_surface || sk_surface->getCanvas() == nullptr) {
430 << "VulkanSurface: SkSurfaces::WrapBackendRenderTarget failed";
431 return false;
432 }
433 sk_surface_ = std::move(sk_surface);
434
435 return true;
436}
437
438void VulkanSurface::SetImageId(uint32_t image_id) {
439 FML_CHECK(image_id_ == 0);
440 image_id_ = image_id;
441}
442
444 return image_id_;
445}
446
448 return valid_ ? sk_surface_ : nullptr;
449}
450
451fuchsia::ui::composition::BufferCollectionImportToken
453 fuchsia::ui::composition::BufferCollectionImportToken import_dup;
454 import_token_.value.duplicate(ZX_RIGHT_SAME_RIGHTS, &import_dup.value);
455 return import_dup;
456}
457
459 zx::event fence;
460 acquire_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence);
461 return fence;
462}
463
465 zx::event fence;
466 release_event_.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence);
467 return fence;
468}
470 ReleaseImageCallback release_image_callback) {
471 release_image_callback_ = release_image_callback;
472}
473
475 size_history_[size_history_index_] = GetSize();
476 size_history_index_ = (size_history_index_ + 1) % kSizeHistorySize;
477 age_++;
478 return age_;
479}
480
482 age_ = 0;
483 return true;
484}
485
487 const std::function<void(void)>& on_writes_committed) {
488 FML_CHECK(on_writes_committed);
489
490 if (!valid_) {
491 on_writes_committed();
492 return;
493 }
494
495 FML_CHECK(pending_on_writes_committed_ == nullptr)
496 << "Attempted to signal a write on the surface when the "
497 "previous write has not yet been acknowledged by the "
498 "compositor.";
499
500 pending_on_writes_committed_ = on_writes_committed;
501}
502
503void VulkanSurface::Reset() {
504 if (acquire_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK ||
505 release_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK) {
506 valid_ = false;
507 FML_LOG(ERROR) << "Could not reset fences. The surface is no longer valid.";
508 }
509
510 VkFence fence = command_buffer_fence_;
511
512 if (command_buffer_) {
513 VK_CALL_LOG_FATAL(vulkan_provider_.vk().WaitForFences(
514 vulkan_provider_.vk_device(), 1, &fence, VK_TRUE, UINT64_MAX));
515 command_buffer_.reset();
516 }
517
518 VK_CALL_LOG_ERROR(vulkan_provider_.vk().ResetFences(
519 vulkan_provider_.vk_device(), 1, &fence));
520
521 // Need to make a new acquire semaphore every frame or else validation layers
522 // get confused about why no one is waiting on it in this VkInstance
523 acquire_semaphore_.Reset();
524 acquire_semaphore_ = SemaphoreFromEvent(acquire_event_);
525 if (!acquire_semaphore_) {
526 FML_LOG(ERROR) << "failed to create acquire semaphore";
527 }
528
529 wait_.Begin(async_get_default_dispatcher());
530
531 // It is safe for the caller to collect the surface in the callback.
532 auto callback = pending_on_writes_committed_;
533 pending_on_writes_committed_ = nullptr;
534 if (callback) {
535 callback();
536 }
537}
538
539void VulkanSurface::OnHandleReady(async_dispatcher_t* dispatcher,
540 async::WaitBase* wait,
541 zx_status_t status,
542 const zx_packet_signal_t* signal) {
543 if (status != ZX_OK)
544 return;
545 FML_DCHECK(signal->observed & ZX_EVENT_SIGNALED);
546 Reset();
547}
548
549} // namespace flutter_runner
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
SkColorType
Definition: SkColorType.h:19
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kUnknown_SkPixelGeometry
static sk_sp< SkColorSpace > MakeSRGB()
int width() const
Definition: SkSurface.h:178
int height() const
Definition: SkSurface.h:184
void SetReleaseImageCallback(ReleaseImageCallback release_image_callback) override
fuchsia::ui::composition::BufferCollectionImportToken GetBufferCollectionImportToken() override
bool IsValid() const override
zx::event GetAcquireFence() 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
size_t AdvanceAndGetAge() override
sk_sp< SkSurface > GetSkiaSurface() const override
zx::event GetReleaseFence() override
VulkanSurface(vulkan::VulkanProvider &vulkan_provider, fuchsia::sysmem::AllocatorSyncPtr &sysmem_allocator, fuchsia::ui::composition::AllocatorPtr &flatland_allocator, sk_sp< GrDirectContext > context, const SkISize &size)
T * get() const
Definition: SkRefCnt.h:303
vulkan::VulkanHandle< VkFence > CreateFence()
virtual const vulkan::VulkanProcTable & vk()=0
virtual const vulkan::VulkanHandle< VkDevice > & vk_device()=0
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyEvent * event
GAsyncResult * result
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_CHECK(condition)
Definition: logging.h:85
#define FML_DCHECK(condition)
Definition: logging.h:103
Dart_NativeFunction function
Definition: fuchsia.cc:51
static float max(float r, float g, float b)
Definition: hsl.cpp:49
SK_API GrBackendRenderTarget MakeVk(int width, int height, const GrVkImageInfo &)
sk_sp< const SkImage > image
Definition: SkRecords.h:269
SK_API sk_sp< SkSurface > WrapBackendRenderTarget(GrRecordingContext *context, const GrBackendRenderTarget &backendRenderTarget, GrSurfaceOrigin origin, SkColorType colorType, sk_sp< SkColorSpace > colorSpace, const SkSurfaceProps *surfaceProps, RenderTargetReleaseProc releaseProc=nullptr, ReleaseContext releaseContext=nullptr)
std::function< void()> ReleaseImageCallback
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
uint32_t color_type
#define LOG_AND_RETURN(cond, msg)
VkImage fImage
Definition: GrVkTypes.h:26
skgpu::VulkanAlloc fAlloc
Definition: GrVkTypes.h:27
VkFormat fFormat
Definition: GrVkTypes.h:30
uint32_t fSampleCount
Definition: GrVkTypes.h:32
uint32_t fLevelCount
Definition: GrVkTypes.h:33
VkImageLayout fImageLayout
Definition: GrVkTypes.h:29
VkImageUsageFlags fImageUsageFlags
Definition: GrVkTypes.h:31
VkImageTiling fImageTiling
Definition: GrVkTypes.h:28
Definition: SkSize.h:16
static constexpr SkISize MakeEmpty()
Definition: SkSize.h:22
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
VkImageLayout initialLayout
Definition: vulkan_core.h:3448
VkImageTiling tiling
Definition: vulkan_core.h:3443
VkStructureType sType
Definition: vulkan_core.h:3434
VkImageUsageFlags usage
Definition: vulkan_core.h:3444
VkStructureType sType
Definition: vulkan_core.h:3303
VkDeviceSize allocationSize
Definition: vulkan_core.h:3305
VkStructureType sType
Definition: vulkan_core.h:3392
VkImageCreateInfo vk_image_create_info
VkMemoryRequirements vk_memory_requirements
vulkan::VulkanHandle< VkImage > vk_image
VkDeviceSize fSize
Definition: VulkanTypes.h:41
VkDeviceMemory fMemory
Definition: VulkanTypes.h:39
VkDeviceSize fOffset
Definition: VulkanTypes.h:40
int_closure create
#define ERROR(message)
Definition: elf_loader.cc:260
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
Definition: trace_event.h:141
@ VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT
Definition: vulkan_core.h:2266
@ VK_IMAGE_LAYOUT_UNDEFINED
Definition: vulkan_core.h:1331
@ VK_SHARING_MODE_EXCLUSIVE
Definition: vulkan_core.h:1813
#define VK_TRUE
Definition: vulkan_core.h:131
VkFlags VkImageUsageFlags
Definition: vulkan_core.h:2382
@ VK_IMAGE_TILING_OPTIMAL
Definition: vulkan_core.h:1767
@ VK_IMAGE_USAGE_TRANSFER_DST_BIT
Definition: vulkan_core.h:2353
@ VK_IMAGE_USAGE_SAMPLED_BIT
Definition: vulkan_core.h:2354
@ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
Definition: vulkan_core.h:2356
@ VK_IMAGE_USAGE_TRANSFER_SRC_BIT
Definition: vulkan_core.h:2352
@ VK_SAMPLE_COUNT_1_BIT
Definition: vulkan_core.h:2340
@ VK_IMAGE_TYPE_2D
Definition: vulkan_core.h:1775
VkFlags VkImageCreateFlags
Definition: vulkan_core.h:2337
VkResult
Definition: vulkan_core.h:140
@ VK_SUCCESS
Definition: vulkan_core.h:141
#define VK_NULL_HANDLE
Definition: vulkan_core.h:46
VkFormat
Definition: vulkan_core.h:1458
@ VK_FORMAT_R8G8B8A8_UNORM
Definition: vulkan_core.h:1496
@ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA
Definition: vulkan_core.h:5101
@ VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA
Definition: vulkan_core.h:983
@ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
Definition: vulkan_core.h:211
@ VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA
Definition: vulkan_core.h:980
@ VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA
Definition: vulkan_core.h:977
@ VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA
Definition: vulkan_core.h:979
@ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
Definition: vulkan_core.h:216
@ VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA
Definition: vulkan_core.h:975
@ VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA
Definition: vulkan_core.h:978
@ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
Definition: vulkan_core.h:207
@ VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA
Definition: vulkan_core.h:985
@ VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA
Definition: vulkan_core.h:986
@ VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA
Definition: vulkan_core.h:984
#define VK_CALL_LOG_FATAL(expression)
#define VK_CALL_LOG_ERROR(expression)