-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8cdbed4
commit c992901
Showing
3 changed files
with
208 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright (C) 2023 Albin Johansson (GNU General Public License v3.0) | ||
|
||
#pragma once | ||
|
||
#include <vulkan/vulkan.h> | ||
|
||
#include "tactile/base/container/expected.hpp" | ||
#include "tactile/base/container/smart_ptr.hpp" | ||
#include "tactile/base/prelude.hpp" | ||
#include "tactile/vulkan/api.hpp" | ||
|
||
struct SDL_Window; | ||
|
||
namespace tactile { | ||
|
||
/// \addtogroup Vulkan | ||
/// \{ | ||
|
||
/** | ||
* Wrapper around a \c VkInstance object. | ||
*/ | ||
class VulkanInstance final | ||
{ | ||
public: | ||
TACTILE_DELETE_COPY(VulkanInstance); | ||
|
||
/** | ||
* Creates a Vulkan instance. | ||
* | ||
* \details | ||
* In debug builds, the instance will use the \c VK_LAYER_KHRONOS_validation | ||
* layer for API usage validation. | ||
* | ||
* \param window The associated window handle. | ||
* | ||
* \return | ||
* A Vulkan instance if successful; an error code otherwise. | ||
*/ | ||
[[nodiscard]] | ||
static auto make(SDL_Window* window) -> Result<VulkanInstance>; | ||
|
||
VulkanInstance(VulkanInstance&& other) noexcept; | ||
|
||
auto operator=(VulkanInstance&& other) noexcept -> VulkanInstance&; | ||
|
||
~VulkanInstance() noexcept; | ||
|
||
/** | ||
* Returns the associated \c VkInstance. | ||
* | ||
* \return | ||
* A \c VkInstance handle. | ||
*/ | ||
[[nodiscard]] | ||
auto get() -> VkInstance; | ||
|
||
private: | ||
VkInstance mInstance {VK_NULL_HANDLE}; | ||
|
||
explicit VulkanInstance(VkInstance instance) noexcept; | ||
|
||
void _dispose() noexcept; | ||
}; | ||
|
||
/// \} | ||
|
||
} // namespace tactile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
// Copyright (C) 2023 Albin Johansson (GNU General Public License v3.0) | ||
|
||
#include "tactile/vulkan/vulkan_instance.hpp" | ||
|
||
#include <utility> // exchange | ||
|
||
#include <SDL2/SDL_vulkan.h> | ||
|
||
#include "tactile/base/container/vector.hpp" | ||
#include "tactile/base/int.hpp" | ||
#include "tactile/vulkan/vulkan_error.hpp" | ||
|
||
namespace tactile { | ||
namespace { | ||
|
||
inline constexpr uint32 kValidationLayerCount = 1; | ||
inline constexpr const char* kValidationLayerNames[] { | ||
"VK_LAYER_KHRONOS_validation", | ||
}; | ||
|
||
[[nodiscard]] | ||
auto _get_instance_extensions(SDL_Window* window) -> Vector<const char*> | ||
{ | ||
Vector<const char*> instance_extensions {}; | ||
|
||
uint extension_count = 0; | ||
if (!SDL_Vulkan_GetInstanceExtensions(window, &extension_count, nullptr)) { | ||
return instance_extensions; | ||
} | ||
|
||
instance_extensions.reserve(extension_count + 1); | ||
instance_extensions.resize(extension_count); | ||
|
||
SDL_Vulkan_GetInstanceExtensions(window, | ||
&extension_count, | ||
instance_extensions.data()); | ||
|
||
#ifdef TACTILE_USE_VULKAN_SUBSET | ||
instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); | ||
#endif | ||
|
||
return instance_extensions; | ||
} | ||
|
||
} // namespace | ||
|
||
auto VulkanInstance::make(SDL_Window* window) -> Result<VulkanInstance> | ||
{ | ||
uint32 instance_flags = 0; | ||
|
||
#ifdef TACTILE_USE_VULKAN_SUBSET | ||
// Allow partial implementations of the Vulkan spec, such as MoltenVK. | ||
instance_flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; | ||
#endif // TACTILE_USE_VULKAN_SUBSET | ||
|
||
const char* const* enabled_layer_names = nullptr; | ||
uint32 enabled_layer_count = 0; | ||
if constexpr (kIsDebugBuild) { | ||
enabled_layer_names = kValidationLayerNames; | ||
enabled_layer_count = kValidationLayerCount; | ||
} | ||
|
||
const auto instance_extensions = _get_instance_extensions(window); | ||
|
||
const VkApplicationInfo app_info { | ||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, | ||
.pNext = nullptr, | ||
.pApplicationName = "Tactile", | ||
.applicationVersion = VK_MAKE_VERSION(TACTILE_MAJOR_VERSION, | ||
TACTILE_MINOR_VERSION, | ||
TACTILE_PATCH_VERSION), | ||
.pEngineName = "tactile-vulkan", | ||
.engineVersion = VK_MAKE_VERSION(TACTILE_MAJOR_VERSION, | ||
TACTILE_MINOR_VERSION, | ||
TACTILE_PATCH_VERSION), | ||
.apiVersion = VK_API_VERSION_1_2, | ||
}; | ||
|
||
const VkInstanceCreateInfo create_info { | ||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | ||
.pNext = nullptr, | ||
.flags = instance_flags, | ||
.pApplicationInfo = &app_info, | ||
.enabledLayerCount = enabled_layer_count, | ||
.ppEnabledLayerNames = enabled_layer_names, | ||
.enabledExtensionCount = static_cast<uint32>(instance_extensions.size()), | ||
.ppEnabledExtensionNames = instance_extensions.data(), | ||
}; | ||
|
||
VkInstance instance {}; | ||
const auto create_result = vkCreateInstance(&create_info, nullptr, &instance); | ||
|
||
if (create_result != VK_SUCCESS) { | ||
return unexpected(make_error(map_vulkan_result(create_result))); | ||
} | ||
|
||
return VulkanInstance {instance}; | ||
} | ||
|
||
VulkanInstance::VulkanInstance(VkInstance instance) noexcept | ||
: mInstance {instance} | ||
{} | ||
|
||
VulkanInstance::VulkanInstance(VulkanInstance&& other) noexcept | ||
: mInstance {std::exchange(other.mInstance, VK_NULL_HANDLE)} | ||
{} | ||
|
||
auto VulkanInstance::operator=(VulkanInstance&& other) noexcept | ||
-> VulkanInstance& | ||
{ | ||
if (this != &other) { | ||
_dispose(); | ||
mInstance = std::exchange(other.mInstance, VK_NULL_HANDLE); | ||
} | ||
|
||
return *this; | ||
} | ||
|
||
VulkanInstance::~VulkanInstance() noexcept | ||
{ | ||
_dispose(); | ||
} | ||
|
||
void VulkanInstance::_dispose() noexcept | ||
{ | ||
if (mInstance != VK_NULL_HANDLE) { | ||
vkDestroyInstance(mInstance, nullptr); | ||
mInstance = VK_NULL_HANDLE; | ||
} | ||
} | ||
|
||
auto VulkanInstance::get() -> VkInstance | ||
{ | ||
return mInstance; | ||
} | ||
|
||
} // namespace tactile |