Vulkan device creation
This commit is contained in:
@ -76,11 +76,22 @@ class GpuImpl : public Gpu
|
|||||||
|
|
||||||
VkInstance m_instance;
|
VkInstance m_instance;
|
||||||
VkSurfaceKHR m_surface;
|
VkSurfaceKHR m_surface;
|
||||||
|
uint32_t m_queue_family_index;
|
||||||
|
VkDevice m_device;
|
||||||
|
VkQueue m_queue;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GpuImpl(VkInstance instance, VkSurfaceKHR surface)
|
GpuImpl(
|
||||||
|
VkInstance instance,
|
||||||
|
VkSurfaceKHR surface,
|
||||||
|
uint32_t queue_family_index,
|
||||||
|
VkDevice device,
|
||||||
|
VkQueue queue)
|
||||||
: m_instance{instance}
|
: m_instance{instance}
|
||||||
, m_surface{surface}
|
, m_surface{surface}
|
||||||
|
, m_queue_family_index{queue_family_index}
|
||||||
|
, m_device{device}
|
||||||
|
, m_queue{queue}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ASL_DELETE_COPY_MOVE(GpuImpl);
|
ASL_DELETE_COPY_MOVE(GpuImpl);
|
||||||
@ -94,11 +105,16 @@ public:
|
|||||||
{
|
{
|
||||||
ASL_ASSERT(!m_destroyed);
|
ASL_ASSERT(!m_destroyed);
|
||||||
m_destroyed = true;
|
m_destroyed = true;
|
||||||
|
vkDestroyDevice(m_device, VK_ALLOCATOR);
|
||||||
vkDestroySurfaceKHR(m_instance, m_surface, VK_ALLOCATOR);
|
vkDestroySurfaceKHR(m_instance, m_surface, VK_ALLOCATOR);
|
||||||
vkDestroyInstance(m_instance, VK_ALLOCATOR);
|
vkDestroyInstance(m_instance, VK_ALLOCATOR);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint32_t kTargetVersionMajor = 1;
|
||||||
|
static uint32_t kTargetVersionMinor = 3;
|
||||||
|
static uint32_t kTargetVersion = VK_MAKE_API_VERSION(0, kTargetVersionMajor, kTargetVersionMinor, 0); // NOLINT
|
||||||
|
|
||||||
static asl::status_or<VkInstance> create_instance()
|
static asl::status_or<VkInstance> create_instance()
|
||||||
{
|
{
|
||||||
asl::buffer<const char*> instance_extensions;
|
asl::buffer<const char*> instance_extensions;
|
||||||
@ -127,7 +143,7 @@ static asl::status_or<VkInstance> create_instance()
|
|||||||
uint32_t vk_major = VK_API_VERSION_MAJOR(version); // NOLINT
|
uint32_t vk_major = VK_API_VERSION_MAJOR(version); // NOLINT
|
||||||
uint32_t vk_minor = VK_API_VERSION_MINOR(version); // NOLINT
|
uint32_t vk_minor = VK_API_VERSION_MINOR(version); // NOLINT
|
||||||
|
|
||||||
if (vk_major != 1 || vk_minor < 3)
|
if (vk_major != kTargetVersionMajor || vk_minor < kTargetVersionMinor)
|
||||||
{
|
{
|
||||||
return asl::runtime_error("Incompatible Vulkan version: {}.{}", vk_major, vk_minor);
|
return asl::runtime_error("Incompatible Vulkan version: {}.{}", vk_major, vk_minor);
|
||||||
}
|
}
|
||||||
@ -139,7 +155,7 @@ static asl::status_or<VkInstance> create_instance()
|
|||||||
.applicationVersion = 0,
|
.applicationVersion = 0,
|
||||||
.pEngineName = "Custom",
|
.pEngineName = "Custom",
|
||||||
.engineVersion = 0,
|
.engineVersion = 0,
|
||||||
.apiVersion = VK_MAKE_API_VERSION(0, 1, 3, 0), // NOLINT
|
.apiVersion = kTargetVersion,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkInstanceCreateInfo instance_create_info{
|
VkInstanceCreateInfo instance_create_info{
|
||||||
@ -163,6 +179,8 @@ static asl::status_or<VkInstance> create_instance()
|
|||||||
status = vulkan_loader::load_instance(vkGetInstanceProcAddr, instance);
|
status = vulkan_loader::load_instance(vkGetInstanceProcAddr, instance);
|
||||||
ASL_TRY(status);
|
ASL_TRY(status);
|
||||||
|
|
||||||
|
ASL_LOG_INFO("Vulkan instance created");
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +195,105 @@ static asl::status_or<VkSurfaceKHR> create_surface(SDL_Window* window, VkInstanc
|
|||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PhysicalDeviceInfo
|
||||||
|
{
|
||||||
|
VkPhysicalDevice physical_device;
|
||||||
|
uint32_t queue_family_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
static asl::status_or<PhysicalDeviceInfo> find_physical_device(VkInstance instance)
|
||||||
|
{
|
||||||
|
uint32_t count{};
|
||||||
|
asl::buffer<VkPhysicalDevice> physical_devices;
|
||||||
|
asl::buffer<VkQueueFamilyProperties> queue_family_prps;
|
||||||
|
|
||||||
|
vkEnumeratePhysicalDevices(instance, &count, nullptr);
|
||||||
|
physical_devices.resize_zero(count);
|
||||||
|
VkResult res = vkEnumeratePhysicalDevices(instance, &count, physical_devices.data());
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
return asl::runtime_error("Couldn't enumerate Vulkan physical devices: {}", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto* physical_device: physical_devices)
|
||||||
|
{
|
||||||
|
VkPhysicalDeviceProperties prps;
|
||||||
|
vkGetPhysicalDeviceProperties(physical_device, &prps);
|
||||||
|
|
||||||
|
asl::string_view name{prps.deviceName, asl::strlen(prps.deviceName)};
|
||||||
|
|
||||||
|
if (prps.apiVersion < kTargetVersion)
|
||||||
|
{
|
||||||
|
ASL_LOG_INFO("Device {}: invalid supported Vulkan API version", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t queue_family_count{};
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr);
|
||||||
|
queue_family_prps.resize_zero(queue_family_count);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_family_prps.data());
|
||||||
|
|
||||||
|
static constexpr VkQueueFlags kWantedQueueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
|
||||||
|
|
||||||
|
for (uint32_t queue_family_index = 0; queue_family_index < queue_family_count; ++queue_family_index)
|
||||||
|
{
|
||||||
|
if ((queue_family_prps[queue_family_index].queueFlags & kWantedQueueFlags) != kWantedQueueFlags) { continue; }
|
||||||
|
if (!SDL_Vulkan_GetPresentationSupport(instance, physical_device, queue_family_index)) { continue; }
|
||||||
|
|
||||||
|
ASL_LOG_INFO("Chosing device \"{}\" with queue family {}", name, queue_family_index);
|
||||||
|
return PhysicalDeviceInfo{ physical_device, queue_family_index };
|
||||||
|
}
|
||||||
|
|
||||||
|
ASL_LOG_INFO("Device {}: no valid queue found", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return asl::runtime_error("Couldn't find a valid Vulkan physical device");
|
||||||
|
}
|
||||||
|
|
||||||
|
static asl::status_or<VkDevice> create_device(VkPhysicalDevice physical_device, uint32_t queue_family_index)
|
||||||
|
{
|
||||||
|
asl::buffer<const char*> device_extensions;
|
||||||
|
device_extensions.push(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
|
|
||||||
|
const float queue_priority = 1.0F;
|
||||||
|
|
||||||
|
VkDeviceQueueCreateInfo queue_create_info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.queueFamilyIndex = queue_family_index,
|
||||||
|
.queueCount = 1,
|
||||||
|
.pQueuePriorities = &queue_priority,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDeviceCreateInfo create_info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.queueCreateInfoCount = 1,
|
||||||
|
.pQueueCreateInfos = &queue_create_info,
|
||||||
|
.enabledLayerCount = 0,
|
||||||
|
.ppEnabledLayerNames = nullptr,
|
||||||
|
.enabledExtensionCount = static_cast<uint32_t>(device_extensions.size()),
|
||||||
|
.ppEnabledExtensionNames = device_extensions.data(),
|
||||||
|
.pEnabledFeatures = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDevice device{};
|
||||||
|
VkResult res = vkCreateDevice(physical_device, &create_info, VK_ALLOCATOR, &device);
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
return asl::runtime_error("Couldn't create Vulkan device: {}", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASL_LOG_INFO("Vulkan device created");
|
||||||
|
|
||||||
|
auto status = vulkan_loader::load_device(device);
|
||||||
|
ASL_TRY(status);
|
||||||
|
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
asl::status_or<asl::box<Gpu>> init(SDL_Window* window)
|
asl::status_or<asl::box<Gpu>> init(SDL_Window* window)
|
||||||
{
|
{
|
||||||
auto instance = create_instance();
|
auto instance = create_instance();
|
||||||
@ -185,10 +302,23 @@ asl::status_or<asl::box<Gpu>> init(SDL_Window* window)
|
|||||||
auto surface = create_surface(window, instance.value());
|
auto surface = create_surface(window, instance.value());
|
||||||
ASL_TRY(surface);
|
ASL_TRY(surface);
|
||||||
|
|
||||||
// asl::buffer<const char*> device_extensions;
|
auto physical_device_info = find_physical_device(instance.value());
|
||||||
// device_extensions.push(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
ASL_TRY(physical_device_info);
|
||||||
|
|
||||||
return asl::make_box<GpuImpl>(instance.value(), surface.value());
|
auto device = create_device(
|
||||||
|
physical_device_info.value().physical_device,
|
||||||
|
physical_device_info.value().queue_family_index);
|
||||||
|
ASL_TRY(device);
|
||||||
|
|
||||||
|
VkQueue queue{};
|
||||||
|
vkGetDeviceQueue(device.value(), physical_device_info.value().queue_family_index, 0, &queue);
|
||||||
|
|
||||||
|
return asl::make_box<GpuImpl>(
|
||||||
|
instance.value(),
|
||||||
|
surface.value(),
|
||||||
|
physical_device_info.value().queue_family_index,
|
||||||
|
device.value(),
|
||||||
|
queue);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#define FN(NAME) extern PFN_##NAME NAME;
|
#define FN(NAME) extern PFN_##NAME NAME;
|
||||||
VULKAN_GLOBAL_FNS
|
VULKAN_GLOBAL_FNS
|
||||||
VULKAN_INSTANCE_FNS
|
VULKAN_INSTANCE_FNS
|
||||||
|
VULKAN_DEVICE_FNS
|
||||||
#undef FN
|
#undef FN
|
||||||
|
|
||||||
namespace vulkan_loader
|
namespace vulkan_loader
|
||||||
@ -20,6 +21,7 @@ namespace vulkan_loader
|
|||||||
|
|
||||||
asl::status load_global(PFN_vkGetInstanceProcAddr load_fn);
|
asl::status load_global(PFN_vkGetInstanceProcAddr load_fn);
|
||||||
asl::status load_instance(PFN_vkGetInstanceProcAddr load_fn, VkInstance instance);
|
asl::status load_instance(PFN_vkGetInstanceProcAddr load_fn, VkInstance instance);
|
||||||
|
asl::status load_device(VkDevice device);
|
||||||
|
|
||||||
} // namespace vulkan_loader
|
} // namespace vulkan_loader
|
||||||
|
|
||||||
|
@ -4,4 +4,13 @@
|
|||||||
|
|
||||||
#define VULKAN_INSTANCE_FNS \
|
#define VULKAN_INSTANCE_FNS \
|
||||||
FN(vkDestroyInstance) \
|
FN(vkDestroyInstance) \
|
||||||
FN(vkDestroySurfaceKHR)
|
FN(vkDestroySurfaceKHR) \
|
||||||
|
FN(vkEnumeratePhysicalDevices) \
|
||||||
|
FN(vkGetPhysicalDeviceProperties) \
|
||||||
|
FN(vkGetPhysicalDeviceQueueFamilyProperties) \
|
||||||
|
FN(vkCreateDevice) \
|
||||||
|
FN(vkGetDeviceProcAddr)
|
||||||
|
|
||||||
|
#define VULKAN_DEVICE_FNS \
|
||||||
|
FN(vkDestroyDevice) \
|
||||||
|
FN(vkGetDeviceQueue)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#define FN(NAME) PFN_##NAME NAME;
|
#define FN(NAME) PFN_##NAME NAME;
|
||||||
VULKAN_GLOBAL_FNS
|
VULKAN_GLOBAL_FNS
|
||||||
VULKAN_INSTANCE_FNS
|
VULKAN_INSTANCE_FNS
|
||||||
|
VULKAN_DEVICE_FNS
|
||||||
#undef FN
|
#undef FN
|
||||||
|
|
||||||
asl::status vulkan_loader::load_global(PFN_vkGetInstanceProcAddr load_fn)
|
asl::status vulkan_loader::load_global(PFN_vkGetInstanceProcAddr load_fn)
|
||||||
@ -43,3 +44,20 @@ VULKAN_INSTANCE_FNS
|
|||||||
return has_errors ? asl::runtime_error("Couldn't load Vulkan instance functions") : asl::ok();
|
return has_errors ? asl::runtime_error("Couldn't load Vulkan instance functions") : asl::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asl::status vulkan_loader::load_device(VkDevice device)
|
||||||
|
{
|
||||||
|
bool has_errors = false;
|
||||||
|
|
||||||
|
#define FN(NAME) \
|
||||||
|
NAME = asl::bit_cast<PFN_##NAME>(vkGetDeviceProcAddr(device, #NAME)); \
|
||||||
|
if (NAME == nullptr) \
|
||||||
|
{ \
|
||||||
|
ASL_ASSERT(NAME != nullptr); \
|
||||||
|
has_errors = true; \
|
||||||
|
}
|
||||||
|
VULKAN_DEVICE_FNS
|
||||||
|
#undef FN
|
||||||
|
|
||||||
|
return has_errors ? asl::runtime_error("Couldn't load Vulkan device functions") : asl::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user