Binary that renders a triangle using Vulkan and scans the resulting image to a PNG. To be used in developing Turnip.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

triangle.cc 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. #include <png.h>
  2. #include <vulkan/vulkan.h>
  3. #include <fstream>
  4. #include <iostream>
  5. #include <sstream>
  6. #include <string>
  7. #include <vector>
  8. const uint32_t kWidth = 128;
  9. const uint32_t kHeight = 128;
  10. const VkFormat kVulkanFormat = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
  11. const std::string kVertexShaderPath = "triangle.vert.spv";
  12. const std::string kFragmentShaderPath = "triangle.frag.spv";
  13. #define ERROR(message) \
  14. std::cerr << message << std::endl; \
  15. std::exit(EXIT_FAILURE)
  16. VkInstance CreateVkInstance() {
  17. VkApplicationInfo app_info = {};
  18. app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  19. app_info.apiVersion = VK_API_VERSION_1_1;
  20. VkInstanceCreateInfo create_info = {};
  21. create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  22. create_info.pApplicationInfo = &app_info;
  23. create_info.enabledExtensionCount = 0;
  24. create_info.ppEnabledExtensionNames = nullptr;
  25. create_info.enabledLayerCount = 0;
  26. create_info.ppEnabledLayerNames = nullptr;
  27. VkInstance instance;
  28. VkResult result = vkCreateInstance(&create_info, nullptr, &instance);
  29. if (result != VK_SUCCESS) {
  30. ERROR("Error creating VkInstance: " << result);
  31. }
  32. return instance;
  33. }
  34. VkPhysicalDevice ChooseVkPhysicalDevice(VkInstance instance) {
  35. uint32_t device_count = 0;
  36. VkResult result = vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
  37. if (result != VK_SUCCESS) {
  38. ERROR("Error enumerating VkPhysicalDevices: " << result);
  39. }
  40. if (device_count == 0) {
  41. ERROR("No available VkPhysicalDevices");
  42. }
  43. std::vector<VkPhysicalDevice> devices(device_count);
  44. result = vkEnumeratePhysicalDevices(instance, &device_count, devices.data());
  45. if (result != VK_SUCCESS) {
  46. ERROR("Error fetching VkPhysicalDevices: " << result);
  47. }
  48. std::cout << "Found " << device_count << " device(s):" << std::endl;
  49. VkPhysicalDevice chosen_device = VK_NULL_HANDLE;
  50. for (VkPhysicalDevice device : devices) {
  51. VkPhysicalDeviceProperties device_props;
  52. vkGetPhysicalDeviceProperties(device, &device_props);
  53. std::cout << "\t- " << device_props.deviceName << " [V: " <<
  54. VK_VERSION_MAJOR(device_props.apiVersion) << "." <<
  55. VK_VERSION_MINOR(device_props.apiVersion) << "." <<
  56. VK_VERSION_PATCH(device_props.apiVersion) << "]" << std::endl;
  57. // Currently, any device with Vulkan API version 1.1 is fine.
  58. if (chosen_device == VK_NULL_HANDLE && device_props.apiVersion >= VK_API_VERSION_1_1) {
  59. chosen_device = device;
  60. }
  61. }
  62. if (chosen_device == VK_NULL_HANDLE) {
  63. ERROR("Unable to find suitable VkPhysicalDevice");
  64. }
  65. return chosen_device;
  66. }
  67. uint32_t ChooseDeviceQueueFamilyIndex(VkPhysicalDevice physical_device) {
  68. uint32_t props_count;
  69. vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &props_count, nullptr);
  70. std::vector<VkQueueFamilyProperties> props(props_count);
  71. vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &props_count, props.data());
  72. // Simply choose the first graphics queue.
  73. for (size_t i = 0; i < props_count; i++) {
  74. const VkQueueFamilyProperties& prop = props[i];
  75. if ((prop.queueFlags & VK_QUEUE_GRAPHICS_BIT) && prop.queueCount > 0) {
  76. return i;
  77. }
  78. }
  79. ERROR("Unable to find suitable queue family");
  80. }
  81. VkDevice CreateVkDevice(VkPhysicalDevice physical_device, uint32_t device_queue_family_index) {
  82. VkDeviceQueueCreateInfo queue_create_info = {};
  83. queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  84. queue_create_info.queueFamilyIndex = device_queue_family_index;
  85. queue_create_info.queueCount = 1;
  86. float queue_priority = 1.0f;
  87. queue_create_info.pQueuePriorities = &queue_priority;
  88. VkDeviceCreateInfo device_create_info = {};
  89. device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  90. device_create_info.queueCreateInfoCount = 1;
  91. device_create_info.pQueueCreateInfos = &queue_create_info;
  92. // Let's not use any device extensions for now.
  93. device_create_info.enabledExtensionCount = 0;
  94. device_create_info.ppEnabledExtensionNames = nullptr;
  95. VkDevice device;
  96. VkResult result = vkCreateDevice(physical_device, &device_create_info, nullptr, &device);
  97. if (result != VK_SUCCESS) {
  98. ERROR("Unable to create logical device: " << result);
  99. }
  100. return device;
  101. }
  102. VkQueue GetVkQueue(VkDevice device, uint32_t device_queue_family_index) {
  103. VkQueue queue;
  104. vkGetDeviceQueue(device, device_queue_family_index, /*queueIndex*/ 0, &queue);
  105. return queue;
  106. }
  107. VkCommandPool CreateVkCommandPool(VkDevice device, uint32_t device_queue_family_index) {
  108. VkCommandPool command_pool;
  109. VkCommandPoolCreateInfo create_info = {};
  110. create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
  111. create_info.flags = 0;
  112. create_info.queueFamilyIndex = device_queue_family_index;
  113. VkResult result = vkCreateCommandPool(device, &create_info, nullptr, &command_pool);
  114. if (result != VK_SUCCESS) {
  115. ERROR("Unable to create command pool: " << result);
  116. }
  117. return command_pool;
  118. }
  119. VkRenderPass CreateVkRenderPass(VkDevice device) {
  120. VkAttachmentDescription attachment_description = {};
  121. attachment_description.format = kVulkanFormat;
  122. attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
  123. attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
  124. attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
  125. attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  126. attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  127. attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  128. attachment_description.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
  129. VkAttachmentReference attachment_reference = {};
  130. attachment_reference.attachment = 0;
  131. attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
  132. VkSubpassDescription subpass_description = {};
  133. subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
  134. subpass_description.colorAttachmentCount = 1;
  135. subpass_description.pColorAttachments = &attachment_reference;
  136. VkSubpassDependency subpass_dependency = {};
  137. subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
  138. subpass_dependency.dstSubpass = 0;
  139. subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  140. subpass_dependency.srcAccessMask = 0;
  141. subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  142. subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
  143. VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  144. VkRenderPassCreateInfo render_pass_info = {};
  145. render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
  146. render_pass_info.attachmentCount = 1;
  147. render_pass_info.pAttachments = &attachment_description;
  148. render_pass_info.subpassCount = 1;
  149. render_pass_info.pSubpasses = &subpass_description;
  150. render_pass_info.dependencyCount = 1;
  151. render_pass_info.pDependencies = &subpass_dependency;
  152. VkRenderPass render_pass;
  153. VkResult result = vkCreateRenderPass(device, &render_pass_info, nullptr, &render_pass);
  154. if (result != VK_SUCCESS) {
  155. ERROR("Unable to create render pass: " << result);
  156. }
  157. return render_pass;
  158. }
  159. VkShaderModule CreateVkShaderModule(VkDevice device, std::string path) {
  160. std::ifstream fstream(path);
  161. if (!fstream) {
  162. ERROR("Unable to open: " << path);
  163. }
  164. std::stringstream buffer;
  165. buffer << fstream.rdbuf();
  166. std::string spirv_source = buffer.str();
  167. VkShaderModuleCreateInfo create_info = {};
  168. create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
  169. create_info.codeSize = spirv_source.length();
  170. create_info.pCode = (const uint32_t*)spirv_source.c_str();
  171. VkShaderModule shader_module;
  172. VkResult result = vkCreateShaderModule(device, &create_info, nullptr, &shader_module);
  173. if (result != VK_SUCCESS) {
  174. ERROR("Unable to create shader module for " << path << ": ");
  175. }
  176. return shader_module;
  177. }
  178. VkPipeline CreateVkPipeline(VkDevice device, VkRenderPass render_pass) {
  179. VkShaderModule vertex_shader_module = CreateVkShaderModule(device, kVertexShaderPath);
  180. VkShaderModule fragment_shader_module = CreateVkShaderModule(device, kFragmentShaderPath);
  181. VkPipelineShaderStageCreateInfo vertex_shader_stage_info = {};
  182. vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  183. vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
  184. vertex_shader_stage_info.module = vertex_shader_module;
  185. vertex_shader_stage_info.pName = "main";
  186. VkPipelineShaderStageCreateInfo fragment_shader_stage_info = {};
  187. fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  188. fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
  189. fragment_shader_stage_info.module = fragment_shader_module;
  190. fragment_shader_stage_info.pName = "main";
  191. std::vector<VkPipelineShaderStageCreateInfo> shader_stages =
  192. {vertex_shader_stage_info, fragment_shader_stage_info};
  193. VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
  194. vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
  195. vertex_input_info.vertexBindingDescriptionCount = 0;
  196. vertex_input_info.pVertexBindingDescriptions = nullptr;
  197. vertex_input_info.vertexAttributeDescriptionCount = 0;
  198. vertex_input_info.pVertexAttributeDescriptions = nullptr;
  199. VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {};
  200. input_assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
  201. input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
  202. input_assembly_info.primitiveRestartEnable = VK_FALSE;
  203. VkViewport viewport = {};
  204. viewport.x = 0.0f;
  205. viewport.y = 0.0f;
  206. viewport.width = (float)kWidth;
  207. viewport.height = (float)kHeight;
  208. viewport.minDepth = 0.0f;
  209. viewport.maxDepth = 1.0f;
  210. VkExtent2D extent = {};
  211. extent.width = kWidth;
  212. extent.height = kHeight;
  213. VkRect2D scissor = {};
  214. scissor.offset = {0, 0};
  215. scissor.extent = extent;
  216. VkPipelineViewportStateCreateInfo viewport_state_info = {};
  217. viewport_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
  218. viewport_state_info.viewportCount = 1;
  219. viewport_state_info.pViewports = &viewport;
  220. viewport_state_info.scissorCount = 1;
  221. viewport_state_info.pScissors = &scissor;
  222. VkPipelineRasterizationStateCreateInfo rasterization_state_info = {};
  223. rasterization_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
  224. rasterization_state_info.depthClampEnable = VK_FALSE;
  225. rasterization_state_info.rasterizerDiscardEnable = VK_FALSE;
  226. rasterization_state_info.polygonMode = VK_POLYGON_MODE_FILL;
  227. rasterization_state_info.lineWidth = 1.0f;
  228. rasterization_state_info.cullMode = VK_CULL_MODE_BACK_BIT;
  229. rasterization_state_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
  230. rasterization_state_info.depthBiasEnable = VK_FALSE;
  231. VkPipelineMultisampleStateCreateInfo multisampling_state_info = {};
  232. multisampling_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
  233. multisampling_state_info.sampleShadingEnable = VK_FALSE;
  234. multisampling_state_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
  235. VkPipelineColorBlendAttachmentState color_blend_attachment_state = {};
  236. color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
  237. VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
  238. color_blend_attachment_state.blendEnable = VK_FALSE;
  239. VkPipelineColorBlendStateCreateInfo color_blend_state = {};
  240. color_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
  241. color_blend_state.logicOpEnable = VK_FALSE;
  242. color_blend_state.attachmentCount = 1;
  243. color_blend_state.pAttachments = &color_blend_attachment_state;
  244. VkPipelineLayoutCreateInfo pipeline_layout_create_info = {};
  245. pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
  246. VkPipelineLayout pipeline_layout;
  247. VkResult result = vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr,
  248. &pipeline_layout);
  249. if (result != VK_SUCCESS) {
  250. ERROR("Unable to create VkPipelineLayout: " << result);
  251. }
  252. VkGraphicsPipelineCreateInfo pipeline_create_info = {};
  253. pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
  254. pipeline_create_info.stageCount = 2;
  255. pipeline_create_info.pStages = shader_stages.data();
  256. pipeline_create_info.pVertexInputState = &vertex_input_info;
  257. pipeline_create_info.pInputAssemblyState = &input_assembly_info;
  258. pipeline_create_info.pViewportState = &viewport_state_info;
  259. pipeline_create_info.pRasterizationState = &rasterization_state_info;
  260. pipeline_create_info.pMultisampleState = &multisampling_state_info;
  261. pipeline_create_info.pDepthStencilState = nullptr;
  262. pipeline_create_info.pColorBlendState = &color_blend_state;
  263. pipeline_create_info.pDynamicState = nullptr;
  264. pipeline_create_info.layout = pipeline_layout;
  265. pipeline_create_info.renderPass = render_pass;
  266. pipeline_create_info.subpass = 0;
  267. pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
  268. pipeline_create_info.basePipelineIndex = -1;
  269. VkPipeline pipeline;
  270. result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_create_info, nullptr,
  271. &pipeline);
  272. if (result != VK_SUCCESS) {
  273. ERROR("Unable to create VkPipeline: " << result);
  274. }
  275. return pipeline;
  276. }
  277. VkImage CreateVkImage(VkDevice device) {
  278. VkImageCreateInfo create_info = {};
  279. create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  280. create_info.pNext = nullptr;
  281. create_info.imageType = VK_IMAGE_TYPE_2D;
  282. create_info.format = kVulkanFormat;
  283. VkExtent3D extent = {};
  284. extent.width = kWidth;
  285. extent.height = kHeight;
  286. extent.depth = 1;
  287. create_info.extent = extent;
  288. create_info.mipLevels = 1;
  289. create_info.arrayLayers = 1;
  290. create_info.samples = VK_SAMPLE_COUNT_1_BIT;
  291. create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  292. // create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
  293. create_info.tiling = VK_IMAGE_TILING_LINEAR;
  294. create_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  295. create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  296. VkImage image;
  297. VkResult result = vkCreateImage(device, &create_info, nullptr, &image);
  298. if (result != VK_SUCCESS) {
  299. ERROR("Unable to create VkImage: " << result);
  300. }
  301. return image;
  302. }
  303. uint32_t FindMemoryType(uint32_t valid_image_memory_types,
  304. VkPhysicalDeviceMemoryProperties device_memory_properties) {
  305. for (uint32_t i = 0; i < device_memory_properties.memoryTypeCount; i++) {
  306. // We don't care about performance, so just choose the first mappable memory type.
  307. if ((valid_image_memory_types % (1 << i)) &&
  308. (device_memory_properties.memoryTypes[i].propertyFlags &
  309. VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) {
  310. return i;
  311. }
  312. }
  313. ERROR("Unable to find suitable memory type index");
  314. }
  315. VkDeviceMemory AllocateAndBindMemory(VkPhysicalDevice physical_device, VkDevice device,
  316. VkImage image) {
  317. VkMemoryRequirements image_memory_requirements;
  318. vkGetImageMemoryRequirements(device, image, &image_memory_requirements);
  319. VkPhysicalDeviceMemoryProperties device_memory_properties;
  320. vkGetPhysicalDeviceMemoryProperties(physical_device, &device_memory_properties);
  321. VkMemoryAllocateInfo memory_allocate_info = {};
  322. memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  323. memory_allocate_info.allocationSize = image_memory_requirements.size;
  324. memory_allocate_info.memoryTypeIndex = FindMemoryType(
  325. image_memory_requirements.memoryTypeBits, device_memory_properties);
  326. VkDeviceMemory image_memory;
  327. VkResult result = vkAllocateMemory(device, &memory_allocate_info, nullptr, &image_memory);
  328. if (result != VK_SUCCESS) {
  329. ERROR("Unable to allocate image memory: " << result);
  330. }
  331. result = vkBindImageMemory(device, image, image_memory, 0);
  332. if (result != VK_SUCCESS) {
  333. ERROR("Unable to bind image memory: " << result);
  334. }
  335. return image_memory;
  336. }
  337. VkImageView CreateVkImageView(VkDevice device, VkImage image) {
  338. VkImageViewCreateInfo create_info = {};
  339. create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  340. create_info.image = image;
  341. create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
  342. create_info.format = kVulkanFormat;
  343. VkComponentMapping component_mapping = {};
  344. component_mapping.r = VK_COMPONENT_SWIZZLE_IDENTITY;
  345. component_mapping.b = VK_COMPONENT_SWIZZLE_IDENTITY;
  346. component_mapping.g = VK_COMPONENT_SWIZZLE_IDENTITY;
  347. component_mapping.a = VK_COMPONENT_SWIZZLE_IDENTITY;
  348. create_info.components = component_mapping;
  349. VkImageSubresourceRange subresource_range = {};
  350. subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  351. subresource_range.baseMipLevel = 0;
  352. subresource_range.levelCount = 1;
  353. subresource_range.baseArrayLayer = 0;
  354. subresource_range.layerCount = 1;
  355. create_info.subresourceRange = subresource_range;
  356. VkImageView image_view;
  357. VkResult result = vkCreateImageView(device, &create_info, nullptr, &image_view);
  358. if (result != VK_SUCCESS) {
  359. ERROR("Unable to create VkImageView: " << result);
  360. }
  361. return image_view;
  362. }
  363. VkFramebuffer CreateVkFramebuffer(VkDevice device, VkRenderPass render_pass,
  364. VkImageView image_view) {
  365. VkFramebufferCreateInfo create_info = {};
  366. create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
  367. create_info.renderPass = render_pass;
  368. create_info.attachmentCount = 1;
  369. create_info.pAttachments = &image_view;
  370. create_info.width = kWidth;
  371. create_info.height = kHeight;
  372. create_info.layers = 1;
  373. VkFramebuffer framebuffer;
  374. VkResult result = vkCreateFramebuffer(device, &create_info, nullptr, &framebuffer);
  375. if (result != VK_SUCCESS) {
  376. ERROR("Unable to create VkFramebuffer: " << result);
  377. }
  378. return framebuffer;
  379. }
  380. VkCommandBuffer CreateVkCommandBuffer(VkDevice device, VkCommandPool command_pool) {
  381. VkCommandBufferAllocateInfo allocate_info = {};
  382. allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  383. allocate_info.commandPool = command_pool;
  384. allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  385. allocate_info.commandBufferCount = 1;
  386. VkCommandBuffer command_buffer;
  387. VkResult result = vkAllocateCommandBuffers( device, &allocate_info, &command_buffer);
  388. if (result != VK_SUCCESS) {
  389. ERROR("Unable to create VkCommandBuffer: " << result);
  390. }
  391. return command_buffer;
  392. }
  393. void Draw(VkDevice device, VkQueue queue, VkRenderPass render_pass, VkPipeline pipeline,
  394. VkFramebuffer framebuffer, VkCommandBuffer command_buffer) {
  395. VkCommandBufferBeginInfo command_buffer_begin_info = {};
  396. command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  397. command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  398. VkResult result = vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);
  399. if (result != VK_SUCCESS) {
  400. ERROR("Unable to begin command buffer recording: " << result);
  401. }
  402. VkRenderPassBeginInfo render_pass_begin_info = {};
  403. render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  404. render_pass_begin_info.renderPass = render_pass;
  405. render_pass_begin_info.framebuffer = framebuffer;
  406. VkRect2D render_area = {};
  407. render_area.offset = { 0, 0 };
  408. render_area.extent = { kWidth, kHeight };
  409. render_pass_begin_info.renderArea = render_area;
  410. render_pass_begin_info.clearValueCount = 1;
  411. VkClearValue clear_value = {};
  412. clear_value.color.float32[0] = 1.0f;
  413. clear_value.color.float32[1] = 1.0f;
  414. clear_value.color.float32[2] = 0.0f;
  415. clear_value.color.float32[3] = 1.0f;
  416. render_pass_begin_info.pClearValues = &clear_value;
  417. vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
  418. vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  419. vkCmdDraw(command_buffer, 3, 1, 0, 0);
  420. vkCmdEndRenderPass(command_buffer);
  421. result = vkEndCommandBuffer(command_buffer);
  422. if (result != VK_SUCCESS) {
  423. ERROR("Unable to end command buffer recording: " << result);
  424. }
  425. VkSubmitInfo submit_info = {};
  426. submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  427. submit_info.commandBufferCount = 1;
  428. submit_info.pCommandBuffers = &command_buffer;
  429. result = vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
  430. if (result != VK_SUCCESS) {
  431. ERROR("Error in submitting command buffer to queue: " << result);
  432. }
  433. result = vkQueueWaitIdle(queue);
  434. if (result != VK_SUCCESS) {
  435. ERROR("Error in waiting for graphics queue to reach idle state: " << result);
  436. }
  437. }
  438. uint8_t* MapVkDeviceMemory(VkDevice device, VkDeviceMemory image_memory) {
  439. void* mapped_memory = nullptr;
  440. VkResult result = vkMapMemory(device, image_memory, 0, kWidth * kHeight * 4, 0, &mapped_memory);
  441. if (result != VK_SUCCESS) {
  442. ERROR("Unable to map device memory: " << result);
  443. }
  444. return static_cast<uint8_t*>(mapped_memory);
  445. }
  446. void WriteImage(uint8_t* pixels) {
  447. FILE *f = fopen("triangle.png", "wb");
  448. png_image image_info = {};
  449. image_info.version = PNG_IMAGE_VERSION;
  450. image_info.width = kWidth;
  451. image_info.height = kHeight;
  452. image_info.format = PNG_FORMAT_RGBA;
  453. if (png_image_write_to_stdio(&image_info, f, 0, pixels, kWidth * 4, nullptr) == 0) {
  454. ERROR("Error writing PNG: " << image_info.message);
  455. }
  456. fclose(f);
  457. }
  458. int main() {
  459. VkInstance instance = CreateVkInstance();
  460. VkPhysicalDevice physical_device = ChooseVkPhysicalDevice(instance);
  461. uint32_t device_queue_family_index = ChooseDeviceQueueFamilyIndex(physical_device);
  462. VkDevice device = CreateVkDevice(physical_device, device_queue_family_index);
  463. VkQueue queue = GetVkQueue(device, device_queue_family_index);
  464. VkCommandPool command_pool = CreateVkCommandPool(device, device_queue_family_index);
  465. VkRenderPass render_pass = CreateVkRenderPass(device);
  466. VkPipeline pipeline = CreateVkPipeline(device, render_pass);
  467. VkImage image = CreateVkImage(device);
  468. VkDeviceMemory image_memory = AllocateAndBindMemory(physical_device, device, image);
  469. VkImageView image_view = CreateVkImageView(device, image);
  470. VkFramebuffer framebuffer = CreateVkFramebuffer(device, render_pass, image_view);
  471. VkCommandBuffer command_buffer = CreateVkCommandBuffer(device, command_pool);
  472. Draw(device, queue, render_pass, pipeline, framebuffer, command_buffer);
  473. uint8_t* pixels = MapVkDeviceMemory(device, image_memory);
  474. WriteImage(pixels);
  475. return EXIT_SUCCESS;
  476. }