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.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. #include <png.h>
  2. #include <vulkan/vulkan.h>
  3. #include <array>
  4. #include <fstream>
  5. #include <iostream>
  6. #include <sstream>
  7. #include <string>
  8. #include <vector>
  9. const uint32_t kWidth = 256;
  10. const uint32_t kHeight = 256;
  11. const VkFormat kVulkanFormat = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
  12. const VkFormat kVulkanDepthFormat = VK_FORMAT_D32_SFLOAT;
  13. const std::string kVertexShaderPath = "occlusion.vert.spv";
  14. const std::string kFragmentShaderPath = "occlusion.frag.spv";
  15. #define ERROR(message) \
  16. std::cerr << message << std::endl; \
  17. std::exit(EXIT_FAILURE)
  18. VkInstance CreateVkInstance() {
  19. VkApplicationInfo app_info = {};
  20. app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  21. app_info.apiVersion = VK_API_VERSION_1_1;
  22. VkInstanceCreateInfo create_info = {};
  23. create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  24. create_info.pApplicationInfo = &app_info;
  25. create_info.enabledExtensionCount = 0;
  26. create_info.ppEnabledExtensionNames = nullptr;
  27. create_info.enabledLayerCount = 0;
  28. create_info.ppEnabledLayerNames = nullptr;
  29. VkInstance instance;
  30. VkResult result = vkCreateInstance(&create_info, nullptr, &instance);
  31. if (result != VK_SUCCESS) {
  32. ERROR("Error creating VkInstance: " << result);
  33. }
  34. return instance;
  35. }
  36. VkPhysicalDevice ChooseVkPhysicalDevice(VkInstance instance) {
  37. uint32_t device_count = 0;
  38. VkResult result = vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
  39. if (result != VK_SUCCESS) {
  40. ERROR("Error enumerating VkPhysicalDevices: " << result);
  41. }
  42. if (device_count == 0) {
  43. ERROR("No available VkPhysicalDevices");
  44. }
  45. std::vector<VkPhysicalDevice> devices(device_count);
  46. result = vkEnumeratePhysicalDevices(instance, &device_count, devices.data());
  47. if (result != VK_SUCCESS) {
  48. ERROR("Error fetching VkPhysicalDevices: " << result);
  49. }
  50. std::cout << "Found " << device_count << " device(s):" << std::endl;
  51. VkPhysicalDevice chosen_device = VK_NULL_HANDLE;
  52. for (VkPhysicalDevice device : devices) {
  53. VkPhysicalDeviceProperties device_props;
  54. vkGetPhysicalDeviceProperties(device, &device_props);
  55. std::cout << "\t- " << device_props.deviceName << " [V: " <<
  56. VK_VERSION_MAJOR(device_props.apiVersion) << "." <<
  57. VK_VERSION_MINOR(device_props.apiVersion) << "." <<
  58. VK_VERSION_PATCH(device_props.apiVersion) << "]" << std::endl;
  59. // Currently, any device with Vulkan API version 1.1 is fine.
  60. if (chosen_device == VK_NULL_HANDLE && device_props.apiVersion >= VK_API_VERSION_1_1) {
  61. chosen_device = device;
  62. }
  63. }
  64. if (chosen_device == VK_NULL_HANDLE) {
  65. ERROR("Unable to find suitable VkPhysicalDevice");
  66. }
  67. return chosen_device;
  68. }
  69. uint32_t ChooseDeviceQueueFamilyIndex(VkPhysicalDevice physical_device) {
  70. uint32_t props_count;
  71. vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &props_count, nullptr);
  72. std::vector<VkQueueFamilyProperties> props(props_count);
  73. vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &props_count, props.data());
  74. // Simply choose the first graphics queue.
  75. for (size_t i = 0; i < props_count; i++) {
  76. const VkQueueFamilyProperties& prop = props[i];
  77. if ((prop.queueFlags & VK_QUEUE_GRAPHICS_BIT) && prop.queueCount > 0) {
  78. return i;
  79. }
  80. }
  81. ERROR("Unable to find suitable queue family");
  82. }
  83. VkDevice CreateVkDevice(VkPhysicalDevice physical_device, uint32_t device_queue_family_index) {
  84. VkDeviceQueueCreateInfo queue_create_info = {};
  85. queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  86. queue_create_info.queueFamilyIndex = device_queue_family_index;
  87. queue_create_info.queueCount = 1;
  88. float queue_priority = 1.0f;
  89. queue_create_info.pQueuePriorities = &queue_priority;
  90. VkDeviceCreateInfo device_create_info = {};
  91. device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  92. device_create_info.queueCreateInfoCount = 1;
  93. device_create_info.pQueueCreateInfos = &queue_create_info;
  94. // Let's not use any device extensions for now.
  95. device_create_info.enabledExtensionCount = 0;
  96. device_create_info.ppEnabledExtensionNames = nullptr;
  97. VkDevice device;
  98. VkResult result = vkCreateDevice(physical_device, &device_create_info, nullptr, &device);
  99. if (result != VK_SUCCESS) {
  100. ERROR("Unable to create logical device: " << result);
  101. }
  102. return device;
  103. }
  104. VkQueue GetVkQueue(VkDevice device, uint32_t device_queue_family_index) {
  105. VkQueue queue;
  106. vkGetDeviceQueue(device, device_queue_family_index, /*queueIndex*/ 0, &queue);
  107. return queue;
  108. }
  109. VkCommandPool CreateVkCommandPool(VkDevice device, uint32_t device_queue_family_index) {
  110. VkCommandPool command_pool;
  111. VkCommandPoolCreateInfo create_info = {};
  112. create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
  113. create_info.flags = 0;
  114. create_info.queueFamilyIndex = device_queue_family_index;
  115. VkResult result = vkCreateCommandPool(device, &create_info, nullptr, &command_pool);
  116. if (result != VK_SUCCESS) {
  117. ERROR("Unable to create command pool: " << result);
  118. }
  119. return command_pool;
  120. }
  121. VkCommandBuffer CreateVkCommandBuffer(VkDevice device, VkCommandPool command_pool) {
  122. VkCommandBufferAllocateInfo allocate_info = {};
  123. allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  124. allocate_info.commandPool = command_pool;
  125. allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  126. allocate_info.commandBufferCount = 1;
  127. VkCommandBuffer command_buffer;
  128. VkResult result = vkAllocateCommandBuffers( device, &allocate_info, &command_buffer);
  129. if (result != VK_SUCCESS) {
  130. ERROR("Unable to create VkCommandBuffer: " << result);
  131. }
  132. return command_buffer;
  133. }
  134. VkQueryPool CreateVkQueryPool(VkDevice device) {
  135. VkQueryPoolCreateInfo query_pool_create_info = {};
  136. query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
  137. query_pool_create_info.pNext = nullptr;
  138. query_pool_create_info.queryType = VK_QUERY_TYPE_OCCLUSION;
  139. query_pool_create_info.queryCount = 1;
  140. query_pool_create_info.flags = 0;
  141. query_pool_create_info.pipelineStatistics = 0;
  142. VkQueryPool query_pool;
  143. VkResult result = vkCreateQueryPool(device, &query_pool_create_info, nullptr, &query_pool);
  144. if (result != VK_SUCCESS) {
  145. ERROR("Unable to create VkQueryPool: " << result);
  146. }
  147. return query_pool;
  148. }
  149. VkRenderPass CreateVkRenderPass(VkDevice device) {
  150. std::array<VkAttachmentDescription, 2> attachment_descriptions = {};
  151. VkAttachmentDescription* color_attachment_description = &attachment_descriptions[0];
  152. color_attachment_description->format = kVulkanFormat;
  153. color_attachment_description->samples = VK_SAMPLE_COUNT_1_BIT;
  154. color_attachment_description->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
  155. color_attachment_description->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
  156. color_attachment_description->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  157. color_attachment_description->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  158. color_attachment_description->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  159. color_attachment_description->finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
  160. VkAttachmentReference color_attachment_reference = {};
  161. color_attachment_reference.attachment = 0;
  162. color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
  163. VkAttachmentDescription* depth_attachment_description = &attachment_descriptions[1];
  164. depth_attachment_description->format = kVulkanDepthFormat;
  165. depth_attachment_description->samples = VK_SAMPLE_COUNT_1_BIT;
  166. depth_attachment_description->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
  167. depth_attachment_description->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  168. depth_attachment_description->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  169. depth_attachment_description->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  170. depth_attachment_description->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  171. depth_attachment_description->finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
  172. VkAttachmentReference depth_attachment_reference = {};
  173. depth_attachment_reference.attachment = 1;
  174. depth_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
  175. VkSubpassDescription subpass_description = {};
  176. subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
  177. subpass_description.colorAttachmentCount = 1;
  178. subpass_description.pColorAttachments = &color_attachment_reference;
  179. subpass_description.pDepthStencilAttachment = &depth_attachment_reference;
  180. VkSubpassDependency subpass_dependency = {};
  181. subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
  182. subpass_dependency.dstSubpass = 0;
  183. subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  184. subpass_dependency.srcAccessMask = 0;
  185. subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  186. subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
  187. VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  188. VkRenderPassCreateInfo render_pass_info = {};
  189. render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
  190. render_pass_info.attachmentCount = attachment_descriptions.size();
  191. render_pass_info.pAttachments = attachment_descriptions.data();
  192. render_pass_info.subpassCount = 1;
  193. render_pass_info.pSubpasses = &subpass_description;
  194. render_pass_info.dependencyCount = 1;
  195. render_pass_info.pDependencies = &subpass_dependency;
  196. VkRenderPass render_pass;
  197. VkResult result = vkCreateRenderPass(device, &render_pass_info, nullptr, &render_pass);
  198. if (result != VK_SUCCESS) {
  199. ERROR("Unable to create render pass: " << result);
  200. }
  201. return render_pass;
  202. }
  203. VkShaderModule CreateVkShaderModule(VkDevice device, std::string path) {
  204. std::ifstream fstream(path);
  205. if (!fstream) {
  206. ERROR("Unable to open: " << path);
  207. }
  208. std::stringstream buffer;
  209. buffer << fstream.rdbuf();
  210. std::string spirv_source = buffer.str();
  211. VkShaderModuleCreateInfo create_info = {};
  212. create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
  213. create_info.codeSize = spirv_source.length();
  214. create_info.pCode = (const uint32_t*)spirv_source.c_str();
  215. VkShaderModule shader_module;
  216. VkResult result = vkCreateShaderModule(device, &create_info, nullptr, &shader_module);
  217. if (result != VK_SUCCESS) {
  218. ERROR("Unable to create shader module for " << path << ": ");
  219. }
  220. return shader_module;
  221. }
  222. VkPipeline CreateVkPipeline(VkDevice device, VkRenderPass render_pass) {
  223. VkShaderModule vertex_shader_module = CreateVkShaderModule(device, kVertexShaderPath);
  224. VkShaderModule fragment_shader_module = CreateVkShaderModule(device, kFragmentShaderPath);
  225. VkPipelineShaderStageCreateInfo vertex_shader_stage_info = {};
  226. vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  227. vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
  228. vertex_shader_stage_info.module = vertex_shader_module;
  229. vertex_shader_stage_info.pName = "main";
  230. VkPipelineShaderStageCreateInfo fragment_shader_stage_info = {};
  231. fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  232. fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
  233. fragment_shader_stage_info.module = fragment_shader_module;
  234. fragment_shader_stage_info.pName = "main";
  235. std::vector<VkPipelineShaderStageCreateInfo> shader_stages =
  236. {vertex_shader_stage_info, fragment_shader_stage_info};
  237. VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
  238. vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
  239. vertex_input_info.vertexBindingDescriptionCount = 0;
  240. vertex_input_info.pVertexBindingDescriptions = nullptr;
  241. vertex_input_info.vertexAttributeDescriptionCount = 0;
  242. vertex_input_info.pVertexAttributeDescriptions = nullptr;
  243. VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {};
  244. input_assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
  245. input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
  246. input_assembly_info.primitiveRestartEnable = VK_FALSE;
  247. VkViewport viewport = {};
  248. viewport.x = 0.0f;
  249. viewport.y = 0.0f;
  250. viewport.width = (float)kWidth;
  251. viewport.height = (float)kHeight;
  252. viewport.minDepth = 0.0f;
  253. viewport.maxDepth = 1.0f;
  254. VkExtent2D extent = {};
  255. extent.width = kWidth;
  256. extent.height = kHeight;
  257. VkRect2D scissor = {};
  258. scissor.offset = {0, 0};
  259. scissor.extent = extent;
  260. VkPipelineViewportStateCreateInfo viewport_state_info = {};
  261. viewport_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
  262. viewport_state_info.viewportCount = 1;
  263. viewport_state_info.pViewports = &viewport;
  264. viewport_state_info.scissorCount = 1;
  265. viewport_state_info.pScissors = &scissor;
  266. VkPipelineRasterizationStateCreateInfo rasterization_state_info = {};
  267. rasterization_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
  268. rasterization_state_info.depthClampEnable = VK_FALSE;
  269. rasterization_state_info.rasterizerDiscardEnable = VK_FALSE;
  270. rasterization_state_info.polygonMode = VK_POLYGON_MODE_FILL;
  271. rasterization_state_info.lineWidth = 1.0f;
  272. rasterization_state_info.cullMode = VK_CULL_MODE_BACK_BIT;
  273. rasterization_state_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
  274. rasterization_state_info.depthBiasEnable = VK_FALSE;
  275. VkPipelineMultisampleStateCreateInfo multisampling_state_info = {};
  276. multisampling_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
  277. multisampling_state_info.sampleShadingEnable = VK_FALSE;
  278. multisampling_state_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
  279. VkPipelineDepthStencilStateCreateInfo depth_stencil_create_info = {};
  280. depth_stencil_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
  281. depth_stencil_create_info.depthTestEnable = VK_TRUE;
  282. depth_stencil_create_info.depthWriteEnable = VK_TRUE;
  283. depth_stencil_create_info.depthCompareOp = VK_COMPARE_OP_LESS;
  284. // TODO(brkho): Test depth bounds functionality.
  285. depth_stencil_create_info.depthBoundsTestEnable = VK_FALSE;
  286. depth_stencil_create_info.minDepthBounds = 0.0f;
  287. depth_stencil_create_info.maxDepthBounds = 1.0f;
  288. depth_stencil_create_info.stencilTestEnable = VK_FALSE;
  289. VkPipelineColorBlendAttachmentState color_blend_attachment_state = {};
  290. color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
  291. VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
  292. color_blend_attachment_state.blendEnable = VK_FALSE;
  293. VkPipelineColorBlendStateCreateInfo color_blend_state = {};
  294. color_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
  295. color_blend_state.logicOpEnable = VK_FALSE;
  296. color_blend_state.attachmentCount = 1;
  297. color_blend_state.pAttachments = &color_blend_attachment_state;
  298. VkPipelineLayoutCreateInfo pipeline_layout_create_info = {};
  299. pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
  300. VkPipelineLayout pipeline_layout;
  301. VkResult result = vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr,
  302. &pipeline_layout);
  303. if (result != VK_SUCCESS) {
  304. ERROR("Unable to create VkPipelineLayout: " << result);
  305. }
  306. VkGraphicsPipelineCreateInfo pipeline_create_info = {};
  307. pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
  308. pipeline_create_info.stageCount = 2;
  309. pipeline_create_info.pStages = shader_stages.data();
  310. pipeline_create_info.pVertexInputState = &vertex_input_info;
  311. pipeline_create_info.pInputAssemblyState = &input_assembly_info;
  312. pipeline_create_info.pViewportState = &viewport_state_info;
  313. pipeline_create_info.pRasterizationState = &rasterization_state_info;
  314. pipeline_create_info.pMultisampleState = &multisampling_state_info;
  315. pipeline_create_info.pDepthStencilState = &depth_stencil_create_info;
  316. pipeline_create_info.pColorBlendState = &color_blend_state;
  317. pipeline_create_info.pDynamicState = nullptr;
  318. pipeline_create_info.layout = pipeline_layout;
  319. pipeline_create_info.renderPass = render_pass;
  320. pipeline_create_info.subpass = 0;
  321. pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
  322. pipeline_create_info.basePipelineIndex = -1;
  323. VkPipeline pipeline;
  324. result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_create_info, nullptr,
  325. &pipeline);
  326. if (result != VK_SUCCESS) {
  327. ERROR("Unable to create VkPipeline: " << result);
  328. }
  329. return pipeline;
  330. }
  331. VkImage CreateVkImage(VkDevice device, VkFormat format, VkImageTiling image_tiling,
  332. VkImageUsageFlags usage) {
  333. VkImageCreateInfo create_info = {};
  334. create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  335. create_info.pNext = nullptr;
  336. create_info.imageType = VK_IMAGE_TYPE_2D;
  337. create_info.format = format;
  338. VkExtent3D extent = {};
  339. extent.width = kWidth;
  340. extent.height = kHeight;
  341. extent.depth = 1;
  342. create_info.extent = extent;
  343. create_info.mipLevels = 1;
  344. create_info.arrayLayers = 1;
  345. create_info.samples = VK_SAMPLE_COUNT_1_BIT;
  346. create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  347. create_info.tiling = image_tiling;
  348. create_info.usage = usage;
  349. create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  350. VkImage image;
  351. VkResult result = vkCreateImage(device, &create_info, nullptr, &image);
  352. if (result != VK_SUCCESS) {
  353. ERROR("Unable to create VkImage: " << result);
  354. }
  355. return image;
  356. }
  357. inline VkImage CreateRenderVkImage(VkDevice device) {
  358. return CreateVkImage(device, kVulkanFormat, VK_IMAGE_TILING_OPTIMAL,
  359. VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
  360. }
  361. inline VkImage CreateDepthVkImage(VkDevice device) {
  362. return CreateVkImage(device, kVulkanDepthFormat, VK_IMAGE_TILING_OPTIMAL,
  363. VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
  364. }
  365. inline VkImage CreateScanoutVkImage(VkDevice device) {
  366. return CreateVkImage(device, kVulkanFormat, VK_IMAGE_TILING_LINEAR,
  367. VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
  368. }
  369. uint32_t FindMemoryType(uint32_t valid_image_memory_types,
  370. VkPhysicalDeviceMemoryProperties device_memory_properties,
  371. VkMemoryPropertyFlags memory_property_flags) {
  372. for (uint32_t i = 0; i < device_memory_properties.memoryTypeCount; i++) {
  373. // We don't care about performance, so just choose the first mappable memory type.
  374. if ((valid_image_memory_types & (1 << i)) &&
  375. ((device_memory_properties.memoryTypes[i].propertyFlags & memory_property_flags) ==
  376. memory_property_flags)) {
  377. return i;
  378. }
  379. }
  380. ERROR("Unable to find suitable memory type index");
  381. }
  382. VkDeviceMemory AllocateAndBindMemory(VkPhysicalDevice physical_device, VkDevice device,
  383. VkImage image, VkMemoryPropertyFlags memory_property_flags) {
  384. VkMemoryRequirements image_memory_requirements;
  385. vkGetImageMemoryRequirements(device, image, &image_memory_requirements);
  386. VkPhysicalDeviceMemoryProperties device_memory_properties;
  387. vkGetPhysicalDeviceMemoryProperties(physical_device, &device_memory_properties);
  388. VkMemoryAllocateInfo memory_allocate_info = {};
  389. memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  390. memory_allocate_info.allocationSize = image_memory_requirements.size;
  391. memory_allocate_info.memoryTypeIndex = FindMemoryType(
  392. image_memory_requirements.memoryTypeBits, device_memory_properties,
  393. memory_property_flags);
  394. VkDeviceMemory image_memory;
  395. VkResult result = vkAllocateMemory(device, &memory_allocate_info, nullptr, &image_memory);
  396. if (result != VK_SUCCESS) {
  397. ERROR("Unable to allocate image memory: " << result);
  398. }
  399. result = vkBindImageMemory(device, image, image_memory, 0);
  400. if (result != VK_SUCCESS) {
  401. ERROR("Unable to bind image memory: " << result);
  402. }
  403. return image_memory;
  404. }
  405. inline VkDeviceMemory AllocateAndBindRenderMemory(VkPhysicalDevice physical_device,
  406. VkDevice device, VkImage image) {
  407. return AllocateAndBindMemory(physical_device, device, image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  408. }
  409. inline VkDeviceMemory AllocateAndBindDepthMemory(VkPhysicalDevice physical_device,
  410. VkDevice device, VkImage image) {
  411. return AllocateAndBindMemory(physical_device, device, image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  412. }
  413. inline VkDeviceMemory AllocateAndBindScanoutMemory(VkPhysicalDevice physical_device,
  414. VkDevice device, VkImage image) {
  415. return AllocateAndBindMemory(physical_device, device, image, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
  416. }
  417. VkImageView CreateVkImageView(VkDevice device, VkImage image, VkFormat format,
  418. VkImageAspectFlags aspect) {
  419. VkImageViewCreateInfo create_info = {};
  420. create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  421. create_info.image = image;
  422. create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
  423. create_info.format = format;
  424. VkComponentMapping component_mapping = {};
  425. component_mapping.r = VK_COMPONENT_SWIZZLE_IDENTITY;
  426. component_mapping.b = VK_COMPONENT_SWIZZLE_IDENTITY;
  427. component_mapping.g = VK_COMPONENT_SWIZZLE_IDENTITY;
  428. component_mapping.a = VK_COMPONENT_SWIZZLE_IDENTITY;
  429. create_info.components = component_mapping;
  430. VkImageSubresourceRange subresource_range = {};
  431. subresource_range.aspectMask = aspect;
  432. subresource_range.baseMipLevel = 0;
  433. subresource_range.levelCount = 1;
  434. subresource_range.baseArrayLayer = 0;
  435. subresource_range.layerCount = 1;
  436. create_info.subresourceRange = subresource_range;
  437. VkImageView image_view;
  438. VkResult result = vkCreateImageView(device, &create_info, nullptr, &image_view);
  439. if (result != VK_SUCCESS) {
  440. ERROR("Unable to create VkImageView: " << result);
  441. }
  442. return image_view;
  443. }
  444. VkImageView CreateRenderVkImageView(VkDevice device, VkImage image) {
  445. return CreateVkImageView(device, image, kVulkanFormat, VK_IMAGE_ASPECT_COLOR_BIT);
  446. }
  447. VkImageView CreateDepthVkImageView(VkDevice device, VkImage image) {
  448. return CreateVkImageView(device, image, kVulkanDepthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
  449. }
  450. VkFramebuffer CreateVkFramebuffer(VkDevice device, VkRenderPass render_pass,
  451. VkImageView render_image_view, VkImageView depth_image_view) {
  452. std::array<VkImageView, 2> attachments = { render_image_view, depth_image_view };
  453. VkFramebufferCreateInfo create_info = {};
  454. create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
  455. create_info.renderPass = render_pass;
  456. create_info.attachmentCount = attachments.size();
  457. create_info.pAttachments = attachments.data();
  458. create_info.width = kWidth;
  459. create_info.height = kHeight;
  460. create_info.layers = 1;
  461. VkFramebuffer framebuffer;
  462. VkResult result = vkCreateFramebuffer(device, &create_info, nullptr, &framebuffer);
  463. if (result != VK_SUCCESS) {
  464. ERROR("Unable to create VkFramebuffer: " << result);
  465. }
  466. return framebuffer;
  467. }
  468. void BeginQuery(VkCommandBuffer command_buffer, VkQueryPool query_pool) {
  469. vkCmdResetQueryPool(command_buffer, query_pool, 0, 1);
  470. vkCmdBeginQuery(command_buffer, query_pool, 0, 0);
  471. }
  472. void EndQuery(VkCommandBuffer command_buffer, VkQueryPool query_pool) {
  473. vkCmdEndQuery(command_buffer, query_pool, 0);
  474. }
  475. void BeginCommandBuffer(VkCommandBuffer command_buffer) {
  476. VkCommandBufferBeginInfo command_buffer_begin_info = {};
  477. command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  478. command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  479. VkResult result = vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);
  480. if (result != VK_SUCCESS) {
  481. ERROR("Unable to begin command buffer recording: " << result);
  482. }
  483. }
  484. void EndCommandBufferAndSubmit(VkCommandBuffer command_buffer, VkQueue queue) {
  485. VkResult result = vkEndCommandBuffer(command_buffer);
  486. if (result != VK_SUCCESS) {
  487. ERROR("Unable to end command buffer recording: " << result);
  488. }
  489. VkSubmitInfo submit_info = {};
  490. submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  491. submit_info.commandBufferCount = 1;
  492. submit_info.pCommandBuffers = &command_buffer;
  493. result = vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
  494. if (result != VK_SUCCESS) {
  495. ERROR("Error in submitting command buffer to queue: " << result);
  496. }
  497. }
  498. void WaitForIdle(VkQueue queue) {
  499. // In a real application, we should use real synchronization primitives to figure out when the
  500. // command buffers have been executed. Waiting on an idle queue is simple, but it can cause
  501. // deadlock if we continue to submit to the queue while we wait for idle.
  502. VkResult result = vkQueueWaitIdle(queue);
  503. if (result != VK_SUCCESS) {
  504. ERROR("Error in waiting for graphics queue to reach idle state: " << result);
  505. }
  506. }
  507. void Draw(VkDevice device, VkQueue queue, VkRenderPass render_pass, VkPipeline pipeline,
  508. VkFramebuffer framebuffer, VkCommandBuffer command_buffer, VkQueryPool query_pool) {
  509. BeginCommandBuffer(command_buffer);
  510. BeginQuery(command_buffer, query_pool);
  511. VkRenderPassBeginInfo render_pass_begin_info = {};
  512. render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  513. render_pass_begin_info.renderPass = render_pass;
  514. render_pass_begin_info.framebuffer = framebuffer;
  515. VkRect2D render_area = {};
  516. render_area.offset = { 0, 0 };
  517. render_area.extent = { kWidth, kHeight };
  518. render_pass_begin_info.renderArea = render_area;
  519. std::array<VkClearValue, 2> clear_values = {};
  520. clear_values[0].color.float32[0] = 0.0f;
  521. clear_values[0].color.float32[1] = 0.0f;
  522. clear_values[0].color.float32[2] = 1.0f;
  523. clear_values[0].color.float32[3] = 1.0f;
  524. clear_values[1].depthStencil.depth = 1.0f;
  525. clear_values[1].depthStencil.stencil = 0.0f;
  526. render_pass_begin_info.clearValueCount = clear_values.size();
  527. render_pass_begin_info.pClearValues = clear_values.data();
  528. vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
  529. vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  530. vkCmdDraw(command_buffer, 6, 1, 0, 0);
  531. vkCmdEndRenderPass(command_buffer);
  532. EndQuery(command_buffer, query_pool);
  533. }
  534. void BlitToScanoutImage(VkQueue queue, VkCommandBuffer command_buffer, VkImage source_image,
  535. VkImage dest_image) {
  536. // We need to make sure the writes of the render pass have executed before actually scanning out
  537. // the rendered image. Also, we need to transition the layout of the scanout image to
  538. // VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
  539. VkImageMemoryBarrier image_memory_barrier = {};
  540. image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
  541. image_memory_barrier.pNext = nullptr;
  542. image_memory_barrier.srcAccessMask = 0;
  543. image_memory_barrier.dstAccessMask = 0;
  544. image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  545. image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  546. image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  547. image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  548. image_memory_barrier.image = dest_image;
  549. VkImageSubresourceRange subresource_range = {};
  550. subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  551. subresource_range.baseMipLevel = 0;
  552. subresource_range.levelCount = 1;
  553. subresource_range.baseArrayLayer = 0;
  554. subresource_range.layerCount = 1;
  555. image_memory_barrier.subresourceRange = subresource_range;
  556. vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
  557. VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
  558. VkOffset3D blit_start = {};
  559. blit_start.x = 0;
  560. blit_start.y = 0;
  561. blit_start.z = 0;
  562. VkOffset3D blit_end = {};
  563. blit_end.x = kWidth;
  564. blit_end.y = kHeight;
  565. blit_end.z = 1;
  566. VkImageSubresourceLayers subresource_layers = {};
  567. subresource_layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  568. subresource_layers.mipLevel = 0;
  569. subresource_layers.baseArrayLayer = 0;
  570. subresource_layers.layerCount = 1;
  571. VkImageBlit image_blit = {};
  572. image_blit.srcSubresource = subresource_layers;
  573. image_blit.srcOffsets[0] = blit_start;
  574. image_blit.srcOffsets[1] = blit_end;
  575. image_blit.dstSubresource = subresource_layers;
  576. image_blit.dstOffsets[0] = blit_start;
  577. image_blit.dstOffsets[1] = blit_end;
  578. // TODO(brkho): Support multi-planar formats.
  579. vkCmdBlitImage(command_buffer, source_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dest_image,
  580. VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_blit, VK_FILTER_NEAREST);
  581. EndCommandBufferAndSubmit(command_buffer, queue);
  582. }
  583. uint8_t* MapVkDeviceMemory(VkDevice device, VkDeviceMemory image_memory) {
  584. void* mapped_memory = nullptr;
  585. VkResult result = vkMapMemory(device, image_memory, 0, kWidth * kHeight * 4, 0, &mapped_memory);
  586. if (result != VK_SUCCESS) {
  587. ERROR("Unable to map device memory: " << result);
  588. }
  589. return static_cast<uint8_t*>(mapped_memory);
  590. }
  591. uint32_t GetQueryPoolResults(VkDevice device, VkQueryPool query_pool) {
  592. uint32_t passed_fragments = 0;
  593. VkResult result = vkGetQueryPoolResults(device, query_pool, 0, 1, sizeof(passed_fragments),
  594. &passed_fragments, sizeof(uint32_t), VK_QUERY_RESULT_WAIT_BIT);
  595. // TODO(brkho): Currently, we query for results with the VK_QUERY_RESULT_WAIT_BIT flag set which
  596. // blocks execution until the results are ready. We should instead poll and check that result
  597. // isn't VK_NOT_READY.
  598. if (result != VK_SUCCESS) {
  599. ERROR("Unable to get query pool results: " << result);
  600. }
  601. return passed_fragments;
  602. }
  603. void WriteImage(uint8_t* pixels) {
  604. FILE *f = fopen("occlusion.png", "wb");
  605. png_image image_info = {};
  606. image_info.version = PNG_IMAGE_VERSION;
  607. image_info.width = kWidth;
  608. image_info.height = kHeight;
  609. image_info.format = PNG_FORMAT_RGBA;
  610. if (png_image_write_to_stdio(&image_info, f, 0, pixels, kWidth * 4, nullptr) == 0) {
  611. ERROR("Error writing PNG: " << image_info.message);
  612. }
  613. fclose(f);
  614. }
  615. uint32_t GetShadedFragmentsCountManual(uint8_t* pixels) {
  616. uint32_t count = 0;
  617. for (size_t i = 0; i < kHeight * kWidth * 4; i += 4) {
  618. uint8_t r = pixels[i];
  619. uint8_t g = pixels[i + 1];
  620. uint8_t b = pixels[i + 2];
  621. uint8_t a = pixels[i + 3];
  622. if (r == 255 && g == 0 && b == 0 && a == 255) {
  623. count++;
  624. }
  625. }
  626. return count;
  627. }
  628. int main() {
  629. VkInstance instance = CreateVkInstance();
  630. VkPhysicalDevice physical_device = ChooseVkPhysicalDevice(instance);
  631. uint32_t device_queue_family_index = ChooseDeviceQueueFamilyIndex(physical_device);
  632. VkDevice device = CreateVkDevice(physical_device, device_queue_family_index);
  633. VkQueue queue = GetVkQueue(device, device_queue_family_index);
  634. VkCommandPool command_pool = CreateVkCommandPool(device, device_queue_family_index);
  635. VkCommandBuffer command_buffer = CreateVkCommandBuffer(device, command_pool);
  636. VkQueryPool query_pool = CreateVkQueryPool(device);
  637. VkRenderPass render_pass = CreateVkRenderPass(device);
  638. VkPipeline pipeline = CreateVkPipeline(device, render_pass);
  639. VkImage render_image = CreateRenderVkImage(device);
  640. AllocateAndBindRenderMemory(physical_device, device, render_image);
  641. VkImageView render_image_view = CreateRenderVkImageView(device, render_image);
  642. VkImage depth_image = CreateDepthVkImage(device);
  643. AllocateAndBindDepthMemory(physical_device, device, depth_image);
  644. VkImageView depth_image_view = CreateDepthVkImageView(device, depth_image);
  645. VkFramebuffer framebuffer = CreateVkFramebuffer(device, render_pass, render_image_view,
  646. depth_image_view);
  647. VkImage scanout_image = CreateScanoutVkImage(device);
  648. VkDeviceMemory scanout_image_memory =
  649. AllocateAndBindScanoutMemory(physical_device, device, scanout_image);
  650. Draw(device, queue, render_pass, pipeline, framebuffer, command_buffer, query_pool);
  651. // Since the render target is created with VK_IMAGE_TILING_OPTIMAL, we need to copy it to a linear
  652. // format before scanning out.
  653. BlitToScanoutImage(queue, command_buffer, render_image, scanout_image);
  654. WaitForIdle(queue);
  655. uint8_t* pixels = MapVkDeviceMemory(device, scanout_image_memory);
  656. WriteImage(pixels);
  657. uint32_t shaded_fragments_count_query = GetQueryPoolResults(device, query_pool);
  658. uint32_t shaded_fragments_count_manual = GetShadedFragmentsCountManual(pixels);
  659. std::cout << "[Occlusion query] shaded fragments: " << shaded_fragments_count_query << std::endl;
  660. std::cout << "[Manual count] shaded fragments: " << shaded_fragments_count_manual << std::endl;
  661. return EXIT_SUCCESS;
  662. }