1#pragma once
2
3#ifdef _WIN64
4#define VK_USE_PLATFORM_WIN32_KHR 1
5#endif
6
7#include "taichi/rhi/vulkan/vulkan_common.h"
8
9#include <taichi/rhi/device.h>
10#include <taichi/program/kernel_profiler.h>
11
12#include <memory>
13#include <optional>
14#include <vector>
15#include <string>
16#include <functional>
17
18namespace taichi::lang {
19namespace vulkan {
20
21class VulkanDevice;
22
23struct VulkanQueueFamilyIndices {
24 std::optional<uint32_t> compute_family;
25 std::optional<uint32_t> graphics_family;
26 std::optional<uint32_t> present_family;
27 // TODO: While it is the case that all COMPUTE/GRAPHICS queue also support
28 // TRANSFER by default, maye there are some performance benefits to find a
29 // TRANSFER-dedicated queue family.
30 // https://vulkan-tutorial.com/Vertex_buffers/Staging_buffer#page_Transfer-queue
31
32 bool is_complete() const {
33 return compute_family.has_value();
34 }
35
36 bool is_complete_for_ui() {
37 return graphics_family.has_value() && present_family.has_value();
38 }
39};
40
41/**
42 * This class creates a VulkanDevice instance. The underlying Vk* resources are
43 * embedded directly inside the class.
44 */
45class TI_DLL_EXPORT VulkanDeviceCreator {
46 public:
47 struct Params {
48 // User-provided API version. If assigned, the users MUST list all
49 // their desired extensions in `additional_instance_extensions` and
50 // `additional_device_extensions`; no extension is enabled by default.
51 std::optional<uint32_t> api_version;
52 bool is_for_ui{false};
53 std::vector<std::string> additional_instance_extensions;
54 std::vector<std::string> additional_device_extensions;
55 // the VkSurfaceKHR needs to be created after creating the VkInstance, but
56 // before creating the VkPhysicalDevice thus, we allow the user to pass in a
57 // custom surface creator
58 std::function<VkSurfaceKHR(VkInstance)> surface_creator;
59 bool enable_validation_layer{false};
60 };
61
62 explicit VulkanDeviceCreator(const Params &params);
63 ~VulkanDeviceCreator();
64
65 const VulkanDevice *device() const {
66 return ti_device_.get();
67 }
68
69 VulkanDevice *device() {
70 return ti_device_.get();
71 }
72
73 VkSurfaceKHR get_surface() {
74 return surface_;
75 }
76
77 private:
78 void create_instance(uint32_t vk_api_version, bool manual_create);
79 void setup_debug_messenger();
80 void create_surface();
81 void pick_physical_device();
82 void create_logical_device(bool manual_create);
83
84 VkInstance instance_{VK_NULL_HANDLE};
85 VkDebugUtilsMessengerEXT debug_messenger_{VK_NULL_HANDLE};
86 VkPhysicalDevice physical_device_{VK_NULL_HANDLE};
87 VulkanQueueFamilyIndices queue_family_indices_;
88 VkDevice device_{VK_NULL_HANDLE};
89
90 VkQueue compute_queue_{VK_NULL_HANDLE};
91 VkQueue graphics_queue_{VK_NULL_HANDLE};
92
93 VkSurfaceKHR surface_{VK_NULL_HANDLE};
94
95 std::unique_ptr<VulkanDevice> ti_device_{nullptr};
96
97 Params params_;
98};
99
100} // namespace vulkan
101} // namespace taichi::lang
102