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, ©Region);
720 copyRegion.size = indexBufferSize;
721 vkCmdCopyBuffer(copyBuffer, indexStagingBuffer.buffer, indexBuffer.buffer, 1, ©Region);
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