Binary that renders a triangle using Vulkan, scans the resulting image to a PNG, and makes an occlusion query to determine the number of fragments shaded. To be used in developing Turnip.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

occlusion.cc 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  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 = 256;
  9. const uint32_t kHeight = 256;
  10. const VkFormat kVulkanFormat = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
  11. const std::string kVertexShaderPath = "occlusion.vert.spv";
  12. const std::string kFragmentShaderPath = "occlusion.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. VkCommandBuffer CreateVkCommandBuffer(VkDevice device, VkCommandPool command_pool) {
  120. VkCommandBufferAllocateInfo allocate_info = {};
  121. allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  122. allocate_info.commandPool = command_pool;
  123. allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  124. allocate_info.commandBufferCount = 1;
  125. VkCommandBuffer command_buffer;
  126. VkResult result = vkAllocateCommandBuffers( device, &allocate_info, &command_buffer);
  127. if (result != VK_SUCCESS) {
  128. ERROR("Unable to create VkCommandBuffer: " << result);
  129. }
  130. return command_buffer;
  131. }
  132. VkRenderPass CreateVkRenderPass(VkDevice device) {
  133. VkAttachmentDescription attachment_description = {};
  134. attachment_description.format = kVulkanFormat;
  135. attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
  136. attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
  137. attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
  138. attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  139. attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  140. attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  141. attachment_description.finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
  142. VkAttachmentReference attachment_reference = {};
  143. attachment_reference.attachment = 0;
  144. attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
  145. VkSubpassDescription subpass_description = {};
  146. subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
  147. subpass_description.colorAttachmentCount = 1;
  148. subpass_description.pColorAttachments = &attachment_reference;
  149. VkSubpassDependency subpass_dependency = {};
  150. subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
  151. subpass_dependency.dstSubpass = 0;
  152. subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  153. subpass_dependency.srcAccessMask = 0;
  154. subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  155. subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
  156. VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  157. VkRenderPassCreateInfo render_pass_info = {};
  158. render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
  159. render_pass_info.attachmentCount = 1;
  160. render_pass_info.pAttachments = &attachment_description;
  161. render_pass_info.subpassCount = 1;
  162. render_pass_info.pSubpasses = &subpass_description;
  163. render_pass_info.dependencyCount = 1;
  164. render_pass_info.pDependencies = &subpass_dependency;
  165. VkRenderPass render_pass;
  166. VkResult result = vkCreateRenderPass(device, &render_pass_info, nullptr, &render_pass);
  167. if (result != VK_SUCCESS) {
  168. ERROR("Unable to create render pass: " << result);
  169. }
  170. return render_pass;
  171. }
  172. VkShaderModule CreateVkShaderModule(VkDevice device, std::string path) {
  173. std::ifstream fstream(path);
  174. if (!fstream) {
  175. ERROR("Unable to open: " << path);
  176. }
  177. std::stringstream buffer;
  178. buffer << fstream.rdbuf();
  179. std::string spirv_source = buffer.str();
  180. VkShaderModuleCreateInfo create_info = {};
  181. create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
  182. create_info.codeSize = spirv_source.length();
  183. create_info.pCode = (const uint32_t*)spirv_source.c_str();
  184. VkShaderModule shader_module;
  185. VkResult result = vkCreateShaderModule(device, &create_info, nullptr, &shader_module);
  186. if (result != VK_SUCCESS) {
  187. ERROR("Unable to create shader module for " << path << ": ");
  188. }
  189. return shader_module;
  190. }
  191. VkPipeline CreateVkPipeline(VkDevice device, VkRenderPass render_pass) {
  192. VkShaderModule vertex_shader_module = CreateVkShaderModule(device, kVertexShaderPath);
  193. VkShaderModule fragment_shader_module = CreateVkShaderModule(device, kFragmentShaderPath);
  194. VkPipelineShaderStageCreateInfo vertex_shader_stage_info = {};
  195. vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  196. vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
  197. vertex_shader_stage_info.module = vertex_shader_module;
  198. vertex_shader_stage_info.pName = "main";
  199. VkPipelineShaderStageCreateInfo fragment_shader_stage_info = {};
  200. fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  201. fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
  202. fragment_shader_stage_info.module = fragment_shader_module;
  203. fragment_shader_stage_info.pName = "main";
  204. std::vector<VkPipelineShaderStageCreateInfo> shader_stages =
  205. {vertex_shader_stage_info, fragment_shader_stage_info};
  206. VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
  207. vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
  208. vertex_input_info.vertexBindingDescriptionCount = 0;
  209. vertex_input_info.pVertexBindingDescriptions = nullptr;
  210. vertex_input_info.vertexAttributeDescriptionCount = 0;
  211. vertex_input_info.pVertexAttributeDescriptions = nullptr;
  212. VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {};
  213. input_assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
  214. input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
  215. input_assembly_info.primitiveRestartEnable = VK_FALSE;
  216. VkViewport viewport = {};
  217. viewport.x = 0.0f;
  218. viewport.y = 0.0f;
  219. viewport.width = (float)kWidth;
  220. viewport.height = (float)kHeight;
  221. viewport.minDepth = 0.0f;
  222. viewport.maxDepth = 1.0f;
  223. VkExtent2D extent = {};
  224. extent.width = kWidth;
  225. extent.height = kHeight;
  226. VkRect2D scissor = {};
  227. scissor.offset = {0, 0};
  228. scissor.extent = extent;
  229. VkPipelineViewportStateCreateInfo viewport_state_info = {};
  230. viewport_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
  231. viewport_state_info.viewportCount = 1;
  232. viewport_state_info.pViewports = &viewport;
  233. viewport_state_info.scissorCount = 1;
  234. viewport_state_info.pScissors = &scissor;
  235. VkPipelineRasterizationStateCreateInfo rasterization_state_info = {};
  236. rasterization_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
  237. rasterization_state_info.depthClampEnable = VK_FALSE;
  238. rasterization_state_info.rasterizerDiscardEnable = VK_FALSE;
  239. rasterization_state_info.polygonMode = VK_POLYGON_MODE_FILL;
  240. rasterization_state_info.lineWidth = 1.0f;
  241. rasterization_state_info.cullMode = VK_CULL_MODE_BACK_BIT;
  242. rasterization_state_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
  243. rasterization_state_info.depthBiasEnable = VK_FALSE;
  244. VkPipelineMultisampleStateCreateInfo multisampling_state_info = {};
  245. multisampling_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
  246. multisampling_state_info.sampleShadingEnable = VK_FALSE;
  247. multisampling_state_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
  248. VkPipelineColorBlendAttachmentState color_blend_attachment_state = {};
  249. color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
  250. VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
  251. color_blend_attachment_state.blendEnable = VK_FALSE;
  252. VkPipelineColorBlendStateCreateInfo color_blend_state = {};
  253. color_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
  254. color_blend_state.logicOpEnable = VK_FALSE;
  255. color_blend_state.attachmentCount = 1;
  256. color_blend_state.pAttachments = &color_blend_attachment_state;
  257. VkPipelineLayoutCreateInfo pipeline_layout_create_info = {};
  258. pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
  259. VkPipelineLayout pipeline_layout;
  260. VkResult result = vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr,
  261. &pipeline_layout);
  262. if (result != VK_SUCCESS) {
  263. ERROR("Unable to create VkPipelineLayout: " << result);
  264. }
  265. VkGraphicsPipelineCreateInfo pipeline_create_info = {};
  266. pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
  267. pipeline_create_info.stageCount = 2;
  268. pipeline_create_info.pStages = shader_stages.data();
  269. pipeline_create_info.pVertexInputState = &vertex_input_info;
  270. pipeline_create_info.pInputAssemblyState = &input_assembly_info;
  271. pipeline_create_info.pViewportState = &viewport_state_info;
  272. pipeline_create_info.pRasterizationState = &rasterization_state_info;
  273. pipeline_create_info.pMultisampleState = &multisampling_state_info;
  274. pipeline_create_info.pDepthStencilState = nullptr;
  275. pipeline_create_info.pColorBlendState = &color_blend_state;
  276. pipeline_create_info.pDynamicState = nullptr;
  277. pipeline_create_info.layout = pipeline_layout;
  278. pipeline_create_info.renderPass = render_pass;
  279. pipeline_create_info.subpass = 0;
  280. pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
  281. pipeline_create_info.basePipelineIndex = -1;
  282. VkPipeline pipeline;
  283. result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_create_info, nullptr,
  284. &pipeline);
  285. if (result != VK_SUCCESS) {
  286. ERROR("Unable to create VkPipeline: " << result);
  287. }
  288. return pipeline;
  289. }
  290. VkImage CreateVkImage(VkDevice device, VkImageTiling image_tiling, VkImageUsageFlags usage) {
  291. VkImageCreateInfo create_info = {};
  292. create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  293. create_info.pNext = nullptr;
  294. create_info.imageType = VK_IMAGE_TYPE_2D;
  295. create_info.format = kVulkanFormat;
  296. VkExtent3D extent = {};
  297. extent.width = kWidth;
  298. extent.height = kHeight;
  299. extent.depth = 1;
  300. create_info.extent = extent;
  301. create_info.mipLevels = 1;
  302. create_info.arrayLayers = 1;
  303. create_info.samples = VK_SAMPLE_COUNT_1_BIT;
  304. create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  305. create_info.tiling = image_tiling;
  306. create_info.usage = usage;
  307. create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  308. VkImage image;
  309. VkResult result = vkCreateImage(device, &create_info, nullptr, &image);
  310. if (result != VK_SUCCESS) {
  311. ERROR("Unable to create VkImage: " << result);
  312. }
  313. return image;
  314. }
  315. inline VkImage CreateRenderVkImage(VkDevice device) {
  316. return CreateVkImage(device, VK_IMAGE_TILING_OPTIMAL,
  317. VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
  318. }
  319. inline VkImage CreateScanoutVkImage(VkDevice device) {
  320. return CreateVkImage(device, VK_IMAGE_TILING_LINEAR,
  321. VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
  322. }
  323. uint32_t FindMemoryType(uint32_t valid_image_memory_types,
  324. VkPhysicalDeviceMemoryProperties device_memory_properties,
  325. VkMemoryPropertyFlags memory_property_flags) {
  326. for (uint32_t i = 0; i < device_memory_properties.memoryTypeCount; i++) {
  327. // We don't care about performance, so just choose the first mappable memory type.
  328. if ((valid_image_memory_types % (1 << i)) &&
  329. ((device_memory_properties.memoryTypes[i].propertyFlags & memory_property_flags) ==
  330. memory_property_flags)) {
  331. return i;
  332. }
  333. }
  334. ERROR("Unable to find suitable memory type index");
  335. }
  336. VkDeviceMemory AllocateAndBindMemory(VkPhysicalDevice physical_device, VkDevice device,
  337. VkImage image, VkMemoryPropertyFlags memory_property_flags) {
  338. VkMemoryRequirements image_memory_requirements;
  339. vkGetImageMemoryRequirements(device, image, &image_memory_requirements);
  340. VkPhysicalDeviceMemoryProperties device_memory_properties;
  341. vkGetPhysicalDeviceMemoryProperties(physical_device, &device_memory_properties);
  342. VkMemoryAllocateInfo memory_allocate_info = {};
  343. memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  344. memory_allocate_info.allocationSize = image_memory_requirements.size;
  345. memory_allocate_info.memoryTypeIndex = FindMemoryType(
  346. image_memory_requirements.memoryTypeBits, device_memory_properties,
  347. memory_property_flags);
  348. VkDeviceMemory image_memory;
  349. VkResult result = vkAllocateMemory(device, &memory_allocate_info, nullptr, &image_memory);
  350. if (result != VK_SUCCESS) {
  351. ERROR("Unable to allocate image memory: " << result);
  352. }
  353. result = vkBindImageMemory(device, image, image_memory, 0);
  354. if (result != VK_SUCCESS) {
  355. ERROR("Unable to bind image memory: " << result);
  356. }
  357. return image_memory;
  358. }
  359. inline VkDeviceMemory AllocateAndBindRenderMemory(VkPhysicalDevice physical_device,
  360. VkDevice device, VkImage image) {
  361. return AllocateAndBindMemory(physical_device, device, image, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
  362. }
  363. inline VkDeviceMemory AllocateAndBindScanoutMemory(VkPhysicalDevice physical_device,
  364. VkDevice device, VkImage image) {
  365. return AllocateAndBindMemory(physical_device, device, image, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
  366. }
  367. VkImageView CreateVkImageView(VkDevice device, VkImage image) {
  368. VkImageViewCreateInfo create_info = {};
  369. create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  370. create_info.image = image;
  371. create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
  372. create_info.format = kVulkanFormat;
  373. VkComponentMapping component_mapping = {};
  374. component_mapping.r = VK_COMPONENT_SWIZZLE_IDENTITY;
  375. component_mapping.b = VK_COMPONENT_SWIZZLE_IDENTITY;
  376. component_mapping.g = VK_COMPONENT_SWIZZLE_IDENTITY;
  377. component_mapping.a = VK_COMPONENT_SWIZZLE_IDENTITY;
  378. create_info.components = component_mapping;
  379. VkImageSubresourceRange subresource_range = {};
  380. subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  381. subresource_range.baseMipLevel = 0;
  382. subresource_range.levelCount = 1;
  383. subresource_range.baseArrayLayer = 0;
  384. subresource_range.layerCount = 1;
  385. create_info.subresourceRange = subresource_range;
  386. VkImageView image_view;
  387. VkResult result = vkCreateImageView(device, &create_info, nullptr, &image_view);
  388. if (result != VK_SUCCESS) {
  389. ERROR("Unable to create VkImageView: " << result);
  390. }
  391. return image_view;
  392. }
  393. VkFramebuffer CreateVkFramebuffer(VkDevice device, VkRenderPass render_pass,
  394. VkImageView image_view) {
  395. VkFramebufferCreateInfo create_info = {};
  396. create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
  397. create_info.renderPass = render_pass;
  398. create_info.attachmentCount = 1;
  399. create_info.pAttachments = &image_view;
  400. create_info.width = kWidth;
  401. create_info.height = kHeight;
  402. create_info.layers = 1;
  403. VkFramebuffer framebuffer;
  404. VkResult result = vkCreateFramebuffer(device, &create_info, nullptr, &framebuffer);
  405. if (result != VK_SUCCESS) {
  406. ERROR("Unable to create VkFramebuffer: " << result);
  407. }
  408. return framebuffer;
  409. }
  410. void BeginCommandBuffer(VkCommandBuffer command_buffer) {
  411. VkCommandBufferBeginInfo command_buffer_begin_info = {};
  412. command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  413. command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  414. VkResult result = vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);
  415. if (result != VK_SUCCESS) {
  416. ERROR("Unable to begin command buffer recording: " << result);
  417. }
  418. }
  419. void EndCommandBufferAndSubmit(VkCommandBuffer command_buffer, VkQueue queue) {
  420. VkResult result = vkEndCommandBuffer(command_buffer);
  421. if (result != VK_SUCCESS) {
  422. ERROR("Unable to end command buffer recording: " << result);
  423. }
  424. VkSubmitInfo submit_info = {};
  425. submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  426. submit_info.commandBufferCount = 1;
  427. submit_info.pCommandBuffers = &command_buffer;
  428. result = vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
  429. if (result != VK_SUCCESS) {
  430. ERROR("Error in submitting command buffer to queue: " << result);
  431. }
  432. }
  433. void WaitForIdle(VkQueue queue) {
  434. // In a real application, we should use real synchronization primitives to figure out when the
  435. // command buffers have been executed. Waiting on an idle queue is simple, but it can cause
  436. // deadlock if we continue to submit to the queue while we wait for idle.
  437. VkResult result = vkQueueWaitIdle(queue);
  438. if (result != VK_SUCCESS) {
  439. ERROR("Error in waiting for graphics queue to reach idle state: " << result);
  440. }
  441. }
  442. void Draw(VkDevice device, VkQueue queue, VkRenderPass render_pass, VkPipeline pipeline,
  443. VkFramebuffer framebuffer, VkCommandBuffer command_buffer) {
  444. BeginCommandBuffer(command_buffer);
  445. VkRenderPassBeginInfo render_pass_begin_info = {};
  446. render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  447. render_pass_begin_info.renderPass = render_pass;
  448. render_pass_begin_info.framebuffer = framebuffer;
  449. VkRect2D render_area = {};
  450. render_area.offset = { 0, 0 };
  451. render_area.extent = { kWidth, kHeight };
  452. render_pass_begin_info.renderArea = render_area;
  453. render_pass_begin_info.clearValueCount = 1;
  454. VkClearValue clear_value = {};
  455. clear_value.color.float32[0] = 1.0f;
  456. clear_value.color.float32[1] = 1.0f;
  457. clear_value.color.float32[2] = 0.0f;
  458. clear_value.color.float32[3] = 1.0f;
  459. render_pass_begin_info.pClearValues = &clear_value;
  460. vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
  461. vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  462. vkCmdDraw(command_buffer, 3, 1, 0, 0);
  463. vkCmdEndRenderPass(command_buffer);
  464. }
  465. void BlitToScanoutImage(VkQueue queue, VkCommandBuffer command_buffer, VkImage source_image,
  466. VkImage dest_image) {
  467. // We need to make sure the writes of the render pass have executed before actually scanning out
  468. // the rendered image. Also, we need to transition the layout of the scanout image to
  469. // VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
  470. VkImageMemoryBarrier image_memory_barrier = {};
  471. image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
  472. image_memory_barrier.pNext = nullptr;
  473. image_memory_barrier.srcAccessMask = 0;
  474. image_memory_barrier.dstAccessMask = 0;
  475. image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  476. image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  477. image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  478. image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  479. image_memory_barrier.image = dest_image;
  480. VkImageSubresourceRange subresource_range = {};
  481. subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  482. subresource_range.baseMipLevel = 0;
  483. subresource_range.levelCount = 1;
  484. subresource_range.baseArrayLayer = 0;
  485. subresource_range.layerCount = 1;
  486. image_memory_barrier.subresourceRange = subresource_range;
  487. vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
  488. VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
  489. VkOffset3D blit_start = {};
  490. blit_start.x = 0;
  491. blit_start.y = 0;
  492. blit_start.z = 0;
  493. VkOffset3D blit_end = {};
  494. blit_end.x = kWidth;
  495. blit_end.y = kHeight;
  496. blit_end.z = 1;
  497. VkImageSubresourceLayers subresource_layers = {};
  498. subresource_layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  499. subresource_layers.mipLevel = 0;
  500. subresource_layers.baseArrayLayer = 0;
  501. subresource_layers.layerCount = 1;
  502. VkImageBlit image_blit = {};
  503. image_blit.srcSubresource = subresource_layers;
  504. image_blit.srcOffsets[0] = blit_start;
  505. image_blit.srcOffsets[1] = blit_end;
  506. image_blit.dstSubresource = subresource_layers;
  507. image_blit.dstOffsets[0] = blit_start;
  508. image_blit.dstOffsets[1] = blit_end;
  509. // TODO(brkho): Support multi-planar formats.
  510. vkCmdBlitImage(command_buffer, source_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dest_image,
  511. VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_blit, VK_FILTER_NEAREST);
  512. EndCommandBufferAndSubmit(command_buffer, queue);
  513. }
  514. uint8_t* MapVkDeviceMemory(VkDevice device, VkDeviceMemory image_memory) {
  515. void* mapped_memory = nullptr;
  516. VkResult result = vkMapMemory(device, image_memory, 0, kWidth * kHeight * 4, 0, &mapped_memory);
  517. if (result != VK_SUCCESS) {
  518. ERROR("Unable to map device memory: " << result);
  519. }
  520. return static_cast<uint8_t*>(mapped_memory);
  521. }
  522. void WriteImage(uint8_t* pixels) {
  523. FILE *f = fopen("occlusion.png", "wb");
  524. png_image image_info = {};
  525. image_info.version = PNG_IMAGE_VERSION;
  526. image_info.width = kWidth;
  527. image_info.height = kHeight;
  528. image_info.format = PNG_FORMAT_RGBA;
  529. if (png_image_write_to_stdio(&image_info, f, 0, pixels, kWidth * 4, nullptr) == 0) {
  530. ERROR("Error writing PNG: " << image_info.message);
  531. }
  532. fclose(f);
  533. }
  534. int main() {
  535. VkInstance instance = CreateVkInstance();
  536. VkPhysicalDevice physical_device = ChooseVkPhysicalDevice(instance);
  537. uint32_t device_queue_family_index = ChooseDeviceQueueFamilyIndex(physical_device);
  538. VkDevice device = CreateVkDevice(physical_device, device_queue_family_index);
  539. VkQueue queue = GetVkQueue(device, device_queue_family_index);
  540. VkCommandPool command_pool = CreateVkCommandPool(device, device_queue_family_index);
  541. VkCommandBuffer command_buffer = CreateVkCommandBuffer(device, command_pool);
  542. VkRenderPass render_pass = CreateVkRenderPass(device);
  543. VkPipeline pipeline = CreateVkPipeline(device, render_pass);
  544. VkImage render_image = CreateRenderVkImage(device);
  545. AllocateAndBindRenderMemory(physical_device, device, render_image);
  546. VkImageView render_image_view = CreateVkImageView(device, render_image);
  547. VkFramebuffer framebuffer = CreateVkFramebuffer(device, render_pass, render_image_view);
  548. VkImage scanout_image = CreateScanoutVkImage(device);
  549. VkDeviceMemory scanout_image_memory =
  550. AllocateAndBindScanoutMemory(physical_device, device, scanout_image);
  551. Draw(device, queue, render_pass, pipeline, framebuffer, command_buffer);
  552. // Since the render target is created with VK_IMAGE_TILING_OPTIMAL, we need to copy it to a linear
  553. // format before scanning out.
  554. BlitToScanoutImage(queue, command_buffer, render_image, scanout_image);
  555. WaitForIdle(queue);
  556. uint8_t* pixels = MapVkDeviceMemory(device, scanout_image_memory);
  557. WriteImage(pixels);
  558. return EXIT_SUCCESS;
  559. }