Binary that renders a triangle using Vulkan and scans the resulting image to a PNG. To be used in developing Turnip.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

triangle.cc 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #include <png.h>
  2. #include <vulkan/vulkan.h>
  3. #include <iostream>
  4. #include <string>
  5. #include <vector>
  6. const uint32_t kWidth = 16;
  7. const uint32_t kHeight = 16;
  8. #define ERROR(message) \
  9. std::cerr << message << std::endl; \
  10. std::exit(EXIT_FAILURE)
  11. VkInstance CreateVkInstance() {
  12. VkApplicationInfo app_info = {};
  13. app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  14. app_info.apiVersion = VK_API_VERSION_1_1;
  15. VkInstanceCreateInfo create_info = {};
  16. create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  17. create_info.pApplicationInfo = &app_info;
  18. create_info.enabledExtensionCount = 0;
  19. create_info.ppEnabledExtensionNames = nullptr;
  20. create_info.enabledLayerCount = 0;
  21. create_info.ppEnabledLayerNames = nullptr;
  22. VkInstance instance;
  23. VkResult result = vkCreateInstance(&create_info, nullptr, &instance);
  24. if (result != VK_SUCCESS) {
  25. ERROR("Error creating VkInstance: " << result);
  26. }
  27. return instance;
  28. }
  29. VkPhysicalDevice ChooseVkPhysicalDevice(VkInstance instance) {
  30. uint32_t device_count = 0;
  31. VkResult result = vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
  32. if (result != VK_SUCCESS) {
  33. ERROR("Error enumerating VkPhysicalDevices: " << result);
  34. }
  35. if (device_count == 0) {
  36. ERROR("No available VkPhysicalDevices");
  37. }
  38. std::vector<VkPhysicalDevice> devices(device_count);
  39. result = vkEnumeratePhysicalDevices(instance, &device_count, devices.data());
  40. if (result != VK_SUCCESS) {
  41. ERROR("Error fetching VkPhysicalDevices: " << result);
  42. }
  43. std::cout << "Found " << device_count << " device(s):" << std::endl;
  44. VkPhysicalDevice chosen_device = VK_NULL_HANDLE;
  45. for (VkPhysicalDevice device : devices) {
  46. VkPhysicalDeviceProperties device_props;
  47. vkGetPhysicalDeviceProperties(device, &device_props);
  48. std::cout << "\t- " << device_props.deviceName << " [V: " <<
  49. VK_VERSION_MAJOR(device_props.apiVersion) << "." <<
  50. VK_VERSION_MINOR(device_props.apiVersion) << "." <<
  51. VK_VERSION_PATCH(device_props.apiVersion) << "]" << std::endl;
  52. // Currently, any device with Vulkan API version 1.1 is fine.
  53. if (chosen_device == VK_NULL_HANDLE && device_props.apiVersion >= VK_API_VERSION_1_1) {
  54. chosen_device = device;
  55. }
  56. }
  57. if (chosen_device == VK_NULL_HANDLE) {
  58. ERROR("Unable to find suitable VkPhysicalDevice");
  59. }
  60. return chosen_device;
  61. }
  62. uint32_t ChooseDeviceQueueFamilyIndex(VkPhysicalDevice physical_device) {
  63. uint32_t props_count;
  64. vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &props_count, nullptr);
  65. std::vector<VkQueueFamilyProperties> props(props_count);
  66. vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &props_count, props.data());
  67. // Simply choose the first graphics queue.
  68. for (size_t i = 0; i < props_count; i++) {
  69. const VkQueueFamilyProperties& prop = props[i];
  70. if ((prop.queueFlags & VK_QUEUE_GRAPHICS_BIT) && prop.queueCount > 0) {
  71. return i;
  72. }
  73. }
  74. ERROR("Unable to find suitable queue family");
  75. }
  76. VkDevice CreateVkDevice(VkPhysicalDevice physical_device, uint32_t device_queue_family_index) {
  77. VkDeviceQueueCreateInfo queue_create_info = {};
  78. queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  79. queue_create_info.queueFamilyIndex = device_queue_family_index;
  80. queue_create_info.queueCount = 1;
  81. float queue_priority = 1.0f;
  82. queue_create_info.pQueuePriorities = &queue_priority;
  83. VkDeviceCreateInfo device_create_info = {};
  84. device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  85. device_create_info.queueCreateInfoCount = 1;
  86. device_create_info.pQueueCreateInfos = &queue_create_info;
  87. // Let's not use any device extensions for now.
  88. device_create_info.enabledExtensionCount = 0;
  89. device_create_info.ppEnabledExtensionNames = nullptr;
  90. VkDevice device;
  91. VkResult result = vkCreateDevice(physical_device, &device_create_info, nullptr, &device);
  92. if (result != VK_SUCCESS) {
  93. ERROR("Unable to create logical device");
  94. }
  95. return device;
  96. }
  97. int main() {
  98. VkInstance instance = CreateVkInstance();
  99. VkPhysicalDevice physical_device = ChooseVkPhysicalDevice(instance);
  100. uint32_t device_queue_family_index = ChooseDeviceQueueFamilyIndex(physical_device);
  101. VkDevice device = CreateVkDevice(physical_device, device_queue_family_index);
  102. // Example code for exporting a PNG.
  103. FILE *f = fopen("triangle.png", "wb");
  104. std::vector<uint8_t> pixels(kWidth * kHeight * 4);
  105. for (size_t i = 0; i < kHeight; i++) {
  106. for (size_t j = 0; j < kWidth; j++) {
  107. uint32_t base_index = (i * kWidth * 4) + (j * 4);
  108. pixels[base_index] = 255;
  109. pixels[base_index + 1] = 255;
  110. pixels[base_index + 2] = 0;
  111. pixels[base_index + 3] = 255;
  112. }
  113. }
  114. png_image image_info = {};
  115. image_info.version = PNG_IMAGE_VERSION;
  116. image_info.width = kWidth;
  117. image_info.height = kHeight;
  118. image_info.format = PNG_FORMAT_RGBA;
  119. if (png_image_write_to_stdio(&image_info, f, 0, pixels.data(), kWidth * 4, nullptr) == 0) {
  120. ERROR("Error writing PNG: " << image_info.message);
  121. }
  122. fclose(f);
  123. return EXIT_SUCCESS;
  124. }