Flutter Engine
The Flutter Engine
VulkanTexture.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
12#include "src/core/SkMipmap.h"
21
22namespace skgpu::graphite {
23
25 SkISize dimensions,
26 const TextureInfo& info,
27 CreatedImageInfo* outInfo) {
28 SkASSERT(outInfo);
29 const VulkanCaps& caps = sharedContext->vulkanCaps();
30
31 if (dimensions.isEmpty()) {
32 SKGPU_LOG_E("Tried to create VkImage with empty dimensions.");
33 return false;
34 }
35 if (dimensions.width() > caps.maxTextureSize() ||
36 dimensions.height() > caps.maxTextureSize()) {
37 SKGPU_LOG_E("Tried to create VkImage with too large a size.");
38 return false;
39 }
40
41 if ((info.isProtected() == Protected::kYes) != caps.protectedSupport()) {
42 SKGPU_LOG_E("Tried to create %s VkImage in %s Context.",
43 info.isProtected() == Protected::kYes ? "protected" : "unprotected",
44 caps.protectedSupport() ? "protected" : "unprotected");
45 return false;
46 }
47
48 const VulkanTextureSpec& spec = info.vulkanTextureSpec();
49
50 bool isLinear = spec.fImageTiling == VK_IMAGE_TILING_LINEAR;
51 VkImageLayout initialLayout = isLinear ? VK_IMAGE_LAYOUT_PREINITIALIZED
53
54 // Create Image
55 VkSampleCountFlagBits vkSamples;
56 if (!SampleCountToVkSampleCount(info.numSamples(), &vkSamples)) {
57 SKGPU_LOG_E("Failed creating VkImage because we could not covert the number of samples: "
58 "%u to a VkSampleCountFlagBits.", info.numSamples());
59 return false;
60 }
61
62 SkASSERT(!isLinear || vkSamples == VK_SAMPLE_COUNT_1_BIT);
63
64 VkImageCreateFlags createflags = 0;
65 if (info.isProtected() == Protected::kYes && caps.protectedSupport()) {
66 createflags |= VK_IMAGE_CREATE_PROTECTED_BIT;
67 }
68
69 uint32_t numMipLevels = 1;
70 if (info.mipmapped() == Mipmapped::kYes) {
72 }
73
74 uint32_t width = static_cast<uint32_t>(dimensions.fWidth);
75 uint32_t height = static_cast<uint32_t>(dimensions.fHeight);
76
77 const VkImageCreateInfo imageCreateInfo = {
79 nullptr, // pNext
80 createflags, // VkImageCreateFlags
81 VK_IMAGE_TYPE_2D, // VkImageType
82 spec.fFormat, // VkFormat
83 { width, height, 1 }, // VkExtent3D
84 numMipLevels, // mipLevels
85 1, // arrayLayers
86 vkSamples, // samples
87 spec.fImageTiling, // VkImageTiling
88 spec.fImageUsageFlags, // VkImageUsageFlags
89 spec.fSharingMode, // VkSharingMode
90 0, // queueFamilyCount
91 nullptr, // pQueueFamilyIndices
92 initialLayout // initialLayout
93 };
94
95 auto device = sharedContext->device();
96
97 VkImage image = VK_NULL_HANDLE;
100 sharedContext, result, CreateImage(device, &imageCreateInfo, nullptr, &image));
101 if (result != VK_SUCCESS) {
102 SKGPU_LOG_E("Failed call to vkCreateImage with error: %d", result);
103 return false;
104 }
105
106 auto allocator = sharedContext->memoryAllocator();
107 bool forceDedicatedMemory = caps.shouldAlwaysUseDedicatedImageMemory();
108 bool useLazyAllocation =
110
111 auto checkResult = [sharedContext](VkResult result) {
112 return sharedContext->checkVkResult(result);
113 };
115 image,
116 info.isProtected(),
117 forceDedicatedMemory,
118 useLazyAllocation,
119 checkResult,
120 &outInfo->fMemoryAlloc)) {
121 VULKAN_CALL(sharedContext->interface(), DestroyImage(device, image, nullptr));
122 return false;
123 }
124
125 if (useLazyAllocation &&
127 SKGPU_LOG_E("Failed allocate lazy vulkan memory when requested");
129 return false;
130 }
131
134 result,
135 BindImageMemory(
136 device, image, outInfo->fMemoryAlloc.fMemory, outInfo->fMemoryAlloc.fOffset));
137 if (result != VK_SUCCESS) {
139 VULKAN_CALL(sharedContext->interface(), DestroyImage(device, image, nullptr));
140 return false;
141 }
142
143 outInfo->fImage = image;
144 outInfo->fMutableState = sk_make_sp<MutableTextureState>(
146 return true;
147}
148
150 SkISize dimensions,
151 const TextureInfo& info,
152 skgpu::Budgeted budgeted,
153 sk_sp<VulkanYcbcrConversion> ycbcrConversion) {
154 CreatedImageInfo imageInfo;
155 if (!MakeVkImage(sharedContext, dimensions, info, &imageInfo)) {
156 return nullptr;
157 }
158
161 info,
162 std::move(imageInfo.fMutableState),
163 imageInfo.fImage,
164 imageInfo.fMemoryAlloc,
166 budgeted,
167 std::move(ycbcrConversion)));
168}
169
171 SkISize dimensions,
172 const TextureInfo& info,
173 sk_sp<MutableTextureState> mutableState,
174 VkImage image,
175 const VulkanAlloc& alloc,
176 sk_sp<VulkanYcbcrConversion> ycbcrConversion) {
179 info,
180 std::move(mutableState),
181 image,
182 alloc,
185 std::move(ycbcrConversion)));
186}
187
189 switch (format) {
193 [[fallthrough]];
197 [[fallthrough]];
200 default:
202 }
203}
204
206 VkImageLayout newLayout,
207 VkAccessFlags dstAccessMask,
208 VkPipelineStageFlags dstStageMask,
209 bool byRegion,
210 uint32_t newQueueFamilyIndex) const {
211
212 SkASSERT(newLayout == this->currentLayout() ||
213 (VK_IMAGE_LAYOUT_UNDEFINED != newLayout &&
214 VK_IMAGE_LAYOUT_PREINITIALIZED != newLayout));
216 uint32_t currentQueueIndex = this->currentQueueFamilyIndex();
217
219 this->textureInfo().getVulkanTextureInfo(&textureInfo);
220 auto sharedContext = static_cast<const VulkanSharedContext*>(this->sharedContext());
221
222 // Enable the following block on new devices to test that their lazy images stay at 0 memory use
223#if 0
224 auto device = sharedContext->device();
225 if (fAlloc.fFlags & skgpu::VulkanAlloc::kLazilyAllocated_Flag) {
227 VULKAN_CALL(sharedContext->interface(), GetDeviceMemoryCommitment(device, fAlloc.fMemory, &size));
228
229 SkDebugf("Lazy Image. This: %p, image: %d, size: %d\n", this, fImage, size);
230 }
231#endif
232#ifdef SK_DEBUG
233 if (textureInfo.fSharingMode == VK_SHARING_MODE_CONCURRENT) {
234 if (newQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED) {
235 SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED ||
236 currentQueueIndex == VK_QUEUE_FAMILY_EXTERNAL ||
237 currentQueueIndex == VK_QUEUE_FAMILY_FOREIGN_EXT);
238 } else {
239 SkASSERT(newQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
240 newQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT);
241 SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED);
242 }
243 } else {
245 if (newQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED ||
246 currentQueueIndex == sharedContext->queueIndex()) {
247 SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED ||
248 currentQueueIndex == VK_QUEUE_FAMILY_EXTERNAL ||
249 currentQueueIndex == VK_QUEUE_FAMILY_FOREIGN_EXT ||
250 currentQueueIndex == sharedContext->queueIndex());
251 } else if (newQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
252 newQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT) {
253 SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED ||
254 currentQueueIndex == sharedContext->queueIndex());
255 }
256 }
257#endif
258
259 if (textureInfo.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) {
260 if (newQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED) {
261 newQueueFamilyIndex = sharedContext->queueIndex();
262 }
263 if (currentQueueIndex == VK_QUEUE_FAMILY_IGNORED) {
264 currentQueueIndex = sharedContext->queueIndex();
265 }
266 }
267
268 // If the old and new layout are the same and the layout is a read only layout, there is no need
269 // to put in a barrier unless we also need to switch queues.
270 if (newLayout == currentLayout && currentQueueIndex == newQueueFamilyIndex &&
274 return;
275 }
276
279
281 uint32_t numMipLevels = 1;
282 SkISize dimensions = this->dimensions();
283 if (this->mipmapped() == Mipmapped::kYes) {
285 }
286 VkImageMemoryBarrier imageMemoryBarrier = {
288 nullptr, // pNext
289 srcAccessMask, // srcAccessMask
290 dstAccessMask, // dstAccessMask
291 currentLayout, // oldLayout
292 newLayout, // newLayout
293 currentQueueIndex, // srcQueueFamilyIndex
294 newQueueFamilyIndex, // dstQueueFamilyIndex
295 fImage, // image
296 { aspectFlags, 0, numMipLevels, 0, 1 } // subresourceRange
297 };
298 SkASSERT(srcAccessMask == imageMemoryBarrier.srcAccessMask);
299 cmdBuffer->addImageMemoryBarrier(this, srcStageMask, dstStageMask, byRegion,
300 &imageMemoryBarrier);
301
304}
305
306VulkanTexture::VulkanTexture(const VulkanSharedContext* sharedContext,
307 SkISize dimensions,
308 const TextureInfo& info,
309 sk_sp<MutableTextureState> mutableState,
310 VkImage image,
311 const VulkanAlloc& alloc,
312 Ownership ownership,
313 skgpu::Budgeted budgeted,
314 sk_sp<VulkanYcbcrConversion> ycbcrConversion)
315 : Texture(sharedContext, dimensions, info, std::move(mutableState), ownership, budgeted)
316 , fImage(image)
317 , fMemoryAlloc(alloc)
318 , fYcbcrConversion(std::move(ycbcrConversion)) {}
319
320void VulkanTexture::freeGpuData() {
321 // Need to delete any ImageViews first
322 fImageViews.clear();
323
324 // If the texture is wrapped we don't own this data
325 if (this->ownership() != Ownership::kWrapped) {
326 auto sharedContext = static_cast<const VulkanSharedContext*>(this->sharedContext());
327 VULKAN_CALL(sharedContext->interface(),
328 DestroyImage(sharedContext->device(), fImage, nullptr));
329 skgpu::VulkanMemory::FreeImageMemory(sharedContext->memoryAllocator(), fMemoryAlloc);
330 }
331}
332
335}
336
339}
340
343}
344
346 if (VK_IMAGE_LAYOUT_GENERAL == layout) {
348 } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
351 } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
356 } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
358 } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
360 } else if (VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout) {
362 }
363
366}
367
369 // Currently we assume we will never being doing any explict shader writes (this doesn't include
370 // color attachment or depth/stencil writes). So we will ignore the
371 // VK_MEMORY_OUTPUT_SHADER_WRITE_BIT.
372
373 // We can only directly access the host memory if we are in preinitialized or general layout,
374 // and the image is linear.
375 // TODO: Add check for linear here so we are not always adding host to general, and we should
376 // only be in preinitialized if we are linear
378 if (VK_IMAGE_LAYOUT_GENERAL == layout) {
383 } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
385 } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
389 } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
391 } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
394 // There are no writes that need to be made available
395 flags = 0;
396 }
397 return flags;
398}
399
401 for (int i = 0; i < fImageViews.size(); ++i) {
402 if (fImageViews[i]->usage() == usage) {
403 return fImageViews[i].get();
404 }
405 }
406
407 auto sharedContext = static_cast<const VulkanSharedContext*>(this->sharedContext());
408 VulkanTextureInfo vkTexInfo;
409 this->textureInfo().getVulkanTextureInfo(&vkTexInfo);
410 int miplevels = this->textureInfo().mipmapped() == Mipmapped::kYes
412 this->dimensions().height()) + 1
413 : 1;
414 auto imageView = VulkanImageView::Make(sharedContext,
415 fImage,
416 vkTexInfo.fFormat,
417 usage,
418 miplevels,
419 fYcbcrConversion);
420 return fImageViews.push_back(std::move(imageView)).get();
421}
422
423
424} // namespace skgpu::graphite
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
#define SKGPU_LOG_E(fmt,...)
Definition: Log.h:38
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
#define VULKAN_CALL(IFACE, X)
#define VULKAN_CALL_RESULT(SHARED_CONTEXT, RESULT, X)
static int ComputeLevelCount(int baseWidth, int baseHeight)
Definition: SkMipmap.cpp:134
bool protectedSupport() const
Definition: Caps.h:226
int maxTextureSize() const
Definition: Caps.h:141
skgpu::Budgeted budgeted() const
Definition: Resource.h:100
const SharedContext * sharedContext() const
Definition: Resource.h:189
Ownership ownership() const
Definition: Resource.h:98
Mipmapped mipmapped() const
Definition: TextureInfo.h:79
Mipmapped mipmapped() const
Definition: Texture.h:29
SkISize dimensions() const
Definition: Texture.h:31
MutableTextureState * mutableState() const
Definition: Texture.cpp:44
const TextureInfo & textureInfo() const
Definition: Texture.h:32
bool shouldAlwaysUseDedicatedImageMemory() const
Definition: VulkanCaps.h:71
void addImageMemoryBarrier(const Resource *, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, bool byRegion, VkImageMemoryBarrier *barrier)
static std::unique_ptr< const VulkanImageView > Make(const VulkanSharedContext *sharedContext, VkImage image, VkFormat format, Usage usage, uint32_t miplevels, sk_sp< VulkanYcbcrConversion >)
void updateImageLayout(VkImageLayout)
uint32_t currentQueueFamilyIndex() const
void setImageLayoutAndQueueIndex(VulkanCommandBuffer *, VkImageLayout newLayout, VkAccessFlags dstAccessMask, VkPipelineStageFlags dstStageMask, bool byRegion, uint32_t newQueueFamilyIndex) const
static VkAccessFlags LayoutToSrcAccessMask(const VkImageLayout layout)
static bool MakeVkImage(const VulkanSharedContext *, SkISize dimensions, const TextureInfo &, CreatedImageInfo *outInfo)
static VkPipelineStageFlags LayoutToPipelineSrcStageFlags(const VkImageLayout layout)
static sk_sp< Texture > Make(const VulkanSharedContext *, SkISize dimensions, const TextureInfo &, skgpu::Budgeted, sk_sp< VulkanYcbcrConversion >)
VkImageLayout currentLayout() const
const VulkanImageView * getImageView(VulkanImageView::Usage) const
static sk_sp< Texture > MakeWrapped(const VulkanSharedContext *, SkISize dimensions, const TextureInfo &, sk_sp< MutableTextureState >, VkImage, const VulkanAlloc &, sk_sp< VulkanYcbcrConversion >)
VkDevice device
Definition: main.cc:53
FlutterSemanticsFlag flags
GAsyncResult * result
uint32_t uint32_t * format
sk_sp< const SkImage > image
Definition: SkRecords.h:269
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
void SetVkImageLayout(MutableTextureState *state, VkImageLayout layout)
SK_API uint32_t GetVkQueueFamilyIndex(const MutableTextureState &state)
SK_API MutableTextureState MakeVulkan(VkImageLayout layout, uint32_t queueFamilyIndex)
void SetVkQueueFamilyIndex(MutableTextureState *state, uint32_t queueFamilyIndex)
SK_API VkImageLayout GetVkImageLayout(const MutableTextureState &state)
void FreeImageMemory(VulkanMemoryAllocator *, const VulkanAlloc &alloc)
bool AllocImageMemory(VulkanMemoryAllocator *, VkImage image, skgpu::Protected isProtected, bool forceDedicatedMemory, bool useLazyAllocation, const std::function< CheckResult > &, VulkanAlloc *alloc)
VkImageAspectFlags vk_format_to_aspect_flags(VkFormat format)
Budgeted
Definition: GpuTypes.h:35
static constexpr bool SampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits *vkSamples)
Definition: ref_ptr.h:256
int32_t height
int32_t width
static void usage(char *argv0)
Definition: SkSize.h:16
bool isEmpty() const
Definition: SkSize.h:31
int32_t fHeight
Definition: SkSize.h:18
int32_t fWidth
Definition: SkSize.h:17
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
VkAccessFlags srcAccessMask
Definition: vulkan_core.h:2938
VkDeviceMemory fMemory
Definition: VulkanTypes.h:39
VkDeviceSize fOffset
Definition: VulkanTypes.h:40
sk_sp< MutableTextureState > fMutableState
Definition: VulkanTexture.h:32
VkFlags VkPipelineStageFlags
Definition: vulkan_core.h:2470
VkImageLayout
Definition: vulkan_core.h:1330
@ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
Definition: vulkan_core.h:1337
@ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
Definition: vulkan_core.h:1348
@ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
Definition: vulkan_core.h:1334
@ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
Definition: vulkan_core.h:1336
@ VK_IMAGE_LAYOUT_PREINITIALIZED
Definition: vulkan_core.h:1339
@ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
Definition: vulkan_core.h:1333
@ VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
Definition: vulkan_core.h:1335
@ VK_IMAGE_LAYOUT_UNDEFINED
Definition: vulkan_core.h:1331
@ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
Definition: vulkan_core.h:1338
@ VK_IMAGE_LAYOUT_GENERAL
Definition: vulkan_core.h:1332
@ VK_SHARING_MODE_CONCURRENT
Definition: vulkan_core.h:1814
@ VK_SHARING_MODE_EXCLUSIVE
Definition: vulkan_core.h:1813
VkFlags VkImageAspectFlags
Definition: vulkan_core.h:2256
VkFlags VkAccessFlags
Definition: vulkan_core.h:2235
uint64_t VkDeviceSize
Definition: vulkan_core.h:96
@ VK_IMAGE_CREATE_PROTECTED_BIT
Definition: vulkan_core.h:2320
@ VK_IMAGE_TILING_LINEAR
Definition: vulkan_core.h:1768
@ VK_IMAGE_ASPECT_COLOR_BIT
Definition: vulkan_core.h:2238
@ VK_IMAGE_ASPECT_STENCIL_BIT
Definition: vulkan_core.h:2240
@ VK_IMAGE_ASPECT_DEPTH_BIT
Definition: vulkan_core.h:2239
@ VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
Definition: vulkan_core.h:2358
VkSampleCountFlagBits
Definition: vulkan_core.h:2339
@ VK_SAMPLE_COUNT_1_BIT
Definition: vulkan_core.h:2340
#define VK_QUEUE_FAMILY_FOREIGN_EXT
@ 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
@ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
Definition: vulkan_core.h:2210
@ VK_ACCESS_TRANSFER_WRITE_BIT
Definition: vulkan_core.h:2212
@ VK_ACCESS_HOST_WRITE_BIT
Definition: vulkan_core.h:2214
@ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
Definition: vulkan_core.h:2208
#define VK_NULL_HANDLE
Definition: vulkan_core.h:46
#define VK_QUEUE_FAMILY_EXTERNAL
Definition: vulkan_core.h:4927
VkFormat
Definition: vulkan_core.h:1458
@ VK_FORMAT_D24_UNORM_S8_UINT
Definition: vulkan_core.h:1588
@ VK_FORMAT_D32_SFLOAT
Definition: vulkan_core.h:1585
@ VK_FORMAT_S8_UINT
Definition: vulkan_core.h:1586
@ VK_FORMAT_D16_UNORM
Definition: vulkan_core.h:1583
@ VK_FORMAT_D32_SFLOAT_S8_UINT
Definition: vulkan_core.h:1589
@ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
Definition: vulkan_core.h:2442
@ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
Definition: vulkan_core.h:2435
@ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
Definition: vulkan_core.h:2445
@ VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
Definition: vulkan_core.h:2444
@ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
Definition: vulkan_core.h:2451
@ VK_PIPELINE_STAGE_HOST_BIT
Definition: vulkan_core.h:2449
@ VK_PIPELINE_STAGE_TRANSFER_BIT
Definition: vulkan_core.h:2447
#define VK_QUEUE_FAMILY_IGNORED
Definition: vulkan_core.h:127
@ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
Definition: vulkan_core.h:216
@ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER
Definition: vulkan_core.h:247