211 lines
6.3 KiB
C++
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)
|