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, ©Region);
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