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.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

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. }