mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2025-10-30 07:01:10 +00:00
base vulkan classes
This commit is contained in:
parent
bf2b683264
commit
fe5a8520e5
5 changed files with 247 additions and 0 deletions
60
include/device.hpp
Normal file
60
include/device.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
#ifndef DEVICE_HPP
|
||||||
|
#define DEVICE_HPP
|
||||||
|
|
||||||
|
#include "instance.hpp"
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// C++ wrapper class for a Vulkan device.
|
||||||
|
///
|
||||||
|
/// This class manages the lifetime of a Vulkan device.
|
||||||
|
///
|
||||||
|
class Device {
|
||||||
|
public:
|
||||||
|
///
|
||||||
|
/// Create the device.
|
||||||
|
///
|
||||||
|
/// @param instance Vulkan instance
|
||||||
|
///
|
||||||
|
/// @throws std::invalid_argument if the instance is invalid.
|
||||||
|
/// @throws ls::vulkan_error if object creation fails.
|
||||||
|
///
|
||||||
|
Device(const Vulkan::Instance& instance);
|
||||||
|
|
||||||
|
/// Get the Vulkan handle.
|
||||||
|
[[nodiscard]] auto handle() const { return *this->device; }
|
||||||
|
/// Get the physical device associated with this logical device.
|
||||||
|
[[nodiscard]] VkPhysicalDevice getPhysicalDevice() const { return this->physicalDevice; }
|
||||||
|
/// Get the compute queue family index.
|
||||||
|
[[nodiscard]] uint32_t getComputeFamilyIdx() const { return this->computeFamilyIdx; }
|
||||||
|
/// Get the compute queue.
|
||||||
|
[[nodiscard]] VkQueue getComputeQueue() const { return this->computeQueue; }
|
||||||
|
|
||||||
|
/// Check whether the object is valid.
|
||||||
|
[[nodiscard]] bool isValid() const { return static_cast<bool>(this->device); }
|
||||||
|
/// if (obj) operator. Checks if the object is valid.
|
||||||
|
explicit operator bool() const { return this->isValid(); }
|
||||||
|
|
||||||
|
// Trivially copyable, moveable and destructible
|
||||||
|
Device(const Device&) noexcept = default;
|
||||||
|
Device& operator=(const Device&) noexcept = default;
|
||||||
|
Device(Device&&) noexcept = default;
|
||||||
|
Device& operator=(Device&&) noexcept = default;
|
||||||
|
~Device() = default;
|
||||||
|
private:
|
||||||
|
std::shared_ptr<VkDevice> device;
|
||||||
|
VkPhysicalDevice physicalDevice{};
|
||||||
|
|
||||||
|
uint32_t computeFamilyIdx{0};
|
||||||
|
|
||||||
|
VkQueue computeQueue{};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICE_HPP
|
||||||
44
include/instance.hpp
Normal file
44
include/instance.hpp
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef INSTANCE_HPP
|
||||||
|
#define INSTANCE_HPP
|
||||||
|
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// C++ wrapper class for a Vulkan instance.
|
||||||
|
///
|
||||||
|
/// This class manages the lifetime of a Vulkan instance.
|
||||||
|
///
|
||||||
|
class Instance {
|
||||||
|
public:
|
||||||
|
///
|
||||||
|
/// Create the instance.
|
||||||
|
///
|
||||||
|
/// @throws ls::vulkan_error if object creation fails.
|
||||||
|
///
|
||||||
|
Instance();
|
||||||
|
|
||||||
|
/// Get the Vulkan handle.
|
||||||
|
[[nodiscard]] auto handle() const { return this->instance ? *this->instance : VK_NULL_HANDLE; }
|
||||||
|
|
||||||
|
/// Check whether the object is valid.
|
||||||
|
[[nodiscard]] bool isValid() const { return this->handle() != VK_NULL_HANDLE; }
|
||||||
|
/// if (obj) operator. Checks if the object is valid.
|
||||||
|
explicit operator bool() const { return this->isValid(); }
|
||||||
|
|
||||||
|
/// Trivially copyable, moveable and destructible
|
||||||
|
Instance(const Instance&) noexcept = default;
|
||||||
|
Instance& operator=(const Instance&) noexcept = default;
|
||||||
|
Instance(Instance&&) noexcept = default;
|
||||||
|
Instance& operator=(Instance&&) noexcept = default;
|
||||||
|
~Instance() = default;
|
||||||
|
private:
|
||||||
|
std::shared_ptr<VkInstance> instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // INSTANCE_HPP
|
||||||
85
src/device.cpp
Normal file
85
src/device.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
#include "device.hpp"
|
||||||
|
#include "utils/exceptions.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace Vulkan;
|
||||||
|
|
||||||
|
Device::Device(const Instance& instance) {
|
||||||
|
if (!instance)
|
||||||
|
throw std::invalid_argument("Invalid Vulkan instance");
|
||||||
|
|
||||||
|
// get all physical devices
|
||||||
|
uint32_t deviceCount{};
|
||||||
|
auto res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, nullptr);
|
||||||
|
if (res != VK_SUCCESS || deviceCount == 0)
|
||||||
|
throw ls::vulkan_error(res, "Failed to enumerate physical devices");
|
||||||
|
|
||||||
|
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||||
|
res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, devices.data());
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
throw ls::vulkan_error(res, "Failed to get physical devices");
|
||||||
|
|
||||||
|
// find first discrete GPU
|
||||||
|
std::optional<VkPhysicalDevice> physicalDevice;
|
||||||
|
for (const auto& device : devices) {
|
||||||
|
VkPhysicalDeviceProperties properties;
|
||||||
|
vkGetPhysicalDeviceProperties(device, &properties);
|
||||||
|
|
||||||
|
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
|
||||||
|
physicalDevice = device;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!physicalDevice)
|
||||||
|
throw ls::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "No discrete GPU found");
|
||||||
|
|
||||||
|
// find queue family indices
|
||||||
|
uint32_t familyCount{};
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &familyCount, nullptr);
|
||||||
|
|
||||||
|
std::vector<VkQueueFamilyProperties> queueFamilies(familyCount);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &familyCount, queueFamilies.data());
|
||||||
|
|
||||||
|
std::optional<uint32_t> computeFamilyIdx;
|
||||||
|
for (uint32_t i = 0; i < familyCount; ++i) {
|
||||||
|
if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
|
||||||
|
computeFamilyIdx = i;
|
||||||
|
}
|
||||||
|
if (!computeFamilyIdx)
|
||||||
|
throw ls::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "No compute queue family found");
|
||||||
|
|
||||||
|
// create logical device
|
||||||
|
const float queuePriority{1.0F}; // highest priority
|
||||||
|
const VkDeviceQueueCreateInfo computeQueueDesc{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||||
|
.queueFamilyIndex = *computeFamilyIdx,
|
||||||
|
.queueCount = 1,
|
||||||
|
.pQueuePriorities = &queuePriority
|
||||||
|
};
|
||||||
|
const VkDeviceCreateInfo deviceCreateInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||||
|
.queueCreateInfoCount = 1,
|
||||||
|
.pQueueCreateInfos = &computeQueueDesc
|
||||||
|
};
|
||||||
|
VkDevice deviceHandle{};
|
||||||
|
res = vkCreateDevice(*physicalDevice, &deviceCreateInfo, nullptr, &deviceHandle);
|
||||||
|
if (res != VK_SUCCESS | deviceHandle == VK_NULL_HANDLE)
|
||||||
|
throw ls::vulkan_error(res, "Failed to create logical device");
|
||||||
|
|
||||||
|
// get compute queue
|
||||||
|
VkQueue queueHandle{};
|
||||||
|
vkGetDeviceQueue(deviceHandle, *computeFamilyIdx, 0, &queueHandle);
|
||||||
|
|
||||||
|
// store in shared ptr
|
||||||
|
this->computeQueue = queueHandle;
|
||||||
|
this->computeFamilyIdx = *computeFamilyIdx;
|
||||||
|
this->physicalDevice = *physicalDevice;
|
||||||
|
this->device = std::shared_ptr<VkDevice>(
|
||||||
|
new VkDevice(deviceHandle),
|
||||||
|
[](VkDevice* device) {
|
||||||
|
vkDestroyDevice(*device, nullptr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
46
src/instance.cpp
Normal file
46
src/instance.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#include "instance.hpp"
|
||||||
|
#include "utils/exceptions.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace Vulkan;
|
||||||
|
|
||||||
|
const std::vector<const char*> requiredExtensions = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<const char*> requiredLayers = {
|
||||||
|
"VK_LAYER_KHRONOS_validation"
|
||||||
|
};
|
||||||
|
|
||||||
|
Instance::Instance() {
|
||||||
|
// create Vulkan instance
|
||||||
|
const VkApplicationInfo appInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||||
|
.pApplicationName = "lsfg-vk-base",
|
||||||
|
.applicationVersion = VK_MAKE_VERSION(0, 0, 1),
|
||||||
|
.pEngineName = "lsfg-vk-base",
|
||||||
|
.engineVersion = VK_MAKE_VERSION(0, 0, 1),
|
||||||
|
.apiVersion = VK_API_VERSION_1_4
|
||||||
|
};
|
||||||
|
const VkInstanceCreateInfo createInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||||
|
.pApplicationInfo = &appInfo,
|
||||||
|
.enabledLayerCount = static_cast<uint32_t>(requiredLayers.size()),
|
||||||
|
.ppEnabledLayerNames = requiredLayers.data(),
|
||||||
|
.enabledExtensionCount = static_cast<uint32_t>(requiredExtensions.size()),
|
||||||
|
.ppEnabledExtensionNames = requiredExtensions.data()
|
||||||
|
};
|
||||||
|
VkInstance instanceHandle{};
|
||||||
|
auto res = vkCreateInstance(&createInfo, nullptr, &instanceHandle);
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
throw ls::vulkan_error(res, "Failed to create Vulkan instance");
|
||||||
|
|
||||||
|
// store in shared ptr
|
||||||
|
this->instance = std::shared_ptr<VkInstance>(
|
||||||
|
new VkInstance(instanceHandle),
|
||||||
|
[](VkInstance* instance) {
|
||||||
|
vkDestroyInstance(*instance, nullptr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
12
src/main.cpp
Normal file
12
src/main.cpp
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "device.hpp"
|
||||||
|
#include "instance.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
const Vulkan::Instance instance;
|
||||||
|
const Vulkan::Device device(instance);
|
||||||
|
|
||||||
|
std::cerr << "Application finished" << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue