iwa/include/iwa/util/vkutil.hpp
2024-04-06 14:11:26 +02:00

211 lines
6.3 KiB
C++

#pragma once
#if !defined(IWA_UTIL_VKUTIL_HPP_INCLUDED)
#define IWA_UTIL_VKUTIL_HPP_INCLUDED
#include <cstdint>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <magic_enum.hpp>
#include <mijin/util/align.hpp>
#include <mijin/util/traits.hpp>
#include "iwa/vkwrapper.hpp"
namespace iwa
{
inline constexpr std::array DEPTH_FORMATS = {
vk::Format::eD24UnormS8Uint,
vk::Format::eD32Sfloat,
vk::Format::eD32SfloatS8Uint,
vk::Format::eD16Unorm,
vk::Format::eD16UnormS8Uint,
vk::Format::eX8D24UnormPack32
};
inline constexpr std::array STENCIL_FORMATS = {
vk::Format::eS8Uint,
vk::Format::eD24UnormS8Uint,
vk::Format::eD32SfloatS8Uint,
vk::Format::eD16UnormS8Uint
};
namespace impl
{
template<typename T>
constexpr vk::Format getVkFormat() noexcept
{
if constexpr (std::is_same_v<T, std::uint8_t>) {
return vk::Format::eR8Uint;
}
else if constexpr (std::is_same_v<T, std::int8_t>) {
return vk::Format::eR8Sint;
}
else if constexpr (std::is_same_v<T, std::uint16_t>) {
return vk::Format::eR16Uint;
}
else if constexpr (std::is_same_v<T, std::int16_t>) {
return vk::Format::eR16Sint;
}
else if constexpr (std::is_same_v<T, std::uint32_t>) {
return vk::Format::eR32Uint;
}
else if constexpr (std::is_same_v<T, std::int32_t>) {
return vk::Format::eR32Sint;
}
else if constexpr (std::is_same_v<T, std::uint64_t>) {
return vk::Format::eR64Uint;
}
else if constexpr (std::is_same_v<T, std::int64_t>) {
return vk::Format::eR64Sint;
}
else if constexpr (std::is_same_v<T, float>) {
return vk::Format::eR32Sfloat;
}
else if constexpr (std::is_same_v<T, double>) {
return vk::Format::eR64Sfloat;
}
else if constexpr (std::is_same_v<T, glm::vec2>) {
return vk::Format::eR32G32Sfloat;
}
else if constexpr (std::is_same_v<T, glm::vec3>) {
return vk::Format::eR32G32B32Sfloat;
}
else if constexpr (std::is_same_v<T, glm::vec4>) {
return vk::Format::eR32G32B32A32Sfloat;
}
else if constexpr (std::is_same_v<T, glm::ivec2>) {
return vk::Format::eR32G32Sint;
}
else if constexpr (std::is_same_v<T, glm::ivec3>) {
return vk::Format::eR32G32B32Sint;
}
else if constexpr (std::is_same_v<T, glm::ivec4>) {
return vk::Format::eR32G32B32A32Sint;
}
else {
static_assert(mijin::always_false_v<T>, "No Vulkan format for that type.");
}
}
template<typename T>
constexpr vk::IndexType getVkIndexType() noexcept
{
if constexpr (std::is_same_v<T, std::uint8_t>) {
return vk::IndexType::eUint8EXT;
}
else if constexpr (std::is_same_v<T, std::uint16_t>) {
return vk::IndexType::eUint16;
}
else if constexpr (std::is_same_v<T, std::uint32_t>) {
return vk::IndexType::eUint32;
}
else {
static_assert(mijin::always_false_v<T>, "No Vulkan index type for that type.");
}
}
} // namespace impl
template<typename T>
static constexpr vk::Format vk_format_v = impl::getVkFormat<T>();
template<typename T>
static constexpr vk::IndexType vk_index_type_v = impl::getVkIndexType<T>();
template<typename T, typename U>
static constexpr vk::Format vkMemberFormat(U T::*) noexcept { return vk_format_v<U>; }
[[nodiscard]] unsigned vkFormatSize(vk::Format format) noexcept;
[[nodiscard]] unsigned vkIndexTypeSize(vk::IndexType indexType) noexcept;
[[nodiscard]] bool isDepthFormat(vk::Format format) noexcept;
[[nodiscard]] bool isStencilFormat(vk::Format format) noexcept; // NOLINT(readability-redundant-declaration) forward declared in image.hpp, but it wouldn't make sense to remove it from here
template<typename TEnum>
std::optional<TEnum> vkEnumFromStringOpt(std::string_view string) noexcept
{
std::string enumName;
enumName.reserve(string.size() + 1);
bool first = true;
for (const char chr : string)
{
if (first)
{
enumName.push_back(std::toupper(chr));
first = false;
}
else {
enumName.push_back(chr);
}
}
return vk::from_string<TEnum>(enumName);
}
template<typename TEnum>
TEnum vkEnumFromString(std::string_view string, const char* error = "Invalid enum value.")
{
const std::optional<TEnum> value = vkEnumFromStringOpt<TEnum>(string);
if (!value.has_value()) {
throw std::runtime_error(error);
}
return *value;
}
template<typename T>
[[nodiscard]] const T* findInNextChain(const void* pNext, vk::StructureType sType = T().sType) noexcept
{
while (pNext)
{
const vk::BaseInStructure* inStruct = static_cast<const vk::BaseInStructure*>(pNext);
if (inStruct->sType == sType)
{
return static_cast<const T*>(pNext);
}
pNext = inStruct->pNext;
}
return nullptr;
}
// TODO
// std::size_t calcVkStructHash(const void* structure, std::size_t appendTo = 0);
[[nodiscard]] vk::SampleCountFlagBits samplesToVk(unsigned samples) noexcept;
[[nodiscard]] vk::Format detectDepthBufferFormat(class Device& device, unsigned samples = 1) noexcept;
[[nodiscard]] std::vector<unsigned> detectSupportedSampleCounts(class Device& device) noexcept;
template<typename T>
vk::DeviceSize calcVkUniformStride(class Device& device)
{
vk::DeviceSize stride = mijin::alignUp(sizeof(T), alignof(T));
return mijin::alignUp(stride, mijin::delayEvaluation<T>(device).getDeviceInfo().properties.limits.minUniformBufferOffsetAlignment);
}
template<typename T>
vk::DeviceSize calcVkStorageBufferStride(class Device& device)
{
vk::DeviceSize stride = mijin::alignUp(sizeof(T), alignof(T));
return mijin::alignUp(stride, mijin::delayEvaluation<T>(device).getDeviceInfo().properties.limits.minStorageBufferOffsetAlignment);
}
[[nodiscard]] inline bool vkIsSrgbFormat(vk::Format format) noexcept
{
switch (format)
{
case vk::Format::eR8Srgb:
case vk::Format::eR8G8Srgb:
case vk::Format::eR8G8B8Srgb:
case vk::Format::eR8G8B8A8Srgb:
case vk::Format::eB8G8R8Srgb:
case vk::Format::eB8G8R8A8Srgb:
case vk::Format::eA8B8G8R8SrgbPack32:
// TODO: all the weird compressed formats, I don't need them yet
return true;
default:
return false;
}
}
} // namespace iwa
#endif // !defined(IWA_UTIL_VKUTIL_HPP_INCLUDED)