1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #define LOG_TAG "VulkanTestHelpers"
19 
20 #include "VulkanTestHelpers.h"
21 
22 #include <android/asset_manager.h>
23 #include <android/asset_manager_jni.h>
24 #include <android/hardware_buffer.h>
25 #include <android/log.h>
26 
27 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
28 
29 #define ASSERT(a)                                                              \
30   if (!(a)) {                                                                  \
31     ALOGE("Failure: " #a " at " __FILE__ ":%d", __LINE__);                     \
32     return false;                                                              \
33   }
34 
35 #define VK_CALL(a) ASSERT(VK_SUCCESS == (a))
36 
37 namespace {
38 
addImageTransitionBarrier(VkCommandBuffer commandBuffer,VkImage image,VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,VkAccessFlags srcAccessMask,VkAccessFlags dstAccessMask,VkImageLayout oldLayout,VkImageLayout newLayout,uint32_t srcQueue=VK_QUEUE_FAMILY_IGNORED,uint32_t dstQueue=VK_QUEUE_FAMILY_IGNORED)39 void addImageTransitionBarrier(VkCommandBuffer commandBuffer, VkImage image,
40                                VkPipelineStageFlags srcStageMask,
41                                VkPipelineStageFlags dstStageMask,
42                                VkAccessFlags srcAccessMask,
43                                VkAccessFlags dstAccessMask,
44                                VkImageLayout oldLayout, VkImageLayout newLayout,
45                                uint32_t srcQueue = VK_QUEUE_FAMILY_IGNORED,
46                                uint32_t dstQueue = VK_QUEUE_FAMILY_IGNORED) {
47   const VkImageSubresourceRange subResourcerange{
48       .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
49       .baseMipLevel = 0,
50       .levelCount = 1,
51       .baseArrayLayer = 0,
52       .layerCount = 1,
53   };
54   const VkImageMemoryBarrier imageBarrier{
55       .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
56       .pNext = nullptr,
57       .srcAccessMask = srcAccessMask,
58       .dstAccessMask = dstAccessMask,
59       .oldLayout = oldLayout,
60       .newLayout = newLayout,
61       .srcQueueFamilyIndex = srcQueue,
62       .dstQueueFamilyIndex = dstQueue,
63       .image = image,
64       .subresourceRange = subResourcerange,
65   };
66   vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, nullptr,
67                        0, nullptr, 1, &imageBarrier);
68 }
69 
70 } // namespace
71 
enumerateDeviceExtensions(VkPhysicalDevice device,std::vector<VkExtensionProperties> * extensions)72 static bool enumerateDeviceExtensions(VkPhysicalDevice device,
73                                       std::vector<VkExtensionProperties>* extensions) {
74     VkResult result;
75 
76     uint32_t count = 0;
77     result = vkEnumerateDeviceExtensionProperties(device, nullptr, &count, nullptr);
78     if (result != VK_SUCCESS) return false;
79 
80     extensions->resize(count);
81     result = vkEnumerateDeviceExtensionProperties(device, nullptr, &count, extensions->data());
82     if (result != VK_SUCCESS) return false;
83 
84     return true;
85 }
86 
hasExtension(const char * extension_name,const std::vector<VkExtensionProperties> & extensions)87 static bool hasExtension(const char* extension_name,
88                          const std::vector<VkExtensionProperties>& extensions) {
89     return std::find_if(extensions.cbegin(), extensions.cend(),
90                         [extension_name](const VkExtensionProperties& extension) {
91                             return strcmp(extension.extensionName, extension_name) == 0;
92                         }) != extensions.cend();
93 }
94 
init()95 bool VkInit::init() {
96   VkApplicationInfo appInfo = {
97       .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
98       .pNext = nullptr,
99       .pApplicationName = "VulkanGpuTest",
100       .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
101       .pEngineName = "VulkanGpuTestEngine",
102       .engineVersion = VK_MAKE_VERSION(1, 0, 0),
103       .apiVersion = VK_MAKE_VERSION(1, 1, 0),
104   };
105   std::vector<const char *> instanceExt;
106   instanceExt.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
107   VkInstanceCreateInfo createInfo = {
108       .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
109       .pNext = nullptr,
110       .pApplicationInfo = &appInfo,
111       .enabledLayerCount = 0,
112       .ppEnabledLayerNames = nullptr,
113       .enabledExtensionCount = static_cast<uint32_t>(instanceExt.size()),
114       .ppEnabledExtensionNames = instanceExt.data(),
115   };
116   VK_CALL(vkCreateInstance(&createInfo, nullptr, &mInstance));
117 
118   // Find a GPU to use.
119   uint32_t gpuCount = 1;
120   int status = vkEnumeratePhysicalDevices(mInstance, &gpuCount, &mGpu);
121   ASSERT(status == VK_SUCCESS || status == VK_INCOMPLETE);
122   ASSERT(gpuCount > 0);
123 
124   VkPhysicalDeviceProperties physicalDeviceProperties;
125   vkGetPhysicalDeviceProperties(mGpu, &physicalDeviceProperties);
126   std::vector<const char *> deviceExt;
127   if (physicalDeviceProperties.apiVersion < VK_API_VERSION_1_1) {
128       deviceExt.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
129       deviceExt.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
130       deviceExt.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
131       deviceExt.push_back(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME);
132       deviceExt.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
133   }
134   deviceExt.push_back(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);
135   deviceExt.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
136   deviceExt.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
137 
138   std::vector<VkExtensionProperties> supportedDeviceExtensions;
139   ASSERT(enumerateDeviceExtensions(mGpu, &supportedDeviceExtensions));
140   for (const auto extension : deviceExt) {
141       ASSERT(hasExtension(extension, supportedDeviceExtensions));
142   }
143 
144   const VkPhysicalDeviceExternalSemaphoreInfo externalSemaphoreInfo = {
145           VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
146           nullptr,
147           VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
148   };
149   VkExternalSemaphoreProperties externalSemaphoreProperties;
150   vkGetPhysicalDeviceExternalSemaphoreProperties(mGpu, &externalSemaphoreInfo,
151                                                  &externalSemaphoreProperties);
152 
153   ASSERT(externalSemaphoreProperties.externalSemaphoreFeatures &
154          VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
155 
156   uint32_t queueFamilyCount = 0;
157   vkGetPhysicalDeviceQueueFamilyProperties(mGpu, &queueFamilyCount, nullptr);
158   ASSERT(queueFamilyCount != 0);
159   std::vector<VkQueueFamilyProperties> queueFamilyProperties(queueFamilyCount);
160   vkGetPhysicalDeviceQueueFamilyProperties(mGpu, &queueFamilyCount,
161                                            queueFamilyProperties.data());
162 
163   uint32_t queueFamilyIndex;
164   for (queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount;
165        ++queueFamilyIndex) {
166     if (queueFamilyProperties[queueFamilyIndex].queueFlags &
167         VK_QUEUE_GRAPHICS_BIT)
168       break;
169   }
170   ASSERT(queueFamilyIndex < queueFamilyCount);
171   mQueueFamilyIndex = queueFamilyIndex;
172 
173   float priorities[] = {1.0f};
174   VkDeviceQueueCreateInfo queueCreateInfo{
175       .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
176       .pNext = nullptr,
177       .flags = 0,
178       .queueFamilyIndex = queueFamilyIndex,
179       .queueCount = 1,
180       .pQueuePriorities = priorities,
181   };
182 
183   VkDeviceCreateInfo deviceCreateInfo{
184       .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
185       .pNext = nullptr,
186       .queueCreateInfoCount = 1,
187       .pQueueCreateInfos = &queueCreateInfo,
188       .enabledLayerCount = 0,
189       .ppEnabledLayerNames = nullptr,
190       .enabledExtensionCount = static_cast<uint32_t>(deviceExt.size()),
191       .ppEnabledExtensionNames = deviceExt.data(),
192       .pEnabledFeatures = nullptr,
193   };
194 
195   VK_CALL(vkCreateDevice(mGpu, &deviceCreateInfo, nullptr, &mDevice));
196 
197   if (physicalDeviceProperties.apiVersion < VK_API_VERSION_1_1) {
198       mPfnBindImageMemory2 =
199               (PFN_vkBindImageMemory2)vkGetDeviceProcAddr(mDevice, "vkBindImageMemory2KHR");
200       mPfnGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)
201               vkGetDeviceProcAddr(mDevice, "vkGetImageMemoryRequirements2KHR");
202       mPfnCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion)
203               vkGetDeviceProcAddr(mDevice, "vkCreateSamplerYcbcrConversionKHR");
204       mPfnDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion)
205               vkGetDeviceProcAddr(mDevice, "vkDestroySamplerYcbcrConversionKHR");
206   } else {
207       mPfnBindImageMemory2 =
208               (PFN_vkBindImageMemory2)vkGetDeviceProcAddr(mDevice, "vkBindImageMemory2");
209       mPfnGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)
210               vkGetDeviceProcAddr(mDevice, "vkGetImageMemoryRequirements2");
211       mPfnCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion)
212               vkGetDeviceProcAddr(mDevice, "vkCreateSamplerYcbcrConversion");
213       mPfnDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion)
214               vkGetDeviceProcAddr(mDevice, "vkDestroySamplerYcbcrConversion");
215   }
216   ASSERT(mPfnBindImageMemory2);
217   ASSERT(mPfnGetImageMemoryRequirements2);
218   ASSERT(mPfnCreateSamplerYcbcrConversion);
219   ASSERT(mPfnDestroySamplerYcbcrConversion);
220 
221   mPfnGetAndroidHardwareBufferProperties = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)
222           vkGetDeviceProcAddr(mDevice, "vkGetAndroidHardwareBufferPropertiesANDROID");
223   ASSERT(mPfnGetAndroidHardwareBufferProperties);
224 
225   mPfnImportSemaphoreFd =
226           (PFN_vkImportSemaphoreFdKHR)vkGetDeviceProcAddr(mDevice, "vkImportSemaphoreFdKHR");
227   ASSERT(mPfnImportSemaphoreFd);
228 
229   VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR ycbcrFeatures{
230       .sType =
231           VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR,
232       .pNext = nullptr,
233   };
234   VkPhysicalDeviceFeatures2KHR physicalDeviceFeatures{
235       .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
236       .pNext = &ycbcrFeatures,
237   };
238   vkGetPhysicalDeviceFeatures2(mGpu, &physicalDeviceFeatures);
239   ASSERT(ycbcrFeatures.samplerYcbcrConversion == VK_TRUE);
240 
241   vkGetDeviceQueue(mDevice, 0, 0, &mQueue);
242   vkGetPhysicalDeviceMemoryProperties(mGpu, &mMemoryProperties);
243 
244   return true;
245 }
246 
~VkInit()247 VkInit::~VkInit() {
248   if (mQueue != VK_NULL_HANDLE) {
249     // Queues are implicitly destroyed with the device.
250     mQueue = VK_NULL_HANDLE;
251   }
252   if (mDevice != VK_NULL_HANDLE) {
253     vkDestroyDevice(mDevice, nullptr);
254     mDevice = VK_NULL_HANDLE;
255   }
256   if (mInstance != VK_NULL_HANDLE) {
257     vkDestroyInstance(mInstance, nullptr);
258     mInstance = VK_NULL_HANDLE;
259   }
260 }
261 
findMemoryType(uint32_t memoryTypeBitsRequirement,VkFlags requirementsMask)262 uint32_t VkInit::findMemoryType(uint32_t memoryTypeBitsRequirement,
263                                 VkFlags requirementsMask) {
264   for (uint32_t memoryIndex = 0; memoryIndex < VK_MAX_MEMORY_TYPES;
265        ++memoryIndex) {
266     const uint32_t memoryTypeBits = (1 << memoryIndex);
267     const bool isRequiredMemoryType =
268         memoryTypeBitsRequirement & memoryTypeBits;
269     const bool satisfiesFlags =
270         (mMemoryProperties.memoryTypes[memoryIndex].propertyFlags &
271          requirementsMask) == requirementsMask;
272     if (isRequiredMemoryType && satisfiesFlags)
273       return memoryIndex;
274   }
275 
276   // failed to find memory type.
277   ALOGE("Couldn't find required memory type.");
278   return 0;
279 }
280 
VkAHardwareBufferImage(VkInit * init)281 VkAHardwareBufferImage::VkAHardwareBufferImage(VkInit *init) : mInit(init) {}
282 
init(AHardwareBuffer * buffer,bool useExternalFormat,int syncFd)283 bool VkAHardwareBufferImage::init(AHardwareBuffer *buffer, bool useExternalFormat, int syncFd) {
284   AHardwareBuffer_Desc bufferDesc;
285   AHardwareBuffer_describe(buffer, &bufferDesc);
286   ASSERT(bufferDesc.layers == 1);
287 
288   VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
289       .sType =
290           VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
291       .pNext = nullptr,
292   };
293   VkAndroidHardwareBufferPropertiesANDROID properties = {
294       .sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
295       .pNext = &formatInfo,
296   };
297   VK_CALL(mInit->mPfnGetAndroidHardwareBufferProperties(mInit->device(), buffer, &properties));
298   ASSERT(useExternalFormat || formatInfo.format != VK_FORMAT_UNDEFINED);
299   // Create an image to bind to our AHardwareBuffer.
300   VkExternalFormatANDROID externalFormat{
301       .sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
302       .pNext = nullptr,
303       .externalFormat = formatInfo.externalFormat,
304   };
305   VkExternalMemoryImageCreateInfo externalCreateInfo{
306       .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
307       .pNext = useExternalFormat ? &externalFormat : nullptr,
308       .handleTypes =
309           VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
310   };
311   VkImageCreateInfo createInfo{
312       .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
313       .pNext = &externalCreateInfo,
314       .flags = 0u,
315       .imageType = VK_IMAGE_TYPE_2D,
316       .format = useExternalFormat ? VK_FORMAT_UNDEFINED : formatInfo.format,
317       .extent =
318           {
319               bufferDesc.width, bufferDesc.height, 1u,
320           },
321       .mipLevels = 1u,
322       .arrayLayers = 1u,
323       .samples = VK_SAMPLE_COUNT_1_BIT,
324       .tiling = VK_IMAGE_TILING_OPTIMAL,
325       .usage = VK_IMAGE_USAGE_SAMPLED_BIT,
326       .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
327       .queueFamilyIndexCount = 0,
328       .pQueueFamilyIndices = nullptr,
329       .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
330   };
331   VK_CALL(vkCreateImage(mInit->device(), &createInfo, nullptr, &mImage));
332 
333   VkImportAndroidHardwareBufferInfoANDROID androidHardwareBufferInfo{
334       .sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
335       .pNext = nullptr,
336       .buffer = buffer,
337   };
338   VkMemoryDedicatedAllocateInfo memoryAllocateInfo{
339       .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
340       .pNext = &androidHardwareBufferInfo,
341       .image = mImage,
342       .buffer = VK_NULL_HANDLE,
343   };
344   VkMemoryAllocateInfo allocateInfo{
345       .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
346       .pNext = &memoryAllocateInfo,
347       .allocationSize = properties.allocationSize,
348       .memoryTypeIndex = mInit->findMemoryType(
349           properties.memoryTypeBits, 0u /* requirementsMask */),
350   };
351 
352   VK_CALL(vkAllocateMemory(mInit->device(), &allocateInfo, nullptr, &mMemory));
353   VkBindImageMemoryInfo bindImageInfo;
354   bindImageInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
355   bindImageInfo.pNext = nullptr;
356   bindImageInfo.image = mImage;
357   bindImageInfo.memory = mMemory;
358   bindImageInfo.memoryOffset = 0;
359 
360   VK_CALL(mInit->mPfnBindImageMemory2(mInit->device(), 1, &bindImageInfo));
361 
362   VkImageMemoryRequirementsInfo2 memReqsInfo;
363   memReqsInfo.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
364   memReqsInfo.pNext = nullptr;
365   memReqsInfo.image = mImage;
366 
367   VkMemoryDedicatedRequirements dedicatedMemReqs;
368   dedicatedMemReqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
369   dedicatedMemReqs.pNext = nullptr;
370 
371   VkMemoryRequirements2 memReqs;
372   memReqs.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
373   memReqs.pNext = &dedicatedMemReqs;
374 
375   mInit->mPfnGetImageMemoryRequirements2(mInit->device(), &memReqsInfo, &memReqs);
376   ASSERT(VK_TRUE == dedicatedMemReqs.prefersDedicatedAllocation);
377   ASSERT(VK_TRUE == dedicatedMemReqs.requiresDedicatedAllocation);
378 
379   if (useExternalFormat /* TODO: || explicit format requires conversion */) {
380     VkSamplerYcbcrConversionCreateInfo conversionCreateInfo{
381         .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
382         .pNext = &externalFormat,
383         .format = useExternalFormat ? VK_FORMAT_UNDEFINED : formatInfo.format,
384         .ycbcrModel = formatInfo.suggestedYcbcrModel,
385         .ycbcrRange = formatInfo.suggestedYcbcrRange,
386         .components = formatInfo.samplerYcbcrConversionComponents,
387         .xChromaOffset = formatInfo.suggestedXChromaOffset,
388         .yChromaOffset = formatInfo.suggestedYChromaOffset,
389         .chromaFilter = VK_FILTER_NEAREST,
390         .forceExplicitReconstruction = VK_FALSE,
391     };
392     VK_CALL(mInit->mPfnCreateSamplerYcbcrConversion(mInit->device(), &conversionCreateInfo, nullptr,
393                                                     &mConversion));
394   }
395   VkSamplerYcbcrConversionInfo samplerConversionInfo{
396       .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
397       .pNext = &externalFormat,
398       .conversion = mConversion,
399   };
400 
401   VkSamplerCreateInfo samplerCreateInfo{
402       .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
403       .pNext =
404           (mConversion == VK_NULL_HANDLE) ? nullptr : &samplerConversionInfo,
405       .magFilter = VK_FILTER_NEAREST,
406       .minFilter = VK_FILTER_NEAREST,
407       .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
408       .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
409       .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
410       .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
411       .mipLodBias = 0.0f,
412       .anisotropyEnable = VK_FALSE,
413       .maxAnisotropy = 1,
414       .compareEnable = VK_FALSE,
415       .compareOp = VK_COMPARE_OP_NEVER,
416       .minLod = 0.0f,
417       .maxLod = 0.0f,
418       .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
419       .unnormalizedCoordinates = VK_FALSE,
420   };
421   VK_CALL(
422       vkCreateSampler(mInit->device(), &samplerCreateInfo, nullptr, &mSampler));
423 
424   VkImageViewCreateInfo viewCreateInfo{
425       .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
426       .pNext =
427           (mConversion == VK_NULL_HANDLE) ? nullptr : &samplerConversionInfo,
428       .flags = 0,
429       .image = mImage,
430       .viewType = VK_IMAGE_VIEW_TYPE_2D,
431       .format = useExternalFormat ? VK_FORMAT_UNDEFINED : formatInfo.format,
432       .components =
433           {
434               VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
435               VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
436           },
437       .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
438   };
439   VK_CALL(vkCreateImageView(mInit->device(), &viewCreateInfo, nullptr, &mView));
440 
441   // Create semaphore if necessary.
442   if (syncFd != -1) {
443     VkSemaphoreCreateInfo semaphoreCreateInfo{
444         .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
445         .pNext = nullptr,
446         .flags = 0,
447     };
448     VK_CALL(vkCreateSemaphore(mInit->device(), &semaphoreCreateInfo, nullptr,
449                               &mSemaphore));
450 
451     // Import the fd into a semaphore.
452     VkImportSemaphoreFdInfoKHR importSemaphoreInfo{
453         .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
454         .pNext = nullptr,
455         .semaphore = mSemaphore,
456         .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
457         .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
458         .fd = syncFd,
459     };
460     VK_CALL(mInit->mPfnImportSemaphoreFd(mInit->device(), &importSemaphoreInfo));
461   }
462 
463   return true;
464 }
465 
~VkAHardwareBufferImage()466 VkAHardwareBufferImage::~VkAHardwareBufferImage() {
467   if (mView != VK_NULL_HANDLE) {
468     vkDestroyImageView(mInit->device(), mView, nullptr);
469     mView = VK_NULL_HANDLE;
470   }
471   if (mSampler != VK_NULL_HANDLE) {
472     vkDestroySampler(mInit->device(), mSampler, nullptr);
473     mSampler = VK_NULL_HANDLE;
474   }
475   if (mConversion != VK_NULL_HANDLE) {
476     mInit->mPfnDestroySamplerYcbcrConversion(mInit->device(), mConversion, nullptr);
477   }
478   if (mMemory != VK_NULL_HANDLE) {
479     vkFreeMemory(mInit->device(), mMemory, nullptr);
480     mMemory = VK_NULL_HANDLE;
481   }
482   if (mImage != VK_NULL_HANDLE) {
483     vkDestroyImage(mInit->device(), mImage, nullptr);
484     mImage = VK_NULL_HANDLE;
485   }
486   if (mSemaphore != VK_NULL_HANDLE) {
487     vkDestroySemaphore(mInit->device(), mSemaphore, nullptr);
488     mSemaphore = VK_NULL_HANDLE;
489   }
490 }
491 
VkImageRenderer(VkInit * init,uint32_t width,uint32_t height,VkFormat format,uint32_t bytesPerPixel)492 VkImageRenderer::VkImageRenderer(VkInit *init, uint32_t width, uint32_t height,
493                                  VkFormat format, uint32_t bytesPerPixel)
494     : mInit(init), mWidth(width), mHeight(height), mFormat(format),
495       mResultBufferSize(width * height * bytesPerPixel) {}
496 
init(JNIEnv * env,jobject assetMgr)497 bool VkImageRenderer::init(JNIEnv *env, jobject assetMgr) {
498   // Create an image to back our framebuffer.
499   {
500     const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
501                                          VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
502                                          VK_IMAGE_USAGE_TRANSFER_DST_BIT;
503     const VkImageCreateInfo imageCreateInfo{
504         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
505         .pNext = nullptr,
506         .flags = 0u,
507         .imageType = VK_IMAGE_TYPE_2D,
508         .format = mFormat,
509         .extent = {mWidth, mHeight, 1u},
510         .mipLevels = 1u,
511         .arrayLayers = 1u,
512         .samples = VK_SAMPLE_COUNT_1_BIT,
513         .tiling = VK_IMAGE_TILING_OPTIMAL,
514         .usage = imageUsage,
515         .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
516         .queueFamilyIndexCount = 0u,
517         .pQueueFamilyIndices = nullptr,
518         .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
519     };
520     VK_CALL(
521         vkCreateImage(mInit->device(), &imageCreateInfo, nullptr, &mDestImage));
522 
523     // Get memory requirements for image and allocate memory backing.
524     VkMemoryRequirements memoryRequirements;
525     vkGetImageMemoryRequirements(mInit->device(), mDestImage,
526                                  &memoryRequirements);
527 
528     VkMemoryAllocateInfo memoryAllocateInfo{
529         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
530         .pNext = nullptr,
531         .allocationSize = memoryRequirements.size,
532         .memoryTypeIndex =
533             mInit->findMemoryType(memoryRequirements.memoryTypeBits, 0u),
534     };
535     VK_CALL(vkAllocateMemory(mInit->device(), &memoryAllocateInfo, nullptr,
536                              &mDestImageMemory));
537     VK_CALL(
538         vkBindImageMemory(mInit->device(), mDestImage, mDestImageMemory, 0));
539   }
540 
541   // Create image view.
542   {
543     VkImageViewCreateInfo imageViewCreateInfo{
544         .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
545         .pNext = nullptr,
546         .flags = 0u,
547         .image = mDestImage,
548         .viewType = VK_IMAGE_VIEW_TYPE_2D,
549         .format = mFormat,
550         .components = {VK_COMPONENT_SWIZZLE_IDENTITY,
551                        VK_COMPONENT_SWIZZLE_IDENTITY,
552                        VK_COMPONENT_SWIZZLE_IDENTITY,
553                        VK_COMPONENT_SWIZZLE_IDENTITY},
554         .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u},
555     };
556     VK_CALL(vkCreateImageView(mInit->device(), &imageViewCreateInfo, nullptr,
557                               &mDestImageView));
558   }
559 
560   // Create render pass
561   {
562     VkAttachmentDescription attachmentDesc{
563         .flags = 0u,
564         .format = mFormat,
565         .samples = VK_SAMPLE_COUNT_1_BIT,
566         .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
567         .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
568         .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
569         .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
570         .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
571         .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
572     VkAttachmentReference attachmentRef{
573         .attachment = 0u, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
574     };
575     VkSubpassDescription subpassDesc{
576         .flags = 0u,
577         .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
578         .inputAttachmentCount = 0u,
579         .pInputAttachments = nullptr,
580         .colorAttachmentCount = 1u,
581         .pColorAttachments = &attachmentRef,
582         .pResolveAttachments = nullptr,
583         .pDepthStencilAttachment = nullptr,
584         .preserveAttachmentCount = 0u,
585         .pPreserveAttachments = nullptr,
586     };
587     VkRenderPassCreateInfo renderPassCreateInfo{
588         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
589         .pNext = nullptr,
590         .flags = 0u,
591         .attachmentCount = 1u,
592         .pAttachments = &attachmentDesc,
593         .subpassCount = 1u,
594         .pSubpasses = &subpassDesc,
595         .dependencyCount = 0u,
596         .pDependencies = nullptr,
597     };
598     VK_CALL(vkCreateRenderPass(mInit->device(), &renderPassCreateInfo, nullptr,
599                                &mRenderPass));
600   }
601 
602   // Create vertex buffer.
603   {
604     const float vertexData[] = {
605         -1.0f, -1.0f, 0.0f, 0.0f, 1.0f,  -1.0f, 1.0f, 0.0f,
606         1.0f,  1.0f,  1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
607         1.0f,  1.0f,  1.0f, 1.0f, -1.0f, 1.0f,  0.0f, 1.0f,
608     };
609     VkBufferCreateInfo createBufferInfo{
610         .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
611         .pNext = nullptr,
612         .flags = 0,
613         .size = sizeof(vertexData),
614         .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
615         .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
616         .queueFamilyIndexCount = 0,
617         .pQueueFamilyIndices = nullptr,
618     };
619     VK_CALL(vkCreateBuffer(mInit->device(), &createBufferInfo, nullptr,
620                            &mVertexBuffer));
621 
622     VkMemoryRequirements memReq;
623     vkGetBufferMemoryRequirements(mInit->device(), mVertexBuffer, &memReq);
624     VkMemoryAllocateInfo allocInfo{
625         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
626         .pNext = nullptr,
627         .allocationSize = memReq.size,
628         .memoryTypeIndex = mInit->findMemoryType(
629             memReq.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
630                                        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT),
631     };
632     VK_CALL(vkAllocateMemory(mInit->device(), &allocInfo, nullptr,
633                              &mVertexBufferMemory));
634 
635     void *mappedData;
636     VK_CALL(vkMapMemory(mInit->device(), mVertexBufferMemory, 0,
637                         sizeof(vertexData), 0, &mappedData));
638     memcpy(mappedData, vertexData, sizeof(vertexData));
639     vkUnmapMemory(mInit->device(), mVertexBufferMemory);
640 
641     VK_CALL(vkBindBufferMemory(mInit->device(), mVertexBuffer,
642                                mVertexBufferMemory, 0));
643   }
644 
645   // Create framebuffer.
646   {
647     VkFramebufferCreateInfo framebufferCreateInfo{
648         .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
649         .pNext = nullptr,
650         .flags = 0u,
651         .renderPass = mRenderPass,
652         .attachmentCount = 1u,
653         .pAttachments = &mDestImageView,
654         .width = mWidth,
655         .height = mHeight,
656         .layers = 1u,
657     };
658     VK_CALL(vkCreateFramebuffer(mInit->device(), &framebufferCreateInfo,
659                                 nullptr, &mFramebuffer));
660   }
661 
662   // Create the host-side buffer which will be used to read back the results.
663   {
664     VkBufferCreateInfo bufferCreateInfo{
665         .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
666         .pNext = nullptr,
667         .flags = 0u,
668         .size = mResultBufferSize,
669         .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
670         .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
671         .queueFamilyIndexCount = 0u,
672         .pQueueFamilyIndices = nullptr,
673     };
674     VK_CALL(vkCreateBuffer(mInit->device(), &bufferCreateInfo, nullptr,
675                            &mResultBuffer));
676 
677     VkMemoryRequirements memReq;
678     vkGetBufferMemoryRequirements(mInit->device(), mResultBuffer, &memReq);
679     VkMemoryAllocateInfo allocInfo{
680         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
681         .pNext = nullptr,
682         .allocationSize = memReq.size,
683         .memoryTypeIndex = mInit->findMemoryType(
684             memReq.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
685                                        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT),
686     };
687     VK_CALL(vkAllocateMemory(mInit->device(), &allocInfo, nullptr,
688                              &mResultBufferMemory));
689     VK_CALL(vkBindBufferMemory(mInit->device(), mResultBuffer,
690                                mResultBufferMemory, 0));
691   }
692 
693   // Create shaders.
694   {
695     AAsset *vertFile =
696         AAssetManager_open(AAssetManager_fromJava(env, assetMgr),
697                            "shaders/passthrough_vsh.spv", AASSET_MODE_BUFFER);
698     ASSERT(vertFile);
699     size_t vertShaderLength = AAsset_getLength(vertFile);
700     std::vector<uint8_t> vertShader;
701     vertShader.resize(vertShaderLength);
702     AAsset_read(vertFile, static_cast<void *>(vertShader.data()),
703                 vertShaderLength);
704     AAsset_close(vertFile);
705 
706     AAsset *pixelFile =
707         AAssetManager_open(AAssetManager_fromJava(env, assetMgr),
708                            "shaders/passthrough_fsh.spv", AASSET_MODE_BUFFER);
709     ASSERT(pixelFile);
710     size_t pixelShaderLength = AAsset_getLength(pixelFile);
711     std::vector<uint8_t> pixelShader;
712     pixelShader.resize(pixelShaderLength);
713     AAsset_read(pixelFile, static_cast<void *>(pixelShader.data()),
714                 pixelShaderLength);
715     AAsset_close(pixelFile);
716 
717     VkShaderModuleCreateInfo vertexShaderInfo{
718         .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
719         .pNext = nullptr,
720         .flags = 0u,
721         .codeSize = vertShaderLength,
722         .pCode = reinterpret_cast<const uint32_t *>(vertShader.data()),
723     };
724     VK_CALL(vkCreateShaderModule(mInit->device(), &vertexShaderInfo, nullptr,
725                                  &mVertModule));
726 
727     VkShaderModuleCreateInfo pixelShaderInfo{
728         .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
729         .pNext = nullptr,
730         .flags = 0u,
731         .codeSize = pixelShaderLength,
732         .pCode = reinterpret_cast<const uint32_t *>(pixelShader.data()),
733     };
734     VK_CALL(vkCreateShaderModule(mInit->device(), &pixelShaderInfo, nullptr,
735                                  &mPixelModule));
736   }
737 
738   VkPipelineCacheCreateInfo pipelineCacheInfo{
739       .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
740       .pNext = nullptr,
741       .flags = 0, // reserved, must be 0
742       .initialDataSize = 0,
743       .pInitialData = nullptr,
744   };
745   VK_CALL(vkCreatePipelineCache(mInit->device(), &pipelineCacheInfo, nullptr,
746                                 &mCache));
747 
748   // Create Descriptor Pool
749   {
750     const VkDescriptorPoolSize typeCount = {
751         .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 1,
752     };
753     const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{
754         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
755         .pNext = nullptr,
756         .maxSets = 1,
757         .poolSizeCount = 1,
758         .pPoolSizes = &typeCount,
759     };
760 
761     VK_CALL(vkCreateDescriptorPool(mInit->device(), &descriptorPoolCreateInfo,
762                                    nullptr, &mDescriptorPool));
763   }
764 
765   // Create command pool.
766   {
767     VkCommandPoolCreateInfo cmdPoolCreateInfo{
768         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
769         .pNext = nullptr,
770         .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
771         .queueFamilyIndex = 0,
772     };
773     VK_CALL(vkCreateCommandPool(mInit->device(), &cmdPoolCreateInfo, nullptr,
774                                 &mCmdPool));
775   }
776 
777   // Create a fence
778   {
779     VkFenceCreateInfo fenceInfo = {
780         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
781         .pNext = nullptr,
782         .flags = 0,
783     };
784     VK_CALL(vkCreateFence(mInit->device(), &fenceInfo, nullptr, &mFence));
785   }
786 
787   return true;
788 }
789 
~VkImageRenderer()790 VkImageRenderer::~VkImageRenderer() {
791   cleanUpTemporaries();
792 
793   if (mCmdPool != VK_NULL_HANDLE) {
794     vkDestroyCommandPool(mInit->device(), mCmdPool, nullptr);
795     mCmdPool = VK_NULL_HANDLE;
796   }
797   if (mDescriptorPool != VK_NULL_HANDLE) {
798     vkDestroyDescriptorPool(mInit->device(), mDescriptorPool, nullptr);
799     mDescriptorPool = VK_NULL_HANDLE;
800   }
801   if (mDestImageView != VK_NULL_HANDLE) {
802     vkDestroyImageView(mInit->device(), mDestImageView, nullptr);
803     mDestImageView = VK_NULL_HANDLE;
804   }
805   if (mDestImage != VK_NULL_HANDLE) {
806     vkDestroyImage(mInit->device(), mDestImage, nullptr);
807     mDestImage = VK_NULL_HANDLE;
808   }
809   if (mDestImageMemory != VK_NULL_HANDLE) {
810     vkFreeMemory(mInit->device(), mDestImageMemory, nullptr);
811     mDestImageMemory = VK_NULL_HANDLE;
812   }
813   if (mResultBuffer != VK_NULL_HANDLE) {
814     vkDestroyBuffer(mInit->device(), mResultBuffer, nullptr);
815     mResultBuffer = VK_NULL_HANDLE;
816   }
817   if (mResultBufferMemory != VK_NULL_HANDLE) {
818     vkFreeMemory(mInit->device(), mResultBufferMemory, nullptr);
819     mResultBufferMemory = VK_NULL_HANDLE;
820   }
821   if (mRenderPass != VK_NULL_HANDLE) {
822     vkDestroyRenderPass(mInit->device(), mRenderPass, nullptr);
823     mRenderPass = VK_NULL_HANDLE;
824   }
825   if (mVertexBuffer != VK_NULL_HANDLE) {
826     vkDestroyBuffer(mInit->device(), mVertexBuffer, nullptr);
827     mVertexBuffer = VK_NULL_HANDLE;
828   }
829   if (mVertexBufferMemory != VK_NULL_HANDLE) {
830     vkFreeMemory(mInit->device(), mVertexBufferMemory, nullptr);
831     mVertexBufferMemory = VK_NULL_HANDLE;
832   }
833   if (mFramebuffer != VK_NULL_HANDLE) {
834     vkDestroyFramebuffer(mInit->device(), mFramebuffer, nullptr);
835     mFramebuffer = VK_NULL_HANDLE;
836   }
837   if (mCache != VK_NULL_HANDLE) {
838     vkDestroyPipelineCache(mInit->device(), mCache, nullptr);
839     mCache = VK_NULL_HANDLE;
840   }
841   if (mVertModule != VK_NULL_HANDLE) {
842     vkDestroyShaderModule(mInit->device(), mVertModule, nullptr);
843     mVertModule = VK_NULL_HANDLE;
844   }
845   if (mPixelModule != VK_NULL_HANDLE) {
846     vkDestroyShaderModule(mInit->device(), mPixelModule, nullptr);
847     mPixelModule = VK_NULL_HANDLE;
848   }
849   if (mFence != VK_NULL_HANDLE) {
850     vkDestroyFence(mInit->device(), mFence, nullptr);
851     mFence = VK_NULL_HANDLE;
852   }
853 }
854 
renderImageAndReadback(VkImage image,VkSampler sampler,VkImageView view,VkSemaphore semaphore,bool useExternalFormat,std::vector<uint32_t> * data)855 bool VkImageRenderer::renderImageAndReadback(VkImage image, VkSampler sampler,
856                                              VkImageView view,
857                                              VkSemaphore semaphore,
858                                              bool useExternalFormat,
859                                              std::vector<uint32_t> *data) {
860   std::vector<uint8_t> unconvertedData;
861   ASSERT(renderImageAndReadback(image, sampler, view, semaphore,
862                                 useExternalFormat, &unconvertedData));
863   if ((unconvertedData.size() % sizeof(uint32_t)) != 0)
864     return false;
865 
866   const uint32_t *dataPtr =
867       reinterpret_cast<const uint32_t *>(unconvertedData.data());
868   *data = std::vector<uint32_t>(dataPtr, dataPtr + unconvertedData.size() /
869                                                        sizeof(uint32_t));
870   return true;
871 }
872 
renderImageAndReadback(VkImage image,VkSampler sampler,VkImageView view,VkSemaphore semaphore,bool useImmutableSampler,std::vector<uint8_t> * data)873 bool VkImageRenderer::renderImageAndReadback(VkImage image, VkSampler sampler,
874                                              VkImageView view,
875                                              VkSemaphore semaphore,
876                                              bool useImmutableSampler,
877                                              std::vector<uint8_t> *data) {
878   cleanUpTemporaries();
879 
880   // Create graphics pipeline.
881   {
882     VkDescriptorSetLayoutBinding descriptorSetLayoutBinding{
883         .binding = 0,
884         .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
885         .descriptorCount = 1u,
886         .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
887         .pImmutableSamplers = useImmutableSampler ? &sampler : nullptr,
888     };
889     const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
890         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
891         .pNext = nullptr,
892         .bindingCount = 1,
893         .pBindings = &descriptorSetLayoutBinding,
894     };
895     VK_CALL(vkCreateDescriptorSetLayout(mInit->device(),
896                                         &descriptorSetLayoutCreateInfo, nullptr,
897                                         &mDescriptorLayout));
898 
899     VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
900         .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
901         .pNext = nullptr,
902         .setLayoutCount = 1,
903         .pSetLayouts = &mDescriptorLayout,
904         .pushConstantRangeCount = 0,
905         .pPushConstantRanges = nullptr,
906     };
907 
908     VK_CALL(vkCreatePipelineLayout(mInit->device(), &pipelineLayoutCreateInfo,
909                                    nullptr, &mLayout));
910 
911     VkPipelineShaderStageCreateInfo shaderStageParams[2] = {
912         {
913             .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
914             .pNext = nullptr,
915             .flags = 0,
916             .stage = VK_SHADER_STAGE_VERTEX_BIT,
917             .module = mVertModule,
918             .pName = "main",
919             .pSpecializationInfo = nullptr,
920         },
921         {
922             .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
923             .pNext = nullptr,
924             .flags = 0,
925             .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
926             .module = mPixelModule,
927             .pName = "main",
928             .pSpecializationInfo = nullptr,
929         }};
930 
931     VkViewport viewports{
932         .x = 0,
933         .y = 0,
934         .width = static_cast<float>(mWidth),
935         .height = static_cast<float>(mHeight),
936         .minDepth = 0.0f,
937         .maxDepth = 1.0f,
938     };
939 
940     VkRect2D scissor = {
941       .offset = {0, 0},
942       .extent = {mWidth, mHeight},
943     };
944     VkPipelineViewportStateCreateInfo viewportInfo{
945         .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
946         .pNext = nullptr,
947         .viewportCount = 1,
948         .pViewports = &viewports,
949         .scissorCount = 1,
950         .pScissors = &scissor,
951     };
952 
953     VkSampleMask sampleMask = ~0u;
954     VkPipelineMultisampleStateCreateInfo multisampleInfo{
955         .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
956         .pNext = nullptr,
957         .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
958         .sampleShadingEnable = VK_FALSE,
959         .minSampleShading = 0,
960         .pSampleMask = &sampleMask,
961         .alphaToCoverageEnable = VK_FALSE,
962         .alphaToOneEnable = VK_FALSE,
963     };
964     VkPipelineColorBlendAttachmentState attachmentStates{
965         .blendEnable = VK_FALSE,
966         .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
967                           VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
968     };
969     VkPipelineColorBlendStateCreateInfo colorBlendInfo{
970         .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
971         .pNext = nullptr,
972         .flags = 0,
973         .logicOpEnable = VK_FALSE,
974         .logicOp = VK_LOGIC_OP_COPY,
975         .attachmentCount = 1,
976         .pAttachments = &attachmentStates,
977     };
978     VkPipelineRasterizationStateCreateInfo rasterInfo{
979         .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
980         .pNext = nullptr,
981         .depthClampEnable = VK_FALSE,
982         .rasterizerDiscardEnable = VK_FALSE,
983         .polygonMode = VK_POLYGON_MODE_FILL,
984         .cullMode = VK_CULL_MODE_NONE,
985         .frontFace = VK_FRONT_FACE_CLOCKWISE,
986         .depthBiasEnable = VK_FALSE,
987         .lineWidth = 1,
988     };
989     VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo{
990         .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
991         .pNext = nullptr,
992         .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
993         .primitiveRestartEnable = VK_FALSE,
994     };
995 
996     // Specify vertex input state
997     VkVertexInputBindingDescription vertexInputBindingDescription{
998         .binding = 0u,
999         .stride = 4 * sizeof(float),
1000         .inputRate = VK_VERTEX_INPUT_RATE_VERTEX};
1001     VkVertexInputAttributeDescription vertex_input_attributes[2]{
1002         {
1003             .location = 0,
1004             .binding = 0,
1005             .format = VK_FORMAT_R32G32_SFLOAT,
1006             .offset = 0,
1007         },
1008         {
1009             .location = 1,
1010             .binding = 0,
1011             .format = VK_FORMAT_R32G32_SFLOAT,
1012             .offset = sizeof(float) * 2,
1013         }};
1014     VkPipelineVertexInputStateCreateInfo vertexInputInfo{
1015         .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
1016         .pNext = nullptr,
1017         .vertexBindingDescriptionCount = 1,
1018         .pVertexBindingDescriptions = &vertexInputBindingDescription,
1019         .vertexAttributeDescriptionCount = 2,
1020         .pVertexAttributeDescriptions = vertex_input_attributes,
1021     };
1022 
1023     // Create the pipeline
1024     VkGraphicsPipelineCreateInfo pipelineCreateInfo{
1025         .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
1026         .pNext = nullptr,
1027         .flags = 0,
1028         .stageCount = 2,
1029         .pStages = shaderStageParams,
1030         .pVertexInputState = &vertexInputInfo,
1031         .pInputAssemblyState = &inputAssemblyInfo,
1032         .pTessellationState = nullptr,
1033         .pViewportState = &viewportInfo,
1034         .pRasterizationState = &rasterInfo,
1035         .pMultisampleState = &multisampleInfo,
1036         .pDepthStencilState = nullptr,
1037         .pColorBlendState = &colorBlendInfo,
1038         .pDynamicState = 0u,
1039         .layout = mLayout,
1040         .renderPass = mRenderPass,
1041         .subpass = 0,
1042         .basePipelineHandle = VK_NULL_HANDLE,
1043         .basePipelineIndex = 0,
1044     };
1045 
1046     VK_CALL(vkCreateGraphicsPipelines(
1047         mInit->device(), mCache, 1, &pipelineCreateInfo, nullptr, &mPipeline));
1048   }
1049 
1050   // Create a command buffer.
1051   {
1052     VkCommandBufferAllocateInfo cmdBufferCreateInfo{
1053         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1054         .pNext = nullptr,
1055         .commandPool = mCmdPool,
1056         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1057         .commandBufferCount = 1,
1058     };
1059     VK_CALL(vkAllocateCommandBuffers(mInit->device(), &cmdBufferCreateInfo,
1060                                      &mCmdBuffer));
1061   }
1062 
1063   // Create the descriptor sets.
1064   {
1065     VkDescriptorSetAllocateInfo allocInfo{
1066         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1067         .pNext = nullptr,
1068         .descriptorPool = mDescriptorPool,
1069         .descriptorSetCount = 1,
1070         .pSetLayouts = &mDescriptorLayout};
1071     VK_CALL(
1072         vkAllocateDescriptorSets(mInit->device(), &allocInfo, &mDescriptorSet));
1073 
1074     VkDescriptorImageInfo texDesc{
1075         .sampler = sampler,
1076         .imageView = view,
1077         .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
1078     };
1079 
1080     VkWriteDescriptorSet writeDst{
1081         .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
1082         .pNext = nullptr,
1083         .dstSet = mDescriptorSet,
1084         .dstBinding = 0,
1085         .dstArrayElement = 0,
1086         .descriptorCount = 1,
1087         .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1088         .pImageInfo = &texDesc,
1089         .pBufferInfo = nullptr,
1090         .pTexelBufferView = nullptr};
1091     vkUpdateDescriptorSets(mInit->device(), 1, &writeDst, 0, nullptr);
1092   }
1093 
1094   // Begin Command Buffer
1095   {
1096     VkCommandBufferBeginInfo cmdBufferBeginInfo{
1097         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1098         .pNext = nullptr,
1099         .flags = 0u,
1100         .pInheritanceInfo = nullptr,
1101     };
1102 
1103     VK_CALL(vkBeginCommandBuffer(mCmdBuffer, &cmdBufferBeginInfo));
1104   }
1105 
1106   // Transition the provided resource so we can sample from it.
1107   addImageTransitionBarrier(
1108       mCmdBuffer, image, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1109       VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, VK_ACCESS_SHADER_READ_BIT,
1110       VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
1111       VK_QUEUE_FAMILY_FOREIGN_EXT, mInit->queueFamilyIndex());
1112 
1113   // Transition the destination texture for use as a framebuffer.
1114   addImageTransitionBarrier(
1115       mCmdBuffer, mDestImage, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1116       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
1117       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
1118       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
1119 
1120   // Begin Render Pass to draw the source resource to the framebuffer.
1121   {
1122     const VkClearValue clearValue{
1123         .color =
1124             {
1125                 .float32 = {0.0f, 0.0f, 0.0f, 0.0f},
1126             },
1127     };
1128     VkRenderPassBeginInfo renderPassBeginInfo{
1129         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1130         .pNext = nullptr,
1131         .renderPass = mRenderPass,
1132         .framebuffer = mFramebuffer,
1133         .renderArea = {{0, 0}, {mWidth, mHeight}},
1134         .clearValueCount = 1u,
1135         .pClearValues = &clearValue,
1136     };
1137     vkCmdBeginRenderPass(mCmdBuffer, &renderPassBeginInfo,
1138                          VK_SUBPASS_CONTENTS_INLINE);
1139   }
1140 
1141   /// Draw texture to renderpass.
1142   vkCmdBindPipeline(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, mPipeline);
1143   vkCmdBindDescriptorSets(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, mLayout,
1144                           0u, 1, &mDescriptorSet, 0u, nullptr);
1145   VkDeviceSize offset = 0;
1146   vkCmdBindVertexBuffers(mCmdBuffer, 0, 1, &mVertexBuffer, &offset);
1147   vkCmdDraw(mCmdBuffer, 6u, 1u, 0u, 0u);
1148   vkCmdEndRenderPass(mCmdBuffer);
1149 
1150   // Copy to our staging buffer.
1151   {
1152     VkBufferMemoryBarrier bufferBarrier{
1153         .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
1154         .pNext = nullptr,
1155         .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
1156         .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
1157         .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1158         .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1159         .buffer = mResultBuffer,
1160         .offset = 0u,
1161         .size = mResultBufferSize,
1162     };
1163 
1164     VkBufferImageCopy copyRegion{
1165         .bufferOffset = 0u,
1166         .bufferRowLength = mWidth,
1167         .bufferImageHeight = mHeight,
1168         .imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u},
1169         .imageOffset = {0, 0, 0},
1170         .imageExtent = {mWidth, mHeight, 1u}};
1171 
1172     addImageTransitionBarrier(
1173         mCmdBuffer, mDestImage, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1174         VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1175         VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1176         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
1177 
1178     vkCmdCopyImageToBuffer(mCmdBuffer, mDestImage,
1179                            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mResultBuffer,
1180                            1, &copyRegion);
1181 
1182     vkCmdPipelineBarrier(mCmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
1183                          VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0,
1184                          (const VkMemoryBarrier *)nullptr, 1, &bufferBarrier, 0,
1185                          (const VkImageMemoryBarrier *)nullptr);
1186   }
1187 
1188   VK_CALL(vkEndCommandBuffer(mCmdBuffer));
1189 
1190   VkPipelineStageFlags semaphoreWaitFlags =
1191       VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
1192   VkSubmitInfo submitInfo{
1193       .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1194       .pNext = nullptr,
1195       .waitSemaphoreCount = semaphore != VK_NULL_HANDLE ? 1u : 0u,
1196       .pWaitSemaphores = semaphore != VK_NULL_HANDLE ? &semaphore : nullptr,
1197       .pWaitDstStageMask =
1198           semaphore != VK_NULL_HANDLE ? &semaphoreWaitFlags : nullptr,
1199       .commandBufferCount = 1u,
1200       .pCommandBuffers = &mCmdBuffer,
1201       .signalSemaphoreCount = 0u,
1202       .pSignalSemaphores = nullptr,
1203   };
1204   VK_CALL(vkResetFences(mInit->device(), 1, &mFence))
1205   VK_CALL(vkQueueSubmit(mInit->queue(), 1, &submitInfo, mFence));
1206   VK_CALL(vkWaitForFences(mInit->device(), 1, &mFence, VK_TRUE,
1207                           ~(0ull) /* infinity */));
1208 
1209   void *outData;
1210   VK_CALL(vkMapMemory(mInit->device(), mResultBufferMemory, 0u,
1211                       mResultBufferSize, 0u, &outData));
1212   uint8_t *uData = reinterpret_cast<uint8_t *>(outData);
1213   *data = std::vector<uint8_t>(uData, uData + mResultBufferSize);
1214   vkUnmapMemory(mInit->device(), mResultBufferMemory);
1215 
1216   return true;
1217 }
1218 
cleanUpTemporaries()1219 void VkImageRenderer::cleanUpTemporaries() {
1220   if (mCmdBuffer != VK_NULL_HANDLE) {
1221     vkFreeCommandBuffers(mInit->device(), mCmdPool, 1, &mCmdBuffer);
1222     mCmdBuffer = VK_NULL_HANDLE;
1223   }
1224   if (mDescriptorSet != VK_NULL_HANDLE) {
1225     vkResetDescriptorPool(mInit->device(), mDescriptorPool, 0 /*flags*/);
1226     mDescriptorSet = VK_NULL_HANDLE;
1227   }
1228   if (mPipeline != VK_NULL_HANDLE) {
1229     vkDestroyPipeline(mInit->device(), mPipeline, nullptr);
1230     mPipeline = VK_NULL_HANDLE;
1231   }
1232   if (mDescriptorLayout != VK_NULL_HANDLE) {
1233     vkDestroyDescriptorSetLayout(mInit->device(), mDescriptorLayout, nullptr);
1234     mDescriptorLayout = VK_NULL_HANDLE;
1235   }
1236   if (mLayout != VK_NULL_HANDLE) {
1237     vkDestroyPipelineLayout(mInit->device(), mLayout, nullptr);
1238     mLayout = VK_NULL_HANDLE;
1239   }
1240 }
1241