Vulkan SDK for Android 1.1.1 Mali Developer Center
png.cpp
1 /* Copyright (c) 2016-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "png.hpp"
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #define PNG_SWAPCHAIN_IMAGES 3
26 
27 #ifdef FORCE_NO_VALIDATION
28 #define ENABLE_VALIDATION_LAYERS 0
29 #else
30 #define ENABLE_VALIDATION_LAYERS 1
31 #endif
32 
33 using namespace std;
34 
35 namespace MaliSDK
36 {
37 
38 static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT type,
39  uint64_t object, size_t location, int32_t messageCode,
40  const char *pLayerPrefix, const char *pMessage, void *pUserData)
41 {
42  auto *platform = static_cast<PNGPlatform *>(pUserData);
43  auto callback = platform->getExternalDebugCallback();
44 
45  if (callback)
46  {
47  return callback(flags, type, object, location, messageCode, pLayerPrefix, pMessage,
48  platform->getExternalDebugCallbackUserData());
49  }
50  else
51  {
52  if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
53  {
54  LOGE("Validation Layer: Error: %s: %s\n", pLayerPrefix, pMessage);
55  }
56  else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
57  {
58  LOGE("Validation Layer: Warning: %s: %s\n", pLayerPrefix, pMessage);
59  }
60  else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
61  {
62  LOGI("Validation Layer: Performance warning: %s: %s\n", pLayerPrefix, pMessage);
63  }
64  else
65  {
66  LOGI("Validation Layer: Information: %s: %s\n", pLayerPrefix, pMessage);
67  }
68  return VK_FALSE;
69  }
70 }
71 
72 uint32_t PNGPlatform::findMemoryTypeFromRequirements(uint32_t deviceRequirements, uint32_t hostRequirements)
73 {
74  const VkPhysicalDeviceMemoryProperties &props = memoryProperties;
75  for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++)
76  {
77  if (deviceRequirements & (1u << i))
78  {
79  if ((props.memoryTypes[i].propertyFlags & hostRequirements) == hostRequirements)
80  {
81  return i;
82  }
83  }
84  }
85 
86  LOGE("Failed to obtain suitable memory type.\n");
87  abort();
88 }
89 
90 uint32_t PNGPlatform::findMemoryTypeFromRequirementsFallback(uint32_t deviceRequirements, uint32_t hostRequirements,
91  uint32_t hostRequirementsFallback)
92 {
93  const VkPhysicalDeviceMemoryProperties &props = memoryProperties;
94  for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++)
95  {
96  if (deviceRequirements & (1u << i))
97  {
98  if ((props.memoryTypes[i].propertyFlags & hostRequirements) == hostRequirements)
99  {
100  return i;
101  }
102  }
103  }
104 
105  return findMemoryTypeFromRequirements(deviceRequirements, hostRequirementsFallback);
106 }
107 
108 Platform &Platform::get()
109 {
110  // Not initialized until first call to Platform::get().
111  // Initialization is thread-safe.
112  static PNGPlatform singleton;
113  return singleton;
114 }
115 
116 Platform::Status PNGPlatform::getWindowStatus()
117 {
118  return STATUS_RUNNING;
119 }
120 
121 Result PNGPlatform::initialize()
122 {
123  const char *path = getenv("MALI_PNG_PATH");
124  if (!path)
125  {
126  LOGI("MALI_PNG_PATH environment variable not defined, falling back to "
127  "default.\n");
128  path = "Mali-SDK-Frames";
129  }
130  LOGI("Dumping PNG files to: %s.xxxxxxxx.png.\n", path);
131 
132  pngSwapchain = new PNGSwapchain;
133  if (!pngSwapchain)
134  return RESULT_ERROR_OUT_OF_MEMORY;
135 
136  // Create a custom swapchain.
137  if (FAILED(pngSwapchain->init(path, PNG_SWAPCHAIN_IMAGES)))
138  return RESULT_ERROR_GENERIC;
139 
140  pContext = new Context();
141  if (!pContext)
142  return RESULT_ERROR_OUT_OF_MEMORY;
143 
144  return RESULT_SUCCESS;
145 }
146 
147 void PNGPlatform::terminate()
148 {
149  // Don't release anything until the GPU is completely idle.
150  if (device)
151  vkDeviceWaitIdle(device);
152 
153  // Make sure we delete the PNG swapchain before tearing down the buffers.
154  delete pngSwapchain;
155  pngSwapchain = nullptr;
156 
157  for (auto &image : swapchainImages)
158  if (image != VK_NULL_HANDLE)
159  vkDestroyImage(device, image, nullptr);
160 
161  for (auto &memory : swapchainMemory)
162  if (memory != VK_NULL_HANDLE)
163  vkFreeMemory(device, memory, nullptr);
164 
165  for (auto &buffer : swapchainReadback)
166  if (buffer != VK_NULL_HANDLE)
167  vkDestroyBuffer(device, buffer, nullptr);
168 
169  for (auto &memory : swapchainReadbackMemory)
170  if (memory != VK_NULL_HANDLE)
171  vkFreeMemory(device, memory, nullptr);
172 
173  // Make sure we tear down the context before destroying the device since
174  // context
175  // also owns some Vulkan resources.
176  delete pContext;
177  pContext = nullptr;
178 
179  if (device)
180  vkDestroyDevice(device, nullptr);
181 
182  if (debug_callback)
183  {
184  VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkDestroyDebugReportCallbackEXT);
185  vkDestroyDebugReportCallbackEXT(instance, debug_callback, nullptr);
186  }
187 
188  if (instance)
189  vkDestroyInstance(instance, nullptr);
190 
191  swapchainImages.clear();
192  swapchainMemory.clear();
193  swapchainReadback.clear();
194  swapchainReadbackMemory.clear();
195  device = VK_NULL_HANDLE;
196  debug_callback = VK_NULL_HANDLE;
197  instance = VK_NULL_HANDLE;
198 }
199 
200 PNGPlatform::~PNGPlatform()
201 {
202  terminate();
203 }
204 
205 Platform::SwapchainDimensions PNGPlatform::getPreferredSwapchain()
206 {
207  SwapchainDimensions chain = {
208  1280, 720, VK_FORMAT_R8G8B8A8_UNORM,
209  };
210 
211  return chain;
212 }
213 
214 Result PNGPlatform::createWindow(const SwapchainDimensions &swapchain)
215 {
216  return initVulkan(swapchain);
217 }
218 
219 void PNGPlatform::getCurrentSwapchain(vector<VkImage> *images, SwapchainDimensions *swapchain)
220 {
221  *images = swapchainImages;
222  *swapchain = swapchainDimensions;
223 }
224 
225 unsigned PNGPlatform::getNumSwapchainImages() const
226 {
227  return swapchainImages.size();
228 }
229 
230 Result PNGPlatform::acquireNextImage(unsigned *image)
231 {
232  // This function will return when scanout is complete.
233  // This is similar to vkAcquireNextImageKHR and we wait for the fence it
234  // provides us.
235  *image = pngSwapchain->acquire();
236  // Signal the underlying context that we're using this backbuffer now.
237  // This will also wait for all fences associated with this swapchain image to
238  // complete first.
239  pContext->beginFrame(*image, VK_NULL_HANDLE);
240  return RESULT_SUCCESS;
241 }
242 
243 void PNGPlatform::imageMemoryBarrier(VkCommandBuffer cmd, VkImage image, VkAccessFlags srcAccessMask,
244  VkAccessFlags dstAccessMask, VkPipelineStageFlags srcStageMask,
245  VkPipelineStageFlags dstStageMask, VkImageLayout oldLayout,
246  VkImageLayout newLayout)
247 {
248  VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
249 
250  barrier.srcAccessMask = srcAccessMask;
251  barrier.dstAccessMask = dstAccessMask;
252  barrier.oldLayout = oldLayout;
253  barrier.newLayout = newLayout;
254  barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
255  barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
256  barrier.image = image;
257  barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
258  barrier.subresourceRange.levelCount = 1;
259  barrier.subresourceRange.layerCount = 1;
260 
261  vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, false, 0, nullptr, 0, nullptr, 1, &barrier);
262 }
263 
264 Result PNGPlatform::presentImage(unsigned index)
265 {
266  auto cmd = pContext->requestPrimaryCommandBuffer();
267 
268  VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
269  beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
270  vkBeginCommandBuffer(cmd, &beginInfo);
271 
272  // Transition image back from PRESENT_SRC_KHR to TRANSFER_SRC_OPTIMAL.
273  imageMemoryBarrier(cmd, swapchainImages[index], VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
274  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
275  VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
276 
277  // Copy from the image to a host-visible buffer.
278  VkBufferImageCopy region = { 0 };
279  region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
280  region.imageSubresource.layerCount = 1;
281  region.imageExtent.width = swapchainDimensions.width;
282  region.imageExtent.height = swapchainDimensions.height;
283  region.imageExtent.depth = 1;
284  vkCmdCopyImageToBuffer(cmd, swapchainImages[index], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapchainReadback[index],
285  1, &region);
286 
287  VK_CHECK(vkEndCommandBuffer(cmd));
288  pContext->submit(cmd);
289 
290  // For the PNG swapchain, we rely on keeping track of all the queue
291  // submissions we made,
292  // wait for their fences to hit in a separate thread, then we can do
293  // multithreaded PNG encoding.
294  unsigned numFences = pContext->getFenceManager().getActiveFenceCount();
295  VkFence *fences = pContext->getFenceManager().getActiveFences();
296  pngSwapchain->present(index, device, swapchainReadbackMemory[index], swapchainDimensions.width,
297  swapchainDimensions.height, numFences, fences, swapchainCoherent);
298  return RESULT_SUCCESS;
299 }
300 
301 Result PNGPlatform::initVulkan(const SwapchainDimensions &swapchain)
302 {
303  if (!vulkanSymbolWrapperInitLoader())
304  {
305  LOGE("Cannot find Vulkan loader.\n");
306  return RESULT_ERROR_GENERIC;
307  }
308 
309  if (!vulkanSymbolWrapperLoadGlobalSymbols())
310  {
311  LOGE("Failed to load global Vulkan symbols.\n");
312  return RESULT_ERROR_GENERIC;
313  }
314 
315  uint32_t instanceExtensionCount;
316  VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount, nullptr));
317  vector<VkExtensionProperties> instanceExtensions(instanceExtensionCount);
318  VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount, instanceExtensions.data()));
319 
320  for (auto &instanceExt : instanceExtensions)
321  LOGI("Instance extension: %s\n", instanceExt.extensionName);
322 
323 #if ENABLE_VALIDATION_LAYERS
324  uint32_t instanceLayerCount;
325  VK_CHECK(vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr));
326  vector<VkLayerProperties> instanceLayers(instanceLayerCount);
327  VK_CHECK(vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayers.data()));
328 
329  vector<const char *> activeLayers;
330  for (auto &ext : instanceLayers)
331  if (strcmp(ext.layerName, "VK_LAYER_LUNARG_standard_validation") == 0)
332  activeLayers.push_back("VK_LAYER_LUNARG_standard_validation");
333 
334  if (activeLayers.empty())
335  LOGI("Did not find validation layers.\n");
336  else
337  LOGI("Found validation layers!\n");
338 
339  addExternalLayers(activeLayers, instanceLayers);
340 #endif
341 
342  bool haveDebugReport = false;
343  vector<const char *> activeInstanceExtensions;
344  for (auto &ext : instanceExtensions)
345  {
346  if (strcmp(ext.extensionName, "VK_EXT_debug_report") == 0)
347  {
348  haveDebugReport = true;
349  activeInstanceExtensions.push_back("VK_EXT_debug_report");
350  break;
351  }
352  }
353 
354  VkApplicationInfo app = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
355  app.pApplicationName = "Mali SDK";
356  app.applicationVersion = 0;
357  app.pEngineName = "Mali SDK";
358  app.engineVersion = 0;
359  app.apiVersion = VK_MAKE_VERSION(1, 0, 13);
360 
361  VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
362  info.pApplicationInfo = &app;
363 
364 #if ENABLE_VALIDATION_LAYERS
365  if (!activeLayers.empty())
366  {
367  info.enabledLayerCount = activeLayers.size();
368  info.ppEnabledLayerNames = activeLayers.data();
369  LOGI("Using Vulkan instance validation layers.\n");
370  }
371 
372  if (!activeInstanceExtensions.empty())
373  {
374  info.enabledExtensionCount = activeInstanceExtensions.size();
375  info.ppEnabledExtensionNames = activeInstanceExtensions.data();
376  }
377 #endif
378 
379  VK_CHECK(vkCreateInstance(&info, nullptr, &instance));
380 
381  if (!vulkanSymbolWrapperLoadCoreInstanceSymbols(instance))
382  {
383  LOGE("Failed to load instance symbols.");
384  return RESULT_ERROR_GENERIC;
385  }
386 
387  if (haveDebugReport)
388  {
389  VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkCreateDebugReportCallbackEXT);
390  VkDebugReportCallbackCreateInfoEXT info = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT };
391  info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
392  VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
393 
394  info.pfnCallback = debugCallback;
395  info.pUserData = this;
396  if (vkCreateDebugReportCallbackEXT)
397  vkCreateDebugReportCallbackEXT(instance, &info, nullptr, &debug_callback);
398  LOGI("Enabling Vulkan debug reporting.\n");
399  }
400 
401  uint32_t gpuCount = 0;
402  VK_CHECK(vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr));
403  if (gpuCount < 1)
404  {
405  LOGE("Failed to enumerate Vulkan physical device.\n");
406  return RESULT_ERROR_GENERIC;
407  }
408 
409  vector<VkPhysicalDevice> gpus(gpuCount);
410  VK_CHECK(vkEnumeratePhysicalDevices(instance, &gpuCount, gpus.data()));
411 
412  gpu = VK_NULL_HANDLE;
413 
414  for (auto device : gpus)
415  {
416  VkPhysicalDeviceProperties properties;
417  vkGetPhysicalDeviceProperties(device, &properties);
418 
419  // If we have multiple GPUs in our system, try to find a Mali device.
420  if (strstr(properties.deviceName, "Mali"))
421  {
422  gpu = device;
423  LOGI("Found ARM Mali physical device: %s.\n", properties.deviceName);
424  break;
425  }
426  }
427 
428  // Fallback to the first GPU we find in the system.
429  if (gpu == VK_NULL_HANDLE)
430  gpu = gpus.front();
431 
432  vkGetPhysicalDeviceProperties(gpu, &gpuProperties);
433  vkGetPhysicalDeviceMemoryProperties(gpu, &memoryProperties);
434 
435  uint32_t queueCount;
436  vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queueCount, nullptr);
437  queueProperties.resize(queueCount);
438  vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queueCount, queueProperties.data());
439  if (queueCount < 1)
440  return RESULT_ERROR_GENERIC;
441 
442 #if ENABLE_VALIDATION_LAYERS
443  uint32_t deviceLayerCount;
444  VK_CHECK(vkEnumerateDeviceLayerProperties(gpu, &deviceLayerCount, nullptr));
445  vector<VkLayerProperties> deviceLayers(deviceLayerCount);
446  VK_CHECK(vkEnumerateDeviceLayerProperties(gpu, &deviceLayerCount, deviceLayers.data()));
447 
448  activeLayers.clear();
449  for (auto &ext : deviceLayers)
450  {
451  if (strcmp(ext.layerName, "VK_LAYER_LUNARG_standard_validation") == 0)
452  activeLayers.push_back("VK_LAYER_LUNARG_standard_validation");
453  }
454 
455  addExternalLayers(activeLayers, instanceLayers);
456 #endif
457 
458  bool foundQueue = false;
459  for (unsigned i = 0; i < queueCount; i++)
460  {
461  if (queueProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
462  {
463  graphicsQueueIndex = i;
464  foundQueue = true;
465  break;
466  }
467  }
468 
469  if (!foundQueue)
470  {
471  LOGE("Did not find suitable graphics queue.\n");
472  return RESULT_ERROR_GENERIC;
473  }
474 
475  static const float one = 1.0f;
476  VkDeviceQueueCreateInfo queueInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
477  queueInfo.queueFamilyIndex = graphicsQueueIndex;
478  queueInfo.queueCount = 1;
479  queueInfo.pQueuePriorities = &one;
480 
481  VkPhysicalDeviceFeatures features = { false };
482  VkDeviceCreateInfo deviceInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
483  deviceInfo.queueCreateInfoCount = 1;
484  deviceInfo.pQueueCreateInfos = &queueInfo;
485  deviceInfo.pEnabledFeatures = &features;
486 
487 #if ENABLE_VALIDATION_LAYERS
488  if (!activeLayers.empty())
489  {
490  deviceInfo.enabledLayerCount = activeLayers.size();
491  deviceInfo.ppEnabledLayerNames = activeLayers.data();
492  LOGI("Using Vulkan device validation layers.\n");
493  }
494 #endif
495 
496  VK_CHECK(vkCreateDevice(gpu, &deviceInfo, nullptr, &device));
497  if (!vulkanSymbolWrapperLoadCoreDeviceSymbols(device))
498  {
499  LOGE("Failed to load device symbols.");
500  return RESULT_ERROR_GENERIC;
501  }
502 
503  vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
504 
505  swapchainDimensions = swapchain;
506  swapchainDimensions.format = VK_FORMAT_R8G8B8A8_UNORM;
507  swapchainImages.resize(pngSwapchain->getNumImages());
508  swapchainMemory.resize(pngSwapchain->getNumImages());
509  swapchainReadback.resize(pngSwapchain->getNumImages());
510  swapchainReadbackMemory.resize(pngSwapchain->getNumImages());
511 
512  for (unsigned i = 0; i < pngSwapchain->getNumImages(); i++)
513  {
514  VkImageCreateInfo image = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
515 
516  image.imageType = VK_IMAGE_TYPE_2D;
517  image.format = VK_FORMAT_R8G8B8A8_UNORM;
518  image.extent.width = swapchainDimensions.width;
519  image.extent.height = swapchainDimensions.height;
520  image.extent.depth = 1;
521  image.samples = VK_SAMPLE_COUNT_1_BIT;
522  image.tiling = VK_IMAGE_TILING_OPTIMAL;
523  image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
524  image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
525  image.mipLevels = 1;
526  image.arrayLayers = 1;
527 
528  VK_CHECK(vkCreateImage(device, &image, nullptr, &swapchainImages[i]));
529 
530  // Allocate memory for the texture.
531  VkMemoryRequirements memReqs;
532  vkGetImageMemoryRequirements(device, swapchainImages[i], &memReqs);
533 
534  VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
535  alloc.allocationSize = memReqs.size;
536  alloc.memoryTypeIndex =
537  findMemoryTypeFromRequirements(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
538  VK_CHECK(vkAllocateMemory(device, &alloc, nullptr, &swapchainMemory[i]));
539  vkBindImageMemory(device, swapchainImages[i], swapchainMemory[i], 0);
540 
541  // Create a buffer which we will read back from.
542  VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
543  bufferInfo.size = swapchainDimensions.width * swapchainDimensions.height * 4;
544  bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
545  bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
546 
547  VK_CHECK(vkCreateBuffer(device, &bufferInfo, nullptr, &swapchainReadback[i]));
548  vkGetBufferMemoryRequirements(device, swapchainReadback[i], &memReqs);
549 
550  alloc.allocationSize = memReqs.size;
551  // Try to use CACHED_BIT if available, since this will greatly accelerate
552  // readbacks.
553  alloc.memoryTypeIndex = findMemoryTypeFromRequirementsFallback(
554  memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
555  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
556  VK_CHECK(vkAllocateMemory(device, &alloc, nullptr, &swapchainReadbackMemory[i]));
557 
558  // Figure out if we have incoherent memory. If so, we need to do cache
559  // control manually.
560  // This will be the same for every iteration.
561  swapchainCoherent = (memoryProperties.memoryTypes[alloc.memoryTypeIndex].propertyFlags &
562  VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
563 
564  vkBindBufferMemory(device, swapchainReadback[i], swapchainReadbackMemory[i], 0);
565  }
566 
567  Result res = pContext->onPlatformUpdate(this);
568  if (FAILED(res))
569  return RESULT_ERROR_GENERIC;
570 
571  return RESULT_SUCCESS;
572 }
573 }
VkFormat format
Pixel format of the swapchain.
Definition: platform.hpp:61
The Context is the primary way for samples to interact with the swapchain and get rendered images to ...
Definition: context.hpp:36
Describes the size and format of the swapchain.
Definition: platform.hpp:54
Status
Describes the status of the application lifecycle.
Definition: platform.hpp:65
This class implements a swapchain outside the Vulkan API. Its main purpose is debugging without a scr...