• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "vulkan_example.h"
17 #include "vulkan/vulkan_ohos.h"
18 #include <cassert>
19 #include <iostream>
20 #include <string>
21 #include <utmp.h>
22 #include <vector>
23 #include <exception>
24 #include <array>
25 #include <cmath>
26 
27 namespace vkExample {
CheckResult(VkResult result)28 static bool inline CheckResult(VkResult result)
29 {
30     if (result != VK_SUCCESS) {
31         LOGE("Fatal : VkResult is %{public}d, in file:%{public}s, at line %{public}u",
32             static_cast<int>(result), __FILE__, __LINE__);
33         return false;
34     }
35     return true;
36 }
37 
38 // restore the NativeWindow*(will be used in CreateSurface)
SetupWindow(NativeWindow * nativeWindow)39 void VulkanExample::SetupWindow(NativeWindow* nativeWindow)
40 {
41     window = nativeWindow;
42 }
43 
InitVulkan()44 bool VulkanExample::InitVulkan()
45 {
46     bool res = true;
47     res &= CreateInstance();
48     utils::LoadVulkanFunctions(instance);
49     res &= CreateSurface();
50     res &= PickPhysicalDevice();
51     res &= CreateLogicalDevice();
52     utils::LoadVulkanFunctions(device);
53     inited = res;
54     return res;
55 }
56 
SetUp()57 void VulkanExample::SetUp()
58 {
59     CreateSwapChain();
60     CreateImageViews();
61     CreateRenderPass();
62     CreateDescriptorSetLayout();
63     CreateGraphicsPipeline();
64     CreateFramebuffers();
65     CreateCommandPool();
66     CreateVertices();
67     UpdateVertices();
68     CreateUniformBuffers();
69     CreateDescriptorPool();
70     CreateDescriptorSets();
71     CreateCommandBuffer();
72     CreateSyncObjects();
73 }
74 
RenderLoop()75 void VulkanExample::RenderLoop()
76 {
77     UpdateVertices();
78     DrawFrame();
79 }
80 
IsInited() const81 bool VulkanExample::IsInited() const
82 {
83     return inited;
84 }
85 
SetRecreateSwapChain()86 void VulkanExample::SetRecreateSwapChain()
87 {
88     shouldRecreate = true;
89 }
90 
91 // Load libvulkan.so
VulkanExample()92 VulkanExample::VulkanExample()
93 {
94     utils::LoadVulkanLibrary();
95 }
96 
~VulkanExample()97 VulkanExample::~VulkanExample()
98 {
99     vkDestroySemaphore(device, renderFinishedSemaphore, nullptr);
100     vkDestroySemaphore(device, imageAvailableSemaphore, nullptr);
101     vkDestroyFence(device, inFlightFence, nullptr);
102 
103     vkDestroyCommandPool(device, commandPool, nullptr);
104 
105     for (auto framebuffer : swapChainFramebuffers) {
106         vkDestroyFramebuffer(device, framebuffer, nullptr);
107     }
108 
109     vkDestroyPipeline(device, graphicsPipeline, nullptr);
110     vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
111     vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
112     vkDestroyDescriptorPool(device, descriptorPool, nullptr);
113     vkDestroyRenderPass(device, renderPass, nullptr);
114 
115     vkDestroyBuffer(device, vertexBuffer.buffer, nullptr);
116     vkFreeMemory(device, vertexBuffer.memory, nullptr);
117     vkDestroyBuffer(device, indexBuffer.buffer, nullptr);
118     vkFreeMemory(device, indexBuffer.memory, nullptr);
119     vkDestroyBuffer(device, uniformBuffer.buffer, nullptr);
120     vkFreeMemory(device, uniformBuffer.memory, nullptr);
121     vkDestroyBuffer(device, vertexStagingBuffer.buffer, nullptr);
122     vkFreeMemory(device, vertexStagingBuffer.memory, nullptr);
123     vkDestroyBuffer(device, indexStagingBuffer.buffer, nullptr);
124     vkFreeMemory(device, indexStagingBuffer.memory, nullptr);
125     for (auto imageView : swapChainImageViews) {
126         vkDestroyImageView(device, imageView, nullptr);
127     }
128 
129     vkDestroySwapchainKHR(device, swapChain, nullptr);
130     vkDestroyDevice(device, nullptr);
131 
132     vkDestroySurfaceKHR(instance, surface, nullptr);
133     vkDestroyInstance(instance, nullptr);
134     utils::FreeVulkanLibrary();
135 }
136 
CreateInstance()137 bool VulkanExample::CreateInstance()
138 {
139     VkApplicationInfo appInfo{};
140     appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
141     appInfo.pApplicationName = "VulkanExample";
142     appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
143     appInfo.pEngineName = "VulkanExample";
144     appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
145     appInfo.apiVersion = VK_API_VERSION_1_0;
146 
147     VkInstanceCreateInfo createInfo{};
148     createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
149     createInfo.pApplicationInfo = &appInfo;
150 
151     auto extensions = GetRequiredExtensions();
152     if (extensions.size() > 0) {
153         createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
154         createInfo.ppEnabledExtensionNames = extensions.data();
155     }
156 
157     createInfo.enabledLayerCount = 0;
158     createInfo.pNext = nullptr;
159     if (vkCreateInstance == nullptr) {
160         LOGE("vkCreateInstance is null! Failed to create instance!");
161         return false;
162     }
163     bool res = CheckResult(vkCreateInstance(&createInfo, nullptr, &instance));
164     return res;
165 }
166 /*
167  * Create surface on OHOS. Need to call VulkanExample::SetupWindow to set NativeWindow* first.
168  * NativeWindow* is XComponent's surface window pointer. When the XComponent surface is created, we can get this pointer
169  * in 'OnSurfaceCreated' callback function.
170  */
CreateSurface()171 bool VulkanExample::CreateSurface()
172 {
173     VkSurfaceCreateInfoOHOS surfaceCreateInfo{};
174     surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_SURFACE_CREATE_INFO_OHOS;
175     if (window == nullptr) {
176         LOGE("Nativewindow is nullptr. Failed to create surface!");
177         return false;
178     }
179     surfaceCreateInfo.window = window;
180     bool res = CheckResult(vkCreateSurfaceOHOS(instance, &surfaceCreateInfo, nullptr, &surface));
181     return res;
182 }
183 
184 // Enumerate all physical devices and choose a suitable one.
PickPhysicalDevice()185 bool VulkanExample::PickPhysicalDevice()
186 {
187     uint32_t deviceCount = 0;
188     vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
189 
190     if (deviceCount == 0) {
191         LOGI("Failed to find GPUs with Vulkan support!");
192         return false;
193     }
194 
195     std::vector<VkPhysicalDevice> devices(deviceCount);
196     vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
197 
198     for (const auto &device : devices) {
199         if (IsDeviceSuitable(device)) {
200             physicalDevice = device;
201             break;
202         }
203     }
204 
205     if (physicalDevice == VK_NULL_HANDLE) {
206         LOGI("Failed to find a suitable GPU!");
207         return false;
208     }
209     return true;
210 }
211 
CreateLogicalDevice()212 bool VulkanExample::CreateLogicalDevice()
213 {
214     QueueFamilyIndices indices = FindQueueFamilies(physicalDevice);
215 
216     std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
217     std::set<uint32_t> uniqueQueueFamilies = {
218         static_cast<uint32_t>(indices.graphicsFamily),
219         static_cast<uint32_t>(indices.presentFamily)};
220 
221     float queuePriority = 1.0f;
222     for (uint32_t queueFamily : uniqueQueueFamilies) {
223         VkDeviceQueueCreateInfo queueCreateInfo{};
224         queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
225         queueCreateInfo.queueFamilyIndex = queueFamily;
226         queueCreateInfo.queueCount = 1;
227         queueCreateInfo.pQueuePriorities = &queuePriority;
228         queueCreateInfos.push_back(queueCreateInfo);
229     }
230 
231     VkPhysicalDeviceFeatures deviceFeatures{};
232 
233     VkDeviceCreateInfo createInfo{};
234     createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
235 
236     createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
237     createInfo.pQueueCreateInfos = queueCreateInfos.data();
238 
239     createInfo.pEnabledFeatures = &deviceFeatures;
240 
241     createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
242     createInfo.ppEnabledExtensionNames = deviceExtensions.data();
243     createInfo.enabledLayerCount = 0;
244     bool res = CheckResult(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device));
245     vkGetDeviceQueue(device, indices.graphicsFamily, 0, &graphicsQueue);
246     vkGetDeviceQueue(device, indices.presentFamily, 0, &presentQueue);
247     return res;
248 }
249 
CreateSwapChain()250 void VulkanExample::CreateSwapChain()
251 {
252     SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(physicalDevice);
253 
254     VkSurfaceFormatKHR surfaceFormat = ChooseSwapSurfaceFormat(swapChainSupport.formats);
255     VkPresentModeKHR presentMode = ChooseSwapPresentMode(swapChainSupport.presentModes);
256     VkExtent2D extent = ChooseSwapExtent(swapChainSupport.capabilities);
257     uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
258     if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
259         imageCount = swapChainSupport.capabilities.maxImageCount;
260     }
261 
262     VkSwapchainCreateInfoKHR createInfo{};
263     createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
264     createInfo.surface = surface;
265 
266     createInfo.minImageCount = imageCount;
267     createInfo.imageFormat = surfaceFormat.format;
268     createInfo.imageColorSpace = surfaceFormat.colorSpace;
269     createInfo.imageExtent = extent;
270     createInfo.imageArrayLayers = 1;
271     createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
272 
273     QueueFamilyIndices indices = FindQueueFamilies(physicalDevice);
274     uint32_t queueFamilyIndices[] = {static_cast<uint32_t>(indices.graphicsFamily),
275         static_cast<uint32_t>(indices.presentFamily)};
276 
277     if (indices.graphicsFamily != indices.presentFamily) {
278         createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
279         // 2 for graphic family and present family
280         createInfo.queueFamilyIndexCount = 2;
281         createInfo.pQueueFamilyIndices = queueFamilyIndices;
282     } else {
283         createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
284     }
285 
286     createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
287     createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
288     createInfo.presentMode = presentMode;
289     createInfo.clipped = VK_TRUE;
290 
291     createInfo.oldSwapchain = VK_NULL_HANDLE;
292     CheckResult(vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain));
293     vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
294     swapChainImages.resize(imageCount);
295     vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
296 
297     swapChainImageFormat = surfaceFormat.format;
298     swapChainExtent = extent;
299 }
300 
CreateImageViews()301 void VulkanExample::CreateImageViews()
302 {
303     swapChainImageViews.resize(swapChainImages.size());
304 
305     for (size_t i = 0; i < swapChainImages.size(); i++) {
306         VkImageViewCreateInfo createInfo{};
307         createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
308         createInfo.image = swapChainImages[i];
309         createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
310         createInfo.format = swapChainImageFormat;
311         createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
312         createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
313         createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
314         createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
315         createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
316         createInfo.subresourceRange.baseMipLevel = 0;
317         createInfo.subresourceRange.levelCount = 1;
318         createInfo.subresourceRange.baseArrayLayer = 0;
319         createInfo.subresourceRange.layerCount = 1;
320 
321         CheckResult(vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]));
322     }
323 }
324 
CreateRenderPass()325 void VulkanExample::CreateRenderPass()
326 {
327     VkAttachmentDescription colorAttachment{};
328     colorAttachment.format = swapChainImageFormat;
329     colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
330     colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
331     colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
332     colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
333     colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
334     colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
335     colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
336 
337     VkAttachmentReference colorAttachmentRef{};
338     colorAttachmentRef.attachment = 0;
339     colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
340 
341     VkSubpassDescription subpass{};
342     subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
343     subpass.colorAttachmentCount = 1;
344     subpass.pColorAttachments = &colorAttachmentRef;
345 
346     VkSubpassDependency dependency{};
347     dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
348     dependency.dstSubpass = 0;
349     dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
350     dependency.srcAccessMask = 0;
351     dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
352     dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
353 
354     VkRenderPassCreateInfo renderPassInfo{};
355     renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
356     renderPassInfo.attachmentCount = 1;
357     renderPassInfo.pAttachments = &colorAttachment;
358     renderPassInfo.subpassCount = 1;
359     renderPassInfo.pSubpasses = &subpass;
360     renderPassInfo.dependencyCount = 1;
361     renderPassInfo.pDependencies = &dependency;
362 
363     CheckResult(vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass));
364 }
365 
CreateDescriptorSetLayout()366 void VulkanExample::CreateDescriptorSetLayout()
367 {
368     VkDescriptorSetLayoutBinding layoutBinding{};
369     layoutBinding.binding = 0;
370     layoutBinding.descriptorCount = 1;
371     layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
372     layoutBinding.pImmutableSamplers = nullptr;
373     layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
374 
375     VkDescriptorSetLayoutCreateInfo descriptorLayout{};
376     descriptorLayout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
377     descriptorLayout.bindingCount = 1;
378     descriptorLayout.pBindings = &layoutBinding;
379 
380     CheckResult(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout));
381 }
382 
CreateGraphicsPipeline()383 void VulkanExample::CreateGraphicsPipeline()
384 {
385     VkShaderModule vertShaderModule = LoadSPIRVShader("vert");
386     VkShaderModule fragShaderModule = LoadSPIRVShader("frag");
387     if (vertShaderModule == VK_NULL_HANDLE || fragShaderModule == VK_NULL_HANDLE) {
388         LOGI("Failed to load shader!");
389     }
390     VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
391     vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
392     vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
393     vertShaderStageInfo.module = vertShaderModule;
394     vertShaderStageInfo.pName = "main";
395 
396     VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
397     fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
398     fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
399     fragShaderStageInfo.module = fragShaderModule;
400     fragShaderStageInfo.pName = "main";
401 
402     VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
403 
404     // Vertex Input
405     VkVertexInputBindingDescription vertexInputBinding{};
406     // Input attribute bindings describe shader attribute locations and memory layouts
407     // 2 attributes for position(location = 0) and color (location = 1)
408     std::array<VkVertexInputAttributeDescription, 2> vertexInputAttributes;
409     VkPipelineVertexInputStateCreateInfo vertexInputState =
410         PrepareVertexInputState(vertexInputBinding, vertexInputAttributes);
411 
412     // Input assembly
413     VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = PrepareInputAssemblyState();
414     // Rasterization
415     VkPipelineRasterizationStateCreateInfo rasterizationState = PrepareRasterizationState();
416     // multisample
417     VkPipelineMultisampleStateCreateInfo multisampleState = PrepareMultisampleState();
418     // Color blend
419     VkPipelineColorBlendAttachmentState blendAttachmentState{};
420     VkPipelineColorBlendStateCreateInfo colorBlendState = PrepareColorBlendState(blendAttachmentState);
421     // Viewport
422     VkPipelineViewportStateCreateInfo viewportState = PrepareViewportState();
423 
424     // Dynamic state
425     std::vector<VkDynamicState> dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
426     VkPipelineDynamicStateCreateInfo dynamicState = PrepareDynamicState(dynamicStates);
427 
428     PreparePipelineLayout();
429 
430     VkGraphicsPipelineCreateInfo pipelineInfo{};
431     pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
432     // 2 stages for vertex shader stage and fragment shader stage
433     pipelineInfo.stageCount = 2;
434     pipelineInfo.pStages = shaderStages;
435     pipelineInfo.pVertexInputState = &vertexInputState;
436     pipelineInfo.pInputAssemblyState = &inputAssemblyState;
437     pipelineInfo.pViewportState = &viewportState;
438     pipelineInfo.pRasterizationState = &rasterizationState;
439     pipelineInfo.pMultisampleState = &multisampleState;
440     pipelineInfo.pColorBlendState = &colorBlendState;
441     pipelineInfo.pDynamicState = &dynamicState;
442     pipelineInfo.layout = pipelineLayout;
443     pipelineInfo.renderPass = renderPass;
444     pipelineInfo.subpass = 0;
445     pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
446     CheckResult(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline));
447     vkDestroyShaderModule(device, fragShaderModule, nullptr);
448     vkDestroyShaderModule(device, vertShaderModule, nullptr);
449 }
450 
PrepareVertexInputState(VkVertexInputBindingDescription & vertexInputBinding,std::array<VkVertexInputAttributeDescription,2> & vertexInputAttributes)451 VkPipelineVertexInputStateCreateInfo VulkanExample::PrepareVertexInputState(
452     VkVertexInputBindingDescription& vertexInputBinding,
453     // 2 attributes for position(location = 0) and color (location = 1)
454     std::array<VkVertexInputAttributeDescription, 2>& vertexInputAttributes)
455 {
456     vertexInputBinding.binding = 0;
457     vertexInputBinding.stride = sizeof(Vertex);
458     vertexInputBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
459 
460     // Attribute location 0: Position
461     vertexInputAttributes[0].binding = 0;
462     vertexInputAttributes[0].location = 0;
463     vertexInputAttributes[0].format = VK_FORMAT_R32G32B32_SFLOAT;
464     vertexInputAttributes[0].offset = offsetof(Vertex, position);
465 
466     // Attribute location 1: Color
467     vertexInputAttributes[1].binding = 0;
468     vertexInputAttributes[1].location = 1;
469     // Color attribute is three 32 bit signed (SFLOAT) floats (R32 G32 B32)
470     vertexInputAttributes[1].format = VK_FORMAT_R32G32B32_SFLOAT;
471     vertexInputAttributes[1].offset = offsetof(Vertex, color);
472 
473     // Vertex input state used for pipeline creation
474     VkPipelineVertexInputStateCreateInfo vertexInputState = {};
475     vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
476     vertexInputState.vertexBindingDescriptionCount = 1;
477     vertexInputState.pVertexBindingDescriptions = &vertexInputBinding;
478     // 2 attributes for position(location = 0) and color (location = 1)
479     vertexInputState.vertexAttributeDescriptionCount = 2;
480     vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data();
481     return vertexInputState;
482 }
483 
PrepareColorBlendState(VkPipelineColorBlendAttachmentState & blendAttachmentState)484 VkPipelineColorBlendStateCreateInfo VulkanExample::PrepareColorBlendState(
485     VkPipelineColorBlendAttachmentState& blendAttachmentState)
486 {
487     blendAttachmentState.colorWriteMask =
488         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
489     blendAttachmentState.blendEnable = VK_FALSE;
490     VkPipelineColorBlendStateCreateInfo colorBlendState{};
491     colorBlendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
492     colorBlendState.logicOpEnable = VK_FALSE;
493     colorBlendState.logicOp = VK_LOGIC_OP_COPY;
494     colorBlendState.attachmentCount = 1;
495     colorBlendState.pAttachments = &blendAttachmentState;
496     return colorBlendState;
497 }
498 
PrepareInputAssemblyState()499 VkPipelineInputAssemblyStateCreateInfo VulkanExample::PrepareInputAssemblyState()
500 {
501     VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {};
502     inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
503     inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
504     inputAssemblyState.primitiveRestartEnable = VK_FALSE;
505     return inputAssemblyState;
506 }
PrepareRasterizationState()507 VkPipelineRasterizationStateCreateInfo VulkanExample::PrepareRasterizationState()
508 {
509     VkPipelineRasterizationStateCreateInfo rasterizationState = {};
510     rasterizationState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
511     rasterizationState.polygonMode = VK_POLYGON_MODE_FILL;
512     rasterizationState.lineWidth = 1.0f;
513     rasterizationState.cullMode = VK_CULL_MODE_NONE;
514     rasterizationState.frontFace = VK_FRONT_FACE_CLOCKWISE;
515     rasterizationState.depthClampEnable = VK_FALSE;
516     rasterizationState.rasterizerDiscardEnable = VK_FALSE;
517     rasterizationState.depthBiasEnable = VK_FALSE;
518     return rasterizationState;
519 }
520 
PrepareMultisampleState()521 VkPipelineMultisampleStateCreateInfo VulkanExample::PrepareMultisampleState()
522 {
523     VkPipelineMultisampleStateCreateInfo multisampleState = {};
524     multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
525     multisampleState.sampleShadingEnable = VK_FALSE;
526     multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
527     return multisampleState;
528 }
529 
PrepareViewportState()530 VkPipelineViewportStateCreateInfo VulkanExample::PrepareViewportState()
531 {
532     VkPipelineViewportStateCreateInfo viewportState{};
533     viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
534     viewportState.viewportCount = 1;
535     viewportState.scissorCount = 1;
536     return viewportState;
537 }
538 
PreparePipelineLayout()539 void VulkanExample::PreparePipelineLayout()
540 {
541     VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
542     pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
543     pipelineLayoutInfo.setLayoutCount = 1;
544     pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
545     pipelineLayoutInfo.pushConstantRangeCount = 0;
546     CheckResult(vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout));
547 }
548 
PrepareDynamicState(std::vector<VkDynamicState> & dynamicStates)549 VkPipelineDynamicStateCreateInfo VulkanExample::PrepareDynamicState(std::vector<VkDynamicState>& dynamicStates)
550 {
551     VkPipelineDynamicStateCreateInfo dynamicState{};
552     dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
553     dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size());
554     dynamicState.pDynamicStates = dynamicStates.data();
555     return dynamicState;
556 }
557 
CreateFramebuffers()558 void VulkanExample::CreateFramebuffers()
559 {
560     swapChainFramebuffers.resize(swapChainImageViews.size());
561 
562     for (size_t i = 0; i < swapChainImageViews.size(); i++) {
563         VkImageView attachments[] = {swapChainImageViews[i]};
564 
565         VkFramebufferCreateInfo framebufferInfo{};
566         framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
567         framebufferInfo.renderPass = renderPass;
568         framebufferInfo.attachmentCount = 1;
569         framebufferInfo.pAttachments = attachments;
570         framebufferInfo.width = swapChainExtent.width;
571         framebufferInfo.height = swapChainExtent.height;
572         framebufferInfo.layers = 1;
573 
574         CheckResult(vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]));
575     }
576 }
577 
CreateCommandPool()578 void VulkanExample::CreateCommandPool()
579 {
580     QueueFamilyIndices queueFamilyIndices = FindQueueFamilies(physicalDevice);
581 
582     VkCommandPoolCreateInfo poolInfo{};
583     poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
584     poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
585     poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily;
586 
587     CheckResult(vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool));
588 }
589 
CreateCommandBuffer()590 void VulkanExample::CreateCommandBuffer()
591 {
592     VkCommandBufferAllocateInfo allocInfo{};
593     allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
594     allocInfo.commandPool = commandPool;
595     allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
596     allocInfo.commandBufferCount = 1;
597 
598     CheckResult(vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer));
599 }
600 
GetMemoryTypeIndex(uint32_t typeFilter,VkMemoryPropertyFlags properties)601 uint32_t VulkanExample::GetMemoryTypeIndex(uint32_t typeFilter, VkMemoryPropertyFlags properties)
602 {
603     VkPhysicalDeviceMemoryProperties memProperties;
604     vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
605     for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i) {
606         if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
607             return i;
608         }
609     }
610     LOGE("Failed to find memory type to allocate memory");
611     return 0;
612 }
CreateBuffer(VkDeviceSize size,VkBufferUsageFlags usage,VkMemoryPropertyFlags properties,VkBuffer & buffer,VkDeviceMemory & bufferMemory)613 void VulkanExample::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
614     VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory)
615 {
616     VkBufferCreateInfo bufferInfo{};
617     bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
618     bufferInfo.size = size;
619     bufferInfo.usage = usage;
620     bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
621 
622     CheckResult(vkCreateBuffer(device, &bufferInfo, nullptr, &buffer));
623     VkMemoryRequirements memReqs;
624     vkGetBufferMemoryRequirements(device, buffer, &memReqs);
625 
626     VkMemoryAllocateInfo memAlloc{};
627     memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
628     memAlloc.allocationSize = memReqs.size;
629     memAlloc.memoryTypeIndex = GetMemoryTypeIndex(memReqs.memoryTypeBits, properties);
630 
631     CheckResult(vkAllocateMemory(device, &memAlloc, nullptr, &bufferMemory));
632     CheckResult(vkBindBufferMemory(device, buffer, bufferMemory, 0));
633 }
634 
GetCommandBuffer()635 VkCommandBuffer VulkanExample::GetCommandBuffer()
636 {
637     VkCommandBuffer cmdBuffer;
638     VkCommandBufferAllocateInfo cmdBufAllocateInfo{};
639     cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
640     cmdBufAllocateInfo.commandPool = commandPool;
641     cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
642     cmdBufAllocateInfo.commandBufferCount = 1;
643     CheckResult(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &cmdBuffer));
644 
645     return cmdBuffer;
646 }
647 
FlushCommandBuffer(VkCommandBuffer commandBuffer)648 void VulkanExample::FlushCommandBuffer(VkCommandBuffer commandBuffer)
649 {
650     VkSubmitInfo submitInfo = {};
651     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
652     submitInfo.commandBufferCount = 1;
653     submitInfo.pCommandBuffers = &commandBuffer;
654 
655     // Create fence to ensure that the command buffer has finished executing
656     VkFenceCreateInfo fenceCreateInfo = {};
657     fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
658     fenceCreateInfo.flags = 0;
659     VkFence fence;
660     CheckResult(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
661 
662     // Submit to the queue
663     CheckResult(vkQueueSubmit(graphicsQueue, 1, &submitInfo, fence));
664     // Wait for the fence to signal that command buffer has finished executing
665     CheckResult(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX));
666 
667     vkDestroyFence(device, fence, nullptr);
668     vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
669 }
670 
CreateVertices()671 void VulkanExample::CreateVertices()
672 {
673     // vertex buffer
674     CreateBuffer(vertexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
675                  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, vertexStagingBuffer.buffer,
676                  vertexStagingBuffer.memory);
677 
678     CreateBuffer(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
679                  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer.buffer, vertexBuffer.memory);
680 
681     // index buffer
682     CreateBuffer(indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
683                  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, indexStagingBuffer.buffer,
684                  indexStagingBuffer.memory);
685     CreateBuffer(indexBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
686                  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer.buffer, indexBuffer.memory);
687 }
688 
UpdateVertices()689 void VulkanExample::UpdateVertices()
690 {
691     alpha += 0.01f;
692     const float PI = 3.1415926;
693     if (alpha > PI) {
694         alpha -= PI;
695     }
696     std::vector<Vertex> tempVertices = {{{std::sin(alpha), 1.0f, -std::cos(alpha)}, {1.0f, 0.0f, 0.0f}},
697                                     {{-std::sin(alpha), 1.0f, std::cos(alpha)}, {0.0f, 1.0f, 0.0f}},
698                                     {{0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}};
699     vertices = std::move(tempVertices);
700 
701     // update vertex buffer
702     void *data = nullptr;
703     CheckResult(vkMapMemory(device, vertexStagingBuffer.memory, 0, vertexBufferSize, 0, &data));
704     memcpy(data, vertices.data(), static_cast<size_t>(vertexBufferSize));
705     vkUnmapMemory(device, vertexStagingBuffer.memory);
706     // update index buffer
707     CheckResult(vkMapMemory(device, indexStagingBuffer.memory, 0, vertexBufferSize, 0, &data));
708     memcpy(data, indices.data(), static_cast<size_t>(indexBufferSize));
709     vkUnmapMemory(device, indexStagingBuffer.memory);
710 
711     // copy date from staging buffer to buffer with VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
712     VkCommandBuffer copyBuffer = GetCommandBuffer();
713 
714     VkCommandBufferBeginInfo beginInfo{};
715     beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
716     vkBeginCommandBuffer(copyBuffer, &beginInfo);
717     VkBufferCopy copyRegion{};
718     copyRegion.size = vertexBufferSize;
719     vkCmdCopyBuffer(copyBuffer, vertexStagingBuffer.buffer, vertexBuffer.buffer, 1, &copyRegion);
720     copyRegion.size = indexBufferSize;
721     vkCmdCopyBuffer(copyBuffer, indexStagingBuffer.buffer, indexBuffer.buffer, 1, &copyRegion);
722     vkEndCommandBuffer(copyBuffer);
723     FlushCommandBuffer(copyBuffer);
724 }
CreateUniformBuffers()725 void VulkanExample::CreateUniformBuffers()
726 {
727     VkDeviceSize bufferSize = sizeof(uboVS);
728     CreateBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
729                  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer.buffer,
730                  uniformBuffer.memory);
731     UpdateUniformBuffers();
732 }
733 
UpdateUniformBuffers()734 void VulkanExample::UpdateUniformBuffers()
735 {
736     // Pass matrices to the shaders
737     // Map uniform buffer and update it
738     uint8_t *pData;
739     CheckResult(vkMapMemory(device, uniformBuffer.memory, 0, sizeof(uboVS), 0, (void **)&pData));
740     memcpy(pData, &uboVS, sizeof(uboVS));
741     // Unmap after data has been copied
742     vkUnmapMemory(device, uniformBuffer.memory);
743 }
744 
CreateDescriptorPool()745 void VulkanExample::CreateDescriptorPool()
746 {
747     VkDescriptorPoolSize poolSize{};
748     poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
749     poolSize.descriptorCount = 1;
750 
751     VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
752     descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
753     descriptorPoolInfo.pNext = nullptr;
754     descriptorPoolInfo.poolSizeCount = 1;
755     descriptorPoolInfo.pPoolSizes = &poolSize;
756     // Set the max. number of descriptor sets that can be requested from this pool (requesting beyond this limit will
757     // result in an error)
758     descriptorPoolInfo.maxSets = 1;
759     CheckResult(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
760 }
761 
CreateDescriptorSets()762 void VulkanExample::CreateDescriptorSets()
763 {
764     VkDescriptorSetAllocateInfo allocInfo = {};
765     allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
766     allocInfo.descriptorPool = descriptorPool;
767     allocInfo.descriptorSetCount = 1;
768     allocInfo.pSetLayouts = &descriptorSetLayout;
769     CheckResult(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
770 
771     VkDescriptorBufferInfo bufferInfo{};
772     bufferInfo.buffer = uniformBuffer.buffer;
773     bufferInfo.range = sizeof(uboVS);
774     bufferInfo.offset = 0;
775 
776     VkWriteDescriptorSet writeDescriptorSet = {};
777     // Binding 0 : Uniform buffer
778     writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
779     writeDescriptorSet.dstSet = descriptorSet;
780     writeDescriptorSet.descriptorCount = 1;
781     writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
782     writeDescriptorSet.pBufferInfo = &bufferInfo;
783     // Binds this uniform buffer to binding point 0
784     writeDescriptorSet.dstBinding = 0;
785 
786     vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
787 }
788 
RecordCommandBuffer(VkCommandBuffer commandBuffer,uint32_t imageIndex)789 void VulkanExample::RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex)
790 {
791     VkCommandBufferBeginInfo beginInfo{};
792     beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
793 
794     CheckResult(vkBeginCommandBuffer(commandBuffer, &beginInfo));
795 
796     VkRenderPassBeginInfo renderPassInfo{};
797     renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
798     renderPassInfo.renderPass = renderPass;
799     renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex];
800     renderPassInfo.renderArea.offset = {0, 0};
801     renderPassInfo.renderArea.extent = swapChainExtent;
802 
803     VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
804     renderPassInfo.clearValueCount = 1;
805     renderPassInfo.pClearValues = &clearColor;
806 
807     vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
808 
809     vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
810 
811     VkViewport viewport{};
812     viewport.x = 0.0f;
813     viewport.y = 0.0f;
814     viewport.width = (float)swapChainExtent.width;
815     viewport.height = (float)swapChainExtent.height;
816     viewport.minDepth = 0.0f;
817     viewport.maxDepth = 1.0f;
818     vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
819 
820     VkRect2D scissor{};
821     scissor.offset = {0, 0};
822     scissor.extent = swapChainExtent;
823     vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
824 
825     VkDeviceSize offsets[1] = {0};
826     vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer.buffer, offsets);
827     vkCmdBindIndexBuffer(commandBuffer, indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
828     vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1,
829         &descriptorSet, 0, nullptr);
830     vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
831 
832     vkCmdEndRenderPass(commandBuffer);
833 
834     CheckResult(vkEndCommandBuffer(commandBuffer));
835 }
836 
CreateSyncObjects()837 void VulkanExample::CreateSyncObjects()
838 {
839     VkSemaphoreCreateInfo semaphoreInfo{};
840     semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
841 
842     VkFenceCreateInfo fenceInfo{};
843     fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
844     fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
845 
846     CheckResult(vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore));
847     CheckResult(vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphore));
848     CheckResult(vkCreateFence(device, &fenceInfo, nullptr, &inFlightFence));
849 }
850 
DrawFrame()851 void VulkanExample::DrawFrame()
852 {
853     vkWaitForFences(device, 1, &inFlightFence, VK_TRUE, UINT64_MAX);
854     vkResetFences(device, 1, &inFlightFence);
855 
856     uint32_t imageIndex;
857     VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX,
858         imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
859     if (result == VK_ERROR_OUT_OF_DATE_KHR || shouldRecreate) {
860         LOGI("Need to recreate swapchain!");
861         shouldRecreate = false;
862         RecreateSwapChain();
863         return;
864     }
865     // 0 is VkCommandBufferResetFlagBits
866     vkResetCommandBuffer(commandBuffer, 0);
867     RecordCommandBuffer(commandBuffer, imageIndex);
868 
869     VkSubmitInfo submitInfo{};
870     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
871 
872     VkSemaphore waitSemaphores[] = {imageAvailableSemaphore};
873     VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
874     submitInfo.waitSemaphoreCount = 1;
875     submitInfo.pWaitSemaphores = waitSemaphores;
876     submitInfo.pWaitDstStageMask = waitStages;
877 
878     submitInfo.commandBufferCount = 1;
879     submitInfo.pCommandBuffers = &commandBuffer;
880 
881     VkSemaphore signalSemaphores[] = {renderFinishedSemaphore};
882     submitInfo.signalSemaphoreCount = 1;
883     submitInfo.pSignalSemaphores = signalSemaphores;
884 
885     CheckResult(vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFence));
886 
887     VkPresentInfoKHR presentInfo{};
888     presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
889 
890     presentInfo.waitSemaphoreCount = 1;
891     presentInfo.pWaitSemaphores = signalSemaphores;
892 
893     VkSwapchainKHR swapChains[] = {swapChain};
894     presentInfo.swapchainCount = 1;
895     presentInfo.pSwapchains = swapChains;
896 
897     presentInfo.pImageIndices = &imageIndex;
898 
899     result = vkQueuePresentKHR(presentQueue, &presentInfo);
900     if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
901         RecreateSwapChain();
902     }
903 }
904 
CleanupSwapChain()905 void VulkanExample::CleanupSwapChain()
906 {
907     for (auto framebuffer : swapChainFramebuffers) {
908         vkDestroyFramebuffer(device, framebuffer, nullptr);
909     }
910     for (auto imageView : swapChainImageViews) {
911         vkDestroyImageView(device, imageView, nullptr);
912     }
913     vkDestroySwapchainKHR(device, swapChain, nullptr);
914 }
915 // When surface chagned, we need to recreate swapchain
RecreateSwapChain()916 void VulkanExample::RecreateSwapChain()
917 {
918     vkDeviceWaitIdle(device);
919     CleanupSwapChain();
920     CreateSwapChain();
921     CreateImageViews();
922     CreateFramebuffers();
923 }
924 
CreateShaderModule(const std::vector<char> & code)925 VkShaderModule VulkanExample::CreateShaderModule(const std::vector<char> &code)
926 {
927     VkShaderModuleCreateInfo createInfo{};
928     createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
929     createInfo.codeSize = code.size();
930     createInfo.pCode = reinterpret_cast<const uint32_t *>(code.data());
931 
932     VkShaderModule shaderModule;
933     CheckResult(vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule));
934 
935     return shaderModule;
936 }
937 
ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> & availableFormats)938 VkSurfaceFormatKHR VulkanExample::ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &availableFormats)
939 {
940     for (const auto &availableFormat : availableFormats) {
941         if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB &&
942             availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
943             return availableFormat;
944         }
945     }
946     return availableFormats[0];
947 }
948 
ChooseSwapPresentMode(const std::vector<VkPresentModeKHR> & availablePresentModes)949 VkPresentModeKHR VulkanExample::ChooseSwapPresentMode(const std::vector<VkPresentModeKHR> &availablePresentModes)
950 {
951     for (const auto &availablePresentMode : availablePresentModes) {
952         if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
953             return availablePresentMode;
954         }
955     }
956     return VK_PRESENT_MODE_FIFO_KHR;
957 }
958 
ChooseSwapExtent(const VkSurfaceCapabilitiesKHR & capabilities)959 VkExtent2D VulkanExample::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities)
960 {
961     VkExtent2D actualExtent = {width, height};
962     actualExtent.width = std::max(capabilities.minImageExtent.width,
963         std::min(capabilities.maxImageExtent.width, actualExtent.width));
964     actualExtent.height = std::max(capabilities.minImageExtent.height,
965         std::min(capabilities.maxImageExtent.height, actualExtent.height));
966     return actualExtent;
967 }
968 
QuerySwapChainSupport(VkPhysicalDevice device)969 SwapChainSupportDetails VulkanExample::QuerySwapChainSupport(VkPhysicalDevice device)
970 {
971     SwapChainSupportDetails details;
972     vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
973     uint32_t formatCount;
974     vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
975 
976     if (formatCount != 0) {
977         details.formats.resize(formatCount);
978         vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
979     }
980 
981     uint32_t presentModeCount;
982     vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
983 
984     if (presentModeCount != 0) {
985         details.presentModes.resize(presentModeCount);
986         vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
987     }
988 
989     return details;
990 }
991 
992 // This suitable GPU should support graphics & present queue family and
993 // extension 'VK_KHR_SWAPCHAIN_EXTENSION_NAME'.
IsDeviceSuitable(VkPhysicalDevice device)994 bool VulkanExample::IsDeviceSuitable(VkPhysicalDevice device)
995 {
996     QueueFamilyIndices indices = FindQueueFamilies(device);
997 
998     bool extensionsSupported = CheckDeviceExtensionSupport(device);
999 
1000     bool swapChainAdequate = true;
1001     if (extensionsSupported) {
1002         SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(device);
1003         swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
1004     }
1005 
1006     return indices.IsComplete() && extensionsSupported && swapChainAdequate;
1007 }
1008 
1009 // Check whether the physical device supports all required extensions.
CheckDeviceExtensionSupport(VkPhysicalDevice device)1010 bool VulkanExample::CheckDeviceExtensionSupport(VkPhysicalDevice device)
1011 {
1012     uint32_t extensionCount;
1013     vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
1014 
1015     std::vector<VkExtensionProperties> availableExtensions(extensionCount);
1016     vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
1017 
1018     std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
1019 
1020     for (const auto &extension : availableExtensions) {
1021         requiredExtensions.erase(extension.extensionName);
1022     }
1023 
1024     return requiredExtensions.empty();
1025 }
1026 
1027 // Find graphics family index and present family index of the physical device.
FindQueueFamilies(VkPhysicalDevice device)1028 QueueFamilyIndices VulkanExample::FindQueueFamilies(VkPhysicalDevice device)
1029 {
1030     QueueFamilyIndices indices;
1031 
1032     uint32_t queueFamilyCount = 0;
1033     vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
1034 
1035     std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1036     vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
1037 
1038     int i = 0;
1039     for (const auto &queueFamily : queueFamilies) {
1040         if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
1041             indices.graphicsFamily = i;
1042         }
1043 
1044         VkBool32 presentSupport = false;
1045         vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
1046 
1047         if (presentSupport) {
1048             indices.presentFamily = i;
1049         }
1050 
1051         if (indices.IsComplete()) {
1052             break;
1053         }
1054         i++;
1055     }
1056 
1057     return indices;
1058 }
1059 
1060 // Check whether all required extensions is supported when creating vkInstance.
GetRequiredExtensions()1061 std::vector<const char *> VulkanExample::GetRequiredExtensions()
1062 {
1063     std::vector<const char *> extensions = { VK_KHR_SURFACE_EXTENSION_NAME, VK_OHOS_SURFACE_EXTENSION_NAME};
1064     uint32_t extCount = 0;
1065     vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr);
1066     std::vector<VkExtensionProperties> availableExts(extCount);
1067     if (vkEnumerateInstanceExtensionProperties(nullptr, &extCount, availableExts.data()) == VK_SUCCESS) {
1068         for (const auto& availableExt : availableExts) {
1069             supportedInstanceExtensions.push_back(availableExt.extensionName);
1070         }
1071     }
1072     if (enabledInstanceExtensions.size() > 0) {
1073         for (const char* enabledExt : enabledInstanceExtensions) {
1074             if (std::find(supportedInstanceExtensions.begin(), supportedInstanceExtensions.end(), enabledExt) ==
1075                 supportedInstanceExtensions.end()) {
1076                 LOGE("Failed to enable instance extension %s", enabledExt);
1077             }
1078             extensions.push_back(enabledExt);
1079         }
1080     }
1081     return extensions;
1082 }
1083 // load spirv shader in phone.
LoadSPIRVShader(std::string filename)1084 VkShaderModule VulkanExample::LoadSPIRVShader(std::string filename)
1085 {
1086     // Read shader from sandbox. The path can be found in function aboutToAppear() in /ets/pages/Index.ets.
1087     std::string spvPath = "/data/storage/el2/base/haps/entry/files/rawfile/" + filename + ".spv";
1088     constexpr size_t maxShaderSize = 1000000;
1089     size_t shaderSize;
1090     char *shaderCode = nullptr;
1091     std::ifstream is(spvPath, std::ios::binary | std::ios::in | std::ios::ate);
1092 
1093     if (is.is_open()) {
1094         shaderSize = is.tellg();
1095         is.seekg(0, std::ios::beg);
1096         // Copy file contents into a buffer
1097         if (shaderSize == 0 || shaderSize > maxShaderSize) {
1098             LOGI("Failed to load spriv shader. The shader size is invalid!");
1099         }
1100         shaderCode = new char[shaderSize];
1101         is.read(shaderCode, shaderSize);
1102         is.close();
1103     }
1104 
1105     if (shaderCode) {
1106         // Create a new shader module that will be used for pipeline creation
1107         VkShaderModuleCreateInfo moduleCreateInfo{};
1108         moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1109         moduleCreateInfo.codeSize = shaderSize;
1110         moduleCreateInfo.pCode = (uint32_t *)shaderCode;
1111 
1112         VkShaderModule shaderModule;
1113         CheckResult(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule));
1114 
1115         delete[] shaderCode;
1116         return shaderModule;
1117     } else {
1118         LOGE("Failed to open shader file %{public}s", filename.c_str());
1119         return VK_NULL_HANDLE;
1120     }
1121 }
1122 } // namespace vkExample