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.

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